1/* 2 * vreset.c 3 * 4 * Initialize the VGA control registers to 80x25 text mode. 5 * 6 * Adapted from a program by: 7 * Steve Sellgren 8 * San Francisco Indigo Company 9 * sfindigo!sellgren@uunet.uu.net 10 * 11 * Original concept by: 12 * Gary Thomas <gdt@linuxppc.org> 13 * Adapted for Moto boxes by: 14 * Pat Kane & Mark Scott, 1996 15 * Adapted for IBM portables by: 16 * Takeshi Ishimoto 17 * Multi-console support: 18 * Terje Malmedal <terje.malmedal@usit.uio.no> 19 */ 20 21#include "iso_font.h" 22#include "nonstdio.h" 23 24extern char *vidmem; 25extern int lines, cols; 26struct VaRegs; 27 28/* 29 * VGA Register 30 */ 31struct VgaRegs 32{ 33 unsigned short io_port; 34 unsigned char io_index; 35 unsigned char io_value; 36}; 37 38void unlockVideo(int slot); 39void setTextRegs(struct VgaRegs *svp); 40void setTextCLUT(int shift); 41void clearVideoMemory(void); 42void loadFont(unsigned char *ISA_mem); 43 44static void mdelay(int ms) 45{ 46 for (; ms > 0; --ms) 47 udelay(1000); 48} 49 50/* 51 * Default console text mode registers used to reset 52 * graphics adapter. 53 */ 54#define NREGS 54 55#define ENDMK 0xFFFF /* End marker */ 56 57#define S3Vendor 0x5333 58#define CirrusVendor 0x1013 59#define DiamondVendor 0x100E 60#define MatroxVendor 0x102B 61#define ParadiseVendor 0x101C 62 63struct VgaRegs GenVgaTextRegs[NREGS+1] = { 64 /* port index value */ 65 /* SR Regs */ 66 { 0x3c4, 0x1, 0x0 }, 67 { 0x3c4, 0x2, 0x3 }, 68 { 0x3c4, 0x3, 0x0 }, 69 { 0x3c4, 0x4, 0x2 }, 70 /* CR Regs */ 71 { 0x3d4, 0x0, 0x5f }, 72 { 0x3d4, 0x1, 0x4f }, 73 { 0x3d4, 0x2, 0x50 }, 74 { 0x3d4, 0x3, 0x82 }, 75 { 0x3d4, 0x4, 0x55 }, 76 { 0x3d4, 0x5, 0x81 }, 77 { 0x3d4, 0x6, 0xbf }, 78 { 0x3d4, 0x7, 0x1f }, 79 { 0x3d4, 0x8, 0x00 }, 80 { 0x3d4, 0x9, 0x4f }, 81 { 0x3d4, 0xa, 0x0d }, 82 { 0x3d4, 0xb, 0x0e }, 83 { 0x3d4, 0xc, 0x00 }, 84 { 0x3d4, 0xd, 0x00 }, 85 { 0x3d4, 0xe, 0x00 }, 86 { 0x3d4, 0xf, 0x00 }, 87 { 0x3d4, 0x10, 0x9c }, 88 { 0x3d4, 0x11, 0x8e }, 89 { 0x3d4, 0x12, 0x8f }, 90 { 0x3d4, 0x13, 0x28 }, 91 { 0x3d4, 0x14, 0x1f }, 92 { 0x3d4, 0x15, 0x96 }, 93 { 0x3d4, 0x16, 0xb9 }, 94 { 0x3d4, 0x17, 0xa3 }, 95 /* GR Regs */ 96 { 0x3ce, 0x0, 0x0 }, 97 { 0x3ce, 0x1, 0x0 }, 98 { 0x3ce, 0x2, 0x0 }, 99 { 0x3ce, 0x3, 0x0 }, 100 { 0x3ce, 0x4, 0x0 }, 101 { 0x3ce, 0x5, 0x10 }, 102 { 0x3ce, 0x6, 0xe }, 103 { 0x3ce, 0x7, 0x0 }, 104 { 0x3ce, 0x8, 0xff }, 105 { ENDMK } 106}; 107 108struct RGBColors 109{ 110 unsigned char r, g, b; 111}; 112 113/* 114 * Default console text mode color table. 115 * These values were obtained by booting Linux with 116 * text mode firmware & then dumping the registers. 117 */ 118struct RGBColors TextCLUT[256] = 119{ 120 /* red green blue */ 121 { 0x0, 0x0, 0x0 }, 122 { 0x0, 0x0, 0x2a }, 123 { 0x0, 0x2a, 0x0 }, 124 { 0x0, 0x2a, 0x2a }, 125 { 0x2a, 0x0, 0x0 }, 126 { 0x2a, 0x0, 0x2a }, 127 { 0x2a, 0x2a, 0x0 }, 128 { 0x2a, 0x2a, 0x2a }, 129 { 0x0, 0x0, 0x15 }, 130 { 0x0, 0x0, 0x3f }, 131 { 0x0, 0x2a, 0x15 }, 132 { 0x0, 0x2a, 0x3f }, 133 { 0x2a, 0x0, 0x15 }, 134 { 0x2a, 0x0, 0x3f }, 135 { 0x2a, 0x2a, 0x15 }, 136 { 0x2a, 0x2a, 0x3f }, 137 { 0x0, 0x15, 0x0 }, 138 { 0x0, 0x15, 0x2a }, 139 { 0x0, 0x3f, 0x0 }, 140 { 0x0, 0x3f, 0x2a }, 141 { 0x2a, 0x15, 0x0 }, 142 { 0x2a, 0x15, 0x2a }, 143 { 0x2a, 0x3f, 0x0 }, 144 { 0x2a, 0x3f, 0x2a }, 145 { 0x0, 0x15, 0x15 }, 146 { 0x0, 0x15, 0x3f }, 147 { 0x0, 0x3f, 0x15 }, 148 { 0x0, 0x3f, 0x3f }, 149 { 0x2a, 0x15, 0x15 }, 150 { 0x2a, 0x15, 0x3f }, 151 { 0x2a, 0x3f, 0x15 }, 152 { 0x2a, 0x3f, 0x3f }, 153 { 0x15, 0x0, 0x0 }, 154 { 0x15, 0x0, 0x2a }, 155 { 0x15, 0x2a, 0x0 }, 156 { 0x15, 0x2a, 0x2a }, 157 { 0x3f, 0x0, 0x0 }, 158 { 0x3f, 0x0, 0x2a }, 159 { 0x3f, 0x2a, 0x0 }, 160 { 0x3f, 0x2a, 0x2a }, 161 { 0x15, 0x0, 0x15 }, 162 { 0x15, 0x0, 0x3f }, 163 { 0x15, 0x2a, 0x15 }, 164 { 0x15, 0x2a, 0x3f }, 165 { 0x3f, 0x0, 0x15 }, 166 { 0x3f, 0x0, 0x3f }, 167 { 0x3f, 0x2a, 0x15 }, 168 { 0x3f, 0x2a, 0x3f }, 169 { 0x15, 0x15, 0x0 }, 170 { 0x15, 0x15, 0x2a }, 171 { 0x15, 0x3f, 0x0 }, 172 { 0x15, 0x3f, 0x2a }, 173 { 0x3f, 0x15, 0x0 }, 174 { 0x3f, 0x15, 0x2a }, 175 { 0x3f, 0x3f, 0x0 }, 176 { 0x3f, 0x3f, 0x2a }, 177 { 0x15, 0x15, 0x15 }, 178 { 0x15, 0x15, 0x3f }, 179 { 0x15, 0x3f, 0x15 }, 180 { 0x15, 0x3f, 0x3f }, 181 { 0x3f, 0x15, 0x15 }, 182 { 0x3f, 0x15, 0x3f }, 183 { 0x3f, 0x3f, 0x15 }, 184 { 0x3f, 0x3f, 0x3f }, 185 { 0x39, 0xc, 0x5 }, 186 { 0x15, 0x2c, 0xf }, 187 { 0x26, 0x10, 0x3d }, 188 { 0x29, 0x29, 0x38 }, 189 { 0x4, 0x1a, 0xe }, 190 { 0x2, 0x1e, 0x3a }, 191 { 0x3c, 0x25, 0x33 }, 192 { 0x3c, 0xc, 0x2c }, 193 { 0x3f, 0x3, 0x2b }, 194 { 0x1c, 0x9, 0x13 }, 195 { 0x25, 0x2a, 0x35 }, 196 { 0x1e, 0xa, 0x38 }, 197 { 0x24, 0x8, 0x3 }, 198 { 0x3, 0xe, 0x36 }, 199 { 0xc, 0x6, 0x2a }, 200 { 0x26, 0x3, 0x32 }, 201 { 0x5, 0x2f, 0x33 }, 202 { 0x3c, 0x35, 0x2f }, 203 { 0x2d, 0x26, 0x3e }, 204 { 0xd, 0xa, 0x10 }, 205 { 0x25, 0x3c, 0x11 }, 206 { 0xd, 0x4, 0x2e }, 207 { 0x5, 0x19, 0x3e }, 208 { 0xc, 0x13, 0x34 }, 209 { 0x2b, 0x6, 0x24 }, 210 { 0x4, 0x3, 0xd }, 211 { 0x2f, 0x3c, 0xc }, 212 { 0x2a, 0x37, 0x1f }, 213 { 0xf, 0x12, 0x38 }, 214 { 0x38, 0xe, 0x2a }, 215 { 0x12, 0x2f, 0x19 }, 216 { 0x29, 0x2e, 0x31 }, 217 { 0x25, 0x13, 0x3e }, 218 { 0x33, 0x3e, 0x33 }, 219 { 0x1d, 0x2c, 0x25 }, 220 { 0x15, 0x15, 0x5 }, 221 { 0x32, 0x25, 0x39 }, 222 { 0x1a, 0x7, 0x1f }, 223 { 0x13, 0xe, 0x1d }, 224 { 0x36, 0x17, 0x34 }, 225 { 0xf, 0x15, 0x23 }, 226 { 0x2, 0x35, 0xd }, 227 { 0x15, 0x3f, 0xc }, 228 { 0x14, 0x2f, 0xf }, 229 { 0x19, 0x21, 0x3e }, 230 { 0x27, 0x11, 0x2f }, 231 { 0x38, 0x3f, 0x3c }, 232 { 0x36, 0x2d, 0x15 }, 233 { 0x16, 0x17, 0x2 }, 234 { 0x1, 0xa, 0x3d }, 235 { 0x1b, 0x11, 0x3f }, 236 { 0x21, 0x3c, 0xd }, 237 { 0x1a, 0x39, 0x3d }, 238 { 0x8, 0xe, 0xe }, 239 { 0x22, 0x21, 0x23 }, 240 { 0x1e, 0x30, 0x5 }, 241 { 0x1f, 0x22, 0x3d }, 242 { 0x1e, 0x2f, 0xa }, 243 { 0x0, 0x1c, 0xe }, 244 { 0x0, 0x1c, 0x15 }, 245 { 0x0, 0x1c, 0x1c }, 246 { 0x0, 0x15, 0x1c }, 247 { 0x0, 0xe, 0x1c }, 248 { 0x0, 0x7, 0x1c }, 249 { 0xe, 0xe, 0x1c }, 250 { 0x11, 0xe, 0x1c }, 251 { 0x15, 0xe, 0x1c }, 252 { 0x18, 0xe, 0x1c }, 253 { 0x1c, 0xe, 0x1c }, 254 { 0x1c, 0xe, 0x18 }, 255 { 0x1c, 0xe, 0x15 }, 256 { 0x1c, 0xe, 0x11 }, 257 { 0x1c, 0xe, 0xe }, 258 { 0x1c, 0x11, 0xe }, 259 { 0x1c, 0x15, 0xe }, 260 { 0x1c, 0x18, 0xe }, 261 { 0x1c, 0x1c, 0xe }, 262 { 0x18, 0x1c, 0xe }, 263 { 0x15, 0x1c, 0xe }, 264 { 0x11, 0x1c, 0xe }, 265 { 0xe, 0x1c, 0xe }, 266 { 0xe, 0x1c, 0x11 }, 267 { 0xe, 0x1c, 0x15 }, 268 { 0xe, 0x1c, 0x18 }, 269 { 0xe, 0x1c, 0x1c }, 270 { 0xe, 0x18, 0x1c }, 271 { 0xe, 0x15, 0x1c }, 272 { 0xe, 0x11, 0x1c }, 273 { 0x14, 0x14, 0x1c }, 274 { 0x16, 0x14, 0x1c }, 275 { 0x18, 0x14, 0x1c }, 276 { 0x1a, 0x14, 0x1c }, 277 { 0x1c, 0x14, 0x1c }, 278 { 0x1c, 0x14, 0x1a }, 279 { 0x1c, 0x14, 0x18 }, 280 { 0x1c, 0x14, 0x16 }, 281 { 0x1c, 0x14, 0x14 }, 282 { 0x1c, 0x16, 0x14 }, 283 { 0x1c, 0x18, 0x14 }, 284 { 0x1c, 0x1a, 0x14 }, 285 { 0x1c, 0x1c, 0x14 }, 286 { 0x1a, 0x1c, 0x14 }, 287 { 0x18, 0x1c, 0x14 }, 288 { 0x16, 0x1c, 0x14 }, 289 { 0x14, 0x1c, 0x14 }, 290 { 0x14, 0x1c, 0x16 }, 291 { 0x14, 0x1c, 0x18 }, 292 { 0x14, 0x1c, 0x1a }, 293 { 0x14, 0x1c, 0x1c }, 294 { 0x14, 0x1a, 0x1c }, 295 { 0x14, 0x18, 0x1c }, 296 { 0x14, 0x16, 0x1c }, 297 { 0x0, 0x0, 0x10 }, 298 { 0x4, 0x0, 0x10 }, 299 { 0x8, 0x0, 0x10 }, 300 { 0xc, 0x0, 0x10 }, 301 { 0x10, 0x0, 0x10 }, 302 { 0x10, 0x0, 0xc }, 303 { 0x10, 0x0, 0x8 }, 304 { 0x10, 0x0, 0x4 }, 305 { 0x10, 0x0, 0x0 }, 306 { 0x10, 0x4, 0x0 }, 307 { 0x10, 0x8, 0x0 }, 308 { 0x10, 0xc, 0x0 }, 309 { 0x10, 0x10, 0x0 }, 310 { 0xc, 0x10, 0x0 }, 311 { 0x8, 0x10, 0x0 }, 312 { 0x4, 0x10, 0x0 }, 313 { 0x0, 0x10, 0x0 }, 314 { 0x0, 0x10, 0x4 }, 315 { 0x0, 0x10, 0x8 }, 316 { 0x0, 0x10, 0xc }, 317 { 0x0, 0x10, 0x10 }, 318 { 0x0, 0xc, 0x10 }, 319 { 0x0, 0x8, 0x10 }, 320 { 0x0, 0x4, 0x10 }, 321 { 0x8, 0x8, 0x10 }, 322 { 0xa, 0x8, 0x10 }, 323 { 0xc, 0x8, 0x10 }, 324 { 0xe, 0x8, 0x10 }, 325 { 0x10, 0x8, 0x10 }, 326 { 0x10, 0x8, 0xe }, 327 { 0x10, 0x8, 0xc }, 328 { 0x10, 0x8, 0xa }, 329 { 0x10, 0x8, 0x8 }, 330 { 0x10, 0xa, 0x8 }, 331 { 0x10, 0xc, 0x8 }, 332 { 0x10, 0xe, 0x8 }, 333 { 0x10, 0x10, 0x8 }, 334 { 0xe, 0x10, 0x8 }, 335 { 0xc, 0x10, 0x8 }, 336 { 0xa, 0x10, 0x8 }, 337 { 0x8, 0x10, 0x8 }, 338 { 0x8, 0x10, 0xa }, 339 { 0x8, 0x10, 0xc }, 340 { 0x8, 0x10, 0xe }, 341 { 0x8, 0x10, 0x10 }, 342 { 0x8, 0xe, 0x10 }, 343 { 0x8, 0xc, 0x10 }, 344 { 0x8, 0xa, 0x10 }, 345 { 0xb, 0xb, 0x10 }, 346 { 0xc, 0xb, 0x10 }, 347 { 0xd, 0xb, 0x10 }, 348 { 0xf, 0xb, 0x10 }, 349 { 0x10, 0xb, 0x10 }, 350 { 0x10, 0xb, 0xf }, 351 { 0x10, 0xb, 0xd }, 352 { 0x10, 0xb, 0xc }, 353 { 0x10, 0xb, 0xb }, 354 { 0x10, 0xc, 0xb }, 355 { 0x10, 0xd, 0xb }, 356 { 0x10, 0xf, 0xb }, 357 { 0x10, 0x10, 0xb }, 358 { 0xf, 0x10, 0xb }, 359 { 0xd, 0x10, 0xb }, 360 { 0xc, 0x10, 0xb }, 361 { 0xb, 0x10, 0xb }, 362 { 0xb, 0x10, 0xc }, 363 { 0xb, 0x10, 0xd }, 364 { 0xb, 0x10, 0xf }, 365 { 0xb, 0x10, 0x10 }, 366 { 0xb, 0xf, 0x10 }, 367 { 0xb, 0xd, 0x10 }, 368 { 0xb, 0xc, 0x10 }, 369 { 0x0, 0x0, 0x0 }, 370 { 0x0, 0x0, 0x0 }, 371 { 0x0, 0x0, 0x0 }, 372 { 0x0, 0x0, 0x0 }, 373 { 0x0, 0x0, 0x0 }, 374 { 0x0, 0x0, 0x0 }, 375 { 0x0, 0x0, 0x0 } 376}; 377 378unsigned char AC[21] = { 379 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 380 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 381 0x0C, 0x00, 0x0F, 0x08, 0x00}; 382 383static int scanPCI(int start_slt); 384static int PCIVendor(int); 385#ifdef DEBUG 386static void printslots(void); 387#endif 388extern void puthex(unsigned long); 389extern void puts(const char *); 390static void unlockS3(void); 391 392static inline void 393outw(int port, unsigned short val) 394{ 395 outb(port, val >> 8); 396 outb(port+1, val); 397} 398 399int 400vga_init(unsigned char *ISA_mem) 401{ 402 int slot; 403 struct VgaRegs *VgaTextRegs; 404 405 /* See if VGA already in TEXT mode - exit if so! */ 406 outb(0x3CE, 0x06); 407 if ((inb(0x3CF) & 0x01) == 0){ 408 puts("VGA already in text mode\n"); 409 return 0; 410 } 411 412 /* If no VGA responding in text mode, then we have some work to do... 413 */ 414 slot = -1; 415 while((slot = scanPCI(slot)) > -1) { /* find video card in use */ 416 unlockVideo(slot); /* enable I/O to card */ 417 VgaTextRegs = GenVgaTextRegs; 418 419 switch (PCIVendor(slot)) { 420 default: 421 break; 422 case(S3Vendor): 423 unlockS3(); 424 break; 425 426 case(CirrusVendor): 427 outw(0x3C4, 0x0612); /* unlock ext regs */ 428 outw(0x3C4, 0x0700); /* reset ext sequence mode */ 429 break; 430 431 case(ParadiseVendor): /* IBM Portable 850 */ 432 outw(0x3ce, 0x0f05); /* unlock pardise registers */ 433 outw(0x3c4, 0x0648); 434 outw(0x3d4, 0x2985); 435 outw(0x3d4, 0x34a6); 436 outb(0x3ce, 0x0b); /* disable linear addressing */ 437 outb(0x3cf, inb(0x3cf) & ~0x30); 438 outw(0x3c4, 0x1400); 439 outb(0x3ce, 0x0e); /* disable 256 color mode */ 440 outb(0x3cf, inb(0x3cf) & ~0x01); 441 outb(0xd00, 0xff); /* enable auto-centering */ 442 if (!(inb(0xd01) & 0x03)) { 443 outb(0x3d4, 0x33); 444 outb(0x3d5, inb(0x3d5) & ~0x90); 445 outb(0x3d4, 0x32); 446 outb(0x3d5, inb(0x3d5) | 0x04); 447 outw(0x3d4, 0x0250); 448 outw(0x3d4, 0x07ba); 449 outw(0x3d4, 0x0900); 450 outw(0x3d4, 0x15e7); 451 outw(0x3d4, 0x2a95); 452 } 453 outw(0x3d4, 0x34a0); 454 break; 455 456 #if 0 /* Untested - probably doesn't work */ 457 case(MatroxVendor): 458 case(DiamondVendor): 459 puts("VGA Chip Vendor ID: "); 460 puthex(PCIVendor(slot)); 461 puts("\n"); 462 mdelay(1000); 463 #endif 464 }; 465 466 outw(0x3C4, 0x0120); /* disable video */ 467 setTextRegs(VgaTextRegs); /* initial register setup */ 468 setTextCLUT(0); /* load color lookup table */ 469 loadFont(ISA_mem); /* load font */ 470 setTextRegs(VgaTextRegs); /* reload registers */ 471 outw(0x3C4, 0x0100); /* re-enable video */ 472 clearVideoMemory(); 473 474 if (PCIVendor(slot) == S3Vendor) { 475 outb(0x3c2, 0x63); /* MISC */ 476 } /* endif */ 477 478 #ifdef DEBUG 479 printslots(); 480 mdelay(5000); 481 #endif 482 483 mdelay(1000); /* give time for the video monitor to come up */ 484 } 485 return (1); /* 'CRT' I/O supported */ 486} 487 488/* 489 * Write to VGA Attribute registers. 490 */ 491void 492writeAttr(unsigned char index, unsigned char data, unsigned char videoOn) 493{ 494 unsigned char v; 495 v = inb(0x3da); /* reset attr. address toggle */ 496 if (videoOn) 497 outb(0x3c0, (index & 0x1F) | 0x20); 498 else 499 outb(0x3c0, (index & 0x1F)); 500 outb(0x3c0, data); 501} 502 503void 504setTextRegs(struct VgaRegs *svp) 505{ 506 int i; 507 508 /* 509 * saved settings 510 */ 511 while( svp->io_port != ENDMK ) { 512 outb(svp->io_port, svp->io_index); 513 outb(svp->io_port+1, svp->io_value); 514 svp++; 515 } 516 517 outb(0x3c2, 0x67); /* MISC */ 518 outb(0x3c6, 0xff); /* MASK */ 519 520 for ( i = 0; i < 0x10; i++) 521 writeAttr(i, AC[i], 0); /* palette */ 522 writeAttr(0x10, 0x0c, 0); /* text mode */ 523 writeAttr(0x11, 0x00, 0); /* overscan color (border) */ 524 writeAttr(0x12, 0x0f, 0); /* plane enable */ 525 writeAttr(0x13, 0x08, 0); /* pixel panning */ 526 writeAttr(0x14, 0x00, 1); /* color select; video on */ 527} 528 529void 530setTextCLUT(int shift) 531{ 532 int i; 533 534 outb(0x3C6, 0xFF); 535 i = inb(0x3C7); 536 outb(0x3C8, 0); 537 i = inb(0x3C7); 538 539 for ( i = 0; i < 256; i++) { 540 outb(0x3C9, TextCLUT[i].r << shift); 541 outb(0x3C9, TextCLUT[i].g << shift); 542 outb(0x3C9, TextCLUT[i].b << shift); 543 } 544} 545 546void 547loadFont(unsigned char *ISA_mem) 548{ 549 int i, j; 550 unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; 551 552 outb(0x3C2, 0x67); 553 /* 554 * Load font 555 */ 556 i = inb(0x3DA); /* Reset Attr toggle */ 557 558 outb(0x3C0,0x30); 559 outb(0x3C0, 0x01); /* graphics mode */ 560 561 outw(0x3C4, 0x0001); /* reset sequencer */ 562 outw(0x3C4, 0x0204); /* write to plane 2 */ 563 outw(0x3C4, 0x0406); /* enable plane graphics */ 564 outw(0x3C4, 0x0003); /* reset sequencer */ 565 outw(0x3CE, 0x0402); /* read plane 2 */ 566 outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ 567 outw(0x3CE, 0x0605); /* set graphics mode */ 568 569 for (i = 0; i < sizeof(font); i += 16) { 570 for (j = 0; j < 16; j++) { 571 __asm__ volatile("eieio"); 572 font_page[(2*i)+j] = font[i+j]; 573 } 574 } 575} 576 577static void 578unlockS3(void) 579{ 580 int s3_device_id; 581 outw(0x3d4, 0x3848); 582 outw(0x3d4, 0x39a5); 583 outb(0x3d4, 0x2d); 584 s3_device_id = inb(0x3d5) << 8; 585 outb(0x3d4, 0x2e); 586 s3_device_id |= inb(0x3d5); 587 588 if (s3_device_id != 0x8812) { 589 /* From the S3 manual */ 590 outb(0x46E8, 0x10); /* Put into setup mode */ 591 outb(0x3C3, 0x10); 592 outb(0x102, 0x01); /* Enable registers */ 593 outb(0x46E8, 0x08); /* Enable video */ 594 outb(0x3C3, 0x08); 595 outb(0x4AE8, 0x00); 596 597 598 outb(0x3D4, 0x38); /* Unlock all registers */ 599 outb(0x3D5, 0x48); 600 outb(0x3D4, 0x39); 601 outb(0x3D5, 0xA5); 602 outb(0x3D4, 0x40); 603 outb(0x3D5, inb(0x3D5)|0x01); 604 outb(0x3D4, 0x33); 605 outb(0x3D5, inb(0x3D5)&~0x52); 606 outb(0x3D4, 0x35); 607 outb(0x3D5, inb(0x3D5)&~0x30); 608 outb(0x3D4, 0x3A); 609 outb(0x3D5, 0x00); 610 outb(0x3D4, 0x53); 611 outb(0x3D5, 0x00); 612 outb(0x3D4, 0x31); 613 outb(0x3D5, inb(0x3D5)&~0x4B); 614 outb(0x3D4, 0x58); 615 616 outb(0x3D5, 0); 617 618 outb(0x3D4, 0x54); 619 outb(0x3D5, 0x38); 620 outb(0x3D4, 0x60); 621 outb(0x3D5, 0x07); 622 outb(0x3D4, 0x61); 623 outb(0x3D5, 0x80); 624 outb(0x3D4, 0x62); 625 outb(0x3D5, 0xA1); 626 outb(0x3D4, 0x69); /* High order bits for cursor address */ 627 outb(0x3D5, 0); 628 629 outb(0x3D4, 0x32); 630 outb(0x3D5, inb(0x3D5)&~0x10); 631 } else { 632 outw(0x3c4, 0x0806); /* IBM Portable 860 */ 633 outw(0x3c4, 0x1041); 634 outw(0x3c4, 0x1128); 635 outw(0x3d4, 0x4000); 636 outw(0x3d4, 0x3100); 637 outw(0x3d4, 0x3a05); 638 outw(0x3d4, 0x6688); 639 outw(0x3d4, 0x5800); /* disable linear addressing */ 640 outw(0x3d4, 0x4500); /* disable H/W cursor */ 641 outw(0x3c4, 0x5410); /* enable auto-centering */ 642 outw(0x3c4, 0x561f); 643 outw(0x3c4, 0x1b80); /* lock DCLK selection */ 644 outw(0x3d4, 0x3900); /* lock S3 registers */ 645 outw(0x3d4, 0x3800); 646 } /* endif */ 647} 648 649/* 650 * cursor() sets an offset (0-1999) into the 80x25 text area. 651 */ 652void 653cursor(int x, int y) 654{ 655 int pos = (y*cols)+x; 656 outb(0x3D4, 14); 657 outb(0x3D5, pos >> 8); 658 outb(0x3D4, 15); 659 outb(0x3D5, pos); 660} 661 662void 663clearVideoMemory(void) 664{ 665 int i, j; 666 for (i = 0; i < lines; i++) { 667 for (j = 0; j < cols; j++) { 668 vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */ 669 vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */ 670 } 671 } 672} 673 674/* ============ */ 675 676 677#define NSLOTS 8 678#define NPCIREGS 5 679 680 681/* 682 should use devfunc number/indirect method to be totally safe on 683 all machines, this works for now on 3 slot Moto boxes 684*/ 685 686struct PCI_ConfigInfo { 687 unsigned long * config_addr; 688 unsigned long regs[NPCIREGS]; 689} PCI_slots [NSLOTS] = { 690 691 { (unsigned long *)0x80808000, {0xDEADBEEF,} }, /* onboard */ 692 { (unsigned long *)0x80800800, {0xDEADBEEF,} }, /* onboard */ 693 { (unsigned long *)0x80801000, {0xDEADBEEF,} }, /* onboard */ 694 { (unsigned long *)0x80802000, {0xDEADBEEF,} }, /* onboard */ 695 { (unsigned long *)0x80804000, {0xDEADBEEF,} }, /* onboard */ 696 { (unsigned long *)0x80810000, {0xDEADBEEF,} }, /* slot A/1 */ 697 { (unsigned long *)0x80820000, {0xDEADBEEF,} }, /* slot B/2 */ 698 { (unsigned long *)0x80840000, {0xDEADBEEF,} } /* slot C/3 */ 699}; 700 701 702 703/* 704 * The following code modifies the PCI Command register 705 * to enable memory and I/O accesses. 706 */ 707void 708unlockVideo(int slot) 709{ 710 volatile unsigned char * ppci; 711 712 ppci = (unsigned char * )PCI_slots[slot].config_addr; 713 ppci[4] = 0x0003; /* enable memory and I/O accesses */ 714 ppci[0x10] = 0x00000; /* turn off memory mapping */ 715 ppci[0x11] = 0x00000; /* mem_base = 0 */ 716 ppci[0x12] = 0x00000; 717 ppci[0x13] = 0x00000; 718 __asm__ volatile("eieio"); 719 720 outb(0x3d4, 0x11); 721 outb(0x3d5, 0x0e); /* unlock CR0-CR7 */ 722} 723 724long 725SwapBytes(long lv) /* turn little endian into big indian long */ 726{ 727 long t; 728 t = (lv&0x000000FF) << 24; 729 t |= (lv&0x0000FF00) << 8; 730 t |= (lv&0x00FF0000) >> 8; 731 t |= (lv&0xFF000000) >> 24; 732 return(t); 733} 734 735 736#define DEVID 0 737#define CMD 1 738#define CLASS 2 739#define MEMBASE 4 740 741int 742scanPCI(int start_slt) 743{ 744 int slt, r; 745 struct PCI_ConfigInfo *pslot; 746 int theSlot = -1; 747 int highVgaSlot = 0; 748 749 for ( slt = start_slt + 1; slt < NSLOTS; slt++) { 750 pslot = &PCI_slots[slt]; 751 for ( r = 0; r < NPCIREGS; r++) { 752 pslot->regs[r] = SwapBytes ( pslot->config_addr[r] ); 753 } 754 /* card in slot ? */ 755 if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { 756 /* VGA ? */ 757 if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || 758 ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) { 759 highVgaSlot = slt; 760 /* did firmware enable it ? */ 761 if ( (pslot->regs[CMD] & 0x03) ) { 762 theSlot = slt; 763 break; 764 } 765 } 766 } 767 } 768 769 return ( theSlot ); 770} 771 772/* return Vendor ID of card in the slot */ 773static 774int PCIVendor(int slotnum) { 775 struct PCI_ConfigInfo *pslot; 776 777 pslot = &PCI_slots[slotnum]; 778 779return (pslot->regs[DEVID] & 0xFFFF); 780} 781 782#ifdef DEBUG 783static 784void printslots(void) 785{ 786 int i; 787 for(i=0; i < NSLOTS; i++) { 788 puts("PCI Slot number: "); puthex(i); 789 puts(" Vendor ID: "); 790 puthex(PCIVendor(i)); puts("\n"); 791 } 792} 793#endif /* DEBUG */ 794