1 /* $NetBSD: vreset.c,v 1.6 2006/06/27 23:26:13 garbled Exp $ */ 2 /*- 3 * Copyright (c) 2006 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Tim Rightnour 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #ifdef VGA_RESET 39 #include <lib/libsa/stand.h> 40 #include "boot.h" 41 #include "iso_font.h" 42 43 #define VGA_SR_PORT 0x3c4 44 #define VGA_CR_PORT 0x3d4 45 #define VGA_CR_DATA 0x3d5 46 #define VGA_GR_PORT 0x3ce 47 #define VGA_GR_DATA 0x3cf 48 #define SRREGS 4 49 #define CRREGS 24 50 #define GRREGS 9 51 #define LINES 25 52 #define COLS 80 53 #define PCI_VENDOR_S3 0x5333 54 #define PCI_VENDOR_CIRRUS 0x1013 55 #define PCI_VENDOR_DIAMOND 0x100E 56 #define PCI_VENDOR_MATROX 0x102B 57 #define PCI_VENDOR_PARADISE 0x101C 58 59 static void write_attr(u_int8_t, u_int8_t, u_int8_t); 60 static void set_text_regs(void); 61 static void set_text_clut(int); 62 static void load_font(u_int8_t *); 63 static void unlock_S3(void); 64 static void clear_video_memory(void); 65 66 extern char *videomem; 67 68 typedef struct vga_reg { 69 u_int8_t idx; 70 u_int8_t val; 71 } vga_reg_t; 72 73 static vga_reg_t SR_regs[SRREGS] = { 74 /* idx val */ 75 { 0x1, 0x0 }, /* 01: clocking mode */ 76 { 0x2, 0x3 }, /* 02: map mask */ 77 { 0x3, 0x0 }, /* 03: character map select */ 78 { 0x4, 0x2 } /* 04: memory mode */ 79 }; 80 81 static vga_reg_t CR_regs[CRREGS] = { 82 /* idx val */ 83 { 0x0, 0x61 }, /* 00: horizontal total */ 84 { 0x1, 0x4f }, /* 01: horizontal display-enable end */ 85 { 0x2, 0x50 }, /* 02: start horizontal blanking */ 86 { 0x3, 0x82 }, /* 03: display skew control / end horizontal blanking */ { 0x4, 0x55 }, /* 04: start horizontal retrace pulse */ 87 { 0x5, 0x81 }, /* 05: horizontal retrace delay / end horiz. retrace */ 88 { 0x6, 0xf0 }, /* 06: vertical total */ 89 { 0x7, 0x1f }, /* 07: overflow register */ 90 { 0x8, 0x00 }, /* 08: preset row scan */ 91 { 0x9, 0x4f }, /* 09: overflow / maximum scan line */ 92 { 0xa, 0x0d }, /* 0A: cursor off / cursor start */ 93 { 0xb, 0x0e }, /* 0B: cursor skew / cursor end */ 94 { 0xc, 0x00 }, /* 0C: start regenerative buffer address high */ 95 { 0xd, 0x00 }, /* 0D: start regenerative buffer address low */ 96 { 0xe, 0x00 }, /* 0E: cursor location high */ 97 { 0xf, 0x00 }, /* 0F: cursor location low */ 98 { 0x10, 0x9a }, /* 10: vertical retrace start */ 99 { 0x11, 0x8c }, /* 11: vertical interrupt / vertical retrace end */ 100 { 0x12, 0x8f }, /* 12: vertical display enable end */ 101 { 0x13, 0x28 }, /* 13: logical line width */ 102 { 0x14, 0x1f }, /* 14: underline location */ 103 { 0x15, 0x97 }, /* 15: start vertical blanking */ 104 { 0x16, 0x00 }, /* 16: end vertical blanking */ 105 { 0x17, 0xa3 }, /* 17: CRT mode control */ 106 }; 107 108 static vga_reg_t GR_regs[GRREGS] = { 109 /* idx val */ 110 { 0x0, 0x00 }, /* 00: set/reset map */ 111 { 0x1, 0x00 }, /* 01: enable set/reset */ 112 { 0x2, 0x00 }, /* 02: color compare */ 113 { 0x3, 0x00 }, /* 03: data rotate */ 114 { 0x4, 0x00 }, /* 04: read map select */ 115 { 0x5, 0x10 }, /* 05: graphics mode */ 116 { 0x6, 0x0e }, /* 06: miscellaneous */ 117 { 0x7, 0x00 }, /* 07: color don't care */ 118 { 0x8, 0xff }, /* 08: bit mask */ 119 }; 120 121 /* video DAC palette registers */ 122 /* XXX only set up 16 colors used by internal palette in ATC regsters */ 123 static const u_int8_t vga_dacpal[] = { 124 /* R G B */ 125 0x00, 0x00, 0x00, /* BLACK */ 126 0x00, 0x00, 0x2a, /* BLUE */ 127 0x00, 0x2a, 0x00, /* GREEN */ 128 0x00, 0x2a, 0x2a, /* CYAN */ 129 0x2a, 0x00, 0x00, /* RED */ 130 0x2a, 0x00, 0x2a, /* MAGENTA */ 131 0x2a, 0x15, 0x00, /* BROWN */ 132 0x2a, 0x2a, 0x2a, /* LIGHTGREY */ 133 0x15, 0x15, 0x15, /* DARKGREY */ 134 0x15, 0x15, 0x3f, /* LIGHTBLUE */ 135 0x15, 0x3f, 0x15, /* LIGHTGREEN */ 136 0x15, 0x3f, 0x3f, /* LIGHTCYAN */ 137 0x3f, 0x15, 0x15, /* LIGHTRED */ 138 0x3f, 0x15, 0x3f, /* LIGHTMAGENTA */ 139 0x3f, 0x3f, 0x15, /* YELLOW */ 140 0x3f, 0x3f, 0x3f /* WHITE */ 141 }; 142 143 static const u_int8_t vga_atc[] = { 144 0x00, /* 00: internal palette 0 */ 145 0x01, /* 01: internal palette 1 */ 146 0x02, /* 02: internal palette 2 */ 147 0x03, /* 03: internal palette 3 */ 148 0x04, /* 04: internal palette 4 */ 149 0x05, /* 05: internal palette 5 */ 150 0x14, /* 06: internal palette 6 */ 151 0x07, /* 07: internal palette 7 */ 152 0x38, /* 08: internal palette 8 */ 153 0x39, /* 09: internal palette 9 */ 154 0x3a, /* 0A: internal palette 10 */ 155 0x3b, /* 0B: internal palette 11 */ 156 0x3c, /* 0C: internal palette 12 */ 157 0x3d, /* 0D: internal palette 13 */ 158 0x3e, /* 0E: internal palette 14 */ 159 0x3f, /* 0F: internal palette 15 */ 160 0x0c, /* 10: attribute mode control */ 161 0x00, /* 11: overscan color */ 162 0x0f, /* 12: color plane enable */ 163 0x08, /* 13: horizontal PEL panning */ 164 0x00 /* 14: color select */ 165 }; 166 167 void 168 vga_reset(u_char *ISA_mem) 169 { 170 int slot, cardfound; 171 172 /* check if we are in text mode, if so, punt */ 173 outb(VGA_GR_PORT, 0x06); 174 if ((inb(VGA_GR_DATA) & 0x01) == 0) 175 return; 176 177 /* guess not, we lose. */ 178 slot = -1; 179 while ((slot = scan_PCI(slot)) > -1) { 180 cardfound = 0; 181 switch (PCI_vendor(slot)) { 182 case PCI_VENDOR_CIRRUS: 183 unlockVideo(slot); 184 outw(VGA_SR_PORT, 0x0612); /* unlock ext regs */ 185 outw(VGA_SR_PORT, 0x0700); /* reset ext sequence mode */ 186 cardfound++; 187 break; 188 case PCI_VENDOR_PARADISE: 189 unlockVideo(slot); 190 outw(VGA_GR_PORT, 0x0f05); /* unlock registers */ 191 outw(VGA_SR_PORT, 0x0648); 192 outw(VGA_CR_PORT, 0x2985); 193 outw(VGA_CR_PORT, 0x34a6); 194 outb(VGA_GR_PORT, 0x0b); /* disable linear addressing */ 195 outb(VGA_GR_DATA, inb(VGA_GR_DATA) & ~0x30); 196 outw(VGA_SR_PORT, 0x1400); 197 outb(VGA_GR_PORT, 0x0e); /* disable 256 color mode */ 198 outb(VGA_GR_DATA, inb(VGA_GR_DATA) & ~0x01); 199 outb(0xd00, 0xff); /* enable auto-centering */ 200 if (!(inb(0xd01) & 0x03)) { 201 outb(VGA_CR_PORT, 0x33); 202 outb(VGA_CR_DATA, inb(VGA_CR_DATA) & ~0x90); 203 outb(VGA_CR_PORT, 0x32); 204 outb(VGA_CR_DATA, inb(VGA_CR_DATA) | 0x04); 205 outw(VGA_CR_PORT, 0x0250); 206 outw(VGA_CR_PORT, 0x07ba); 207 outw(VGA_CR_PORT, 0x0900); 208 outw(VGA_CR_PORT, 0x15e7); 209 outw(VGA_CR_PORT, 0x2a95); 210 } 211 outw(VGA_CR_PORT, 0x34a0); 212 cardfound++; 213 break; 214 case PCI_VENDOR_S3: 215 unlockVideo(slot); 216 unlock_S3(); 217 cardfound++; 218 break; 219 default: 220 break; 221 } 222 if (cardfound) { 223 outw(VGA_SR_PORT, 0x0120); /* disable video */ 224 set_text_regs(); 225 set_text_clut(0); 226 load_font(ISA_mem); 227 set_text_regs(); 228 outw(VGA_SR_PORT, 0x0100); /* re-enable video */ 229 clear_video_memory(); 230 231 if (PCI_vendor(slot) == PCI_VENDOR_S3) 232 outb(0x3c2, 0x63); /* ??? */ 233 delay(1000); 234 } 235 } 236 return; 237 } 238 239 /* write something to a VGA attribute register */ 240 static void 241 write_attr(u_int8_t index, u_int8_t data, u_int8_t videoOn) 242 { 243 u_int8_t v; 244 245 v = inb(0x3da); /* reset attr addr toggle */ 246 if (videoOn) 247 outb(0x3c0, (index & 0x1F) | 0x20); 248 else 249 outb(0x3c0, (index & 0x1F)); 250 outb(0x3c0, data); 251 } 252 253 static void 254 set_text_regs(void) 255 { 256 int i; 257 258 for (i = 0; i < SRREGS; i++) { 259 outb(VGA_SR_PORT, SR_regs[i].idx); 260 outb(VGA_SR_PORT + 1, SR_regs[i].val); 261 } 262 for (i = 0; i < CRREGS; i++) { 263 outb(VGA_CR_PORT, CR_regs[i].idx); 264 outb(VGA_CR_PORT + 1, CR_regs[i].val); 265 } 266 for (i = 0; i < GRREGS; i++) { 267 outb(VGA_GR_PORT, GR_regs[i].idx); 268 outb(VGA_GR_PORT + 1, GR_regs[i].val); 269 } 270 271 outb(0x3c2, 0x67); /* MISC */ 272 outb(0x3c6, 0xff); /* MASK */ 273 274 for (i = 0; i < 0x14; i++) 275 write_attr(i, vga_atc[i], 0); 276 write_attr(0x14, 0x00, 1); /* color select; video on */ 277 } 278 279 static void 280 set_text_clut(int shift) 281 { 282 int i; 283 284 outb(0x3C6, 0xFF); 285 inb(0x3C7); 286 outb(0x3C8, 0); 287 inb(0x3C7); 288 289 for (i = 0; i < (16 * 3); ) { 290 outb(0x3c9, vga_dacpal[i++] << shift); 291 outb(0x3c9, vga_dacpal[i++] << shift); 292 outb(0x3c9, vga_dacpal[i++] << shift); 293 } 294 } 295 296 static void 297 load_font(u_int8_t *ISA_mem) 298 { 299 int i, j; 300 u_int8_t *font_page = (u_int8_t *)&ISA_mem[0xA0000]; 301 302 outb(0x3C2, 0x67); 303 inb(0x3DA); /* Reset Attr toggle */ 304 305 outb(0x3C0, 0x30); 306 outb(0x3C0, 0x01); /* graphics mode */ 307 outw(0x3C4, 0x0001); /* reset sequencer */ 308 outw(0x3C4, 0x0204); /* write to plane 2 */ 309 outw(0x3C4, 0x0406); /* enable plane graphics */ 310 outw(0x3C4, 0x0003); /* reset sequencer */ 311 outw(0x3CE, 0x0402); /* read plane 2 */ 312 outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ 313 outw(0x3CE, 0x0605); /* set graphics mode */ 314 315 for (i = 0; i < sizeof(font); i += 16) { 316 for (j = 0; j < 16; j++) { 317 __asm__ volatile("eieio"); 318 font_page[(2*i)+j] = font[i+j]; 319 } 320 } 321 } 322 323 static void 324 unlock_S3(void) 325 { 326 int s3_devid; 327 328 outw(VGA_CR_PORT, 0x3848); 329 outw(VGA_CR_PORT, 0x39a5); 330 outb(VGA_CR_PORT, 0x2d); 331 s3_devid = inb(VGA_CR_DATA) << 8; 332 outb(VGA_CR_PORT, 0x2e); 333 s3_devid |= inb(VGA_CR_DATA); 334 335 if (s3_devid != 0x8812) { 336 /* from the S3 manual */ 337 outb(0x46E8, 0x10); /* Put into setup mode */ 338 outb(0x3C3, 0x10); 339 outb(0x102, 0x01); /* Enable registers */ 340 outb(0x46E8, 0x08); /* Enable video */ 341 outb(0x3C3, 0x08); 342 outb(0x4AE8, 0x00); 343 outb(VGA_CR_PORT, 0x38); /* Unlock all registers */ 344 outb(VGA_CR_DATA, 0x48); 345 outb(VGA_CR_PORT, 0x39); 346 outb(VGA_CR_DATA, 0xA5); 347 outb(VGA_CR_PORT, 0x40); 348 outb(VGA_CR_DATA, inb(0x3D5)|0x01); 349 outb(VGA_CR_PORT, 0x33); 350 outb(VGA_CR_DATA, inb(0x3D5)&~0x52); 351 outb(VGA_CR_PORT, 0x35); 352 outb(VGA_CR_DATA, inb(0x3D5)&~0x30); 353 outb(VGA_CR_PORT, 0x3A); 354 outb(VGA_CR_DATA, 0x00); 355 outb(VGA_CR_PORT, 0x53); 356 outb(VGA_CR_DATA, 0x00); 357 outb(VGA_CR_PORT, 0x31); 358 outb(VGA_CR_DATA, inb(0x3D5)&~0x4B); 359 outb(VGA_CR_PORT, 0x58); 360 361 outb(VGA_CR_DATA, 0); 362 363 outb(VGA_CR_PORT, 0x54); 364 outb(VGA_CR_DATA, 0x38); 365 outb(VGA_CR_PORT, 0x60); 366 outb(VGA_CR_DATA, 0x07); 367 outb(VGA_CR_PORT, 0x61); 368 outb(VGA_CR_DATA, 0x80); 369 outb(VGA_CR_PORT, 0x62); 370 outb(VGA_CR_DATA, 0xA1); 371 outb(VGA_CR_PORT, 0x69); /* High order bits for cursor address */ 372 outb(VGA_CR_DATA, 0); 373 374 outb(VGA_CR_PORT, 0x32); 375 outb(VGA_CR_DATA, inb(0x3D5)&~0x10); 376 } else { 377 /* IBM Portable 860 */ 378 outw(VGA_SR_PORT, 0x0806); 379 outw(VGA_SR_PORT, 0x1041); 380 outw(VGA_SR_PORT, 0x1128); 381 outw(VGA_CR_PORT, 0x4000); 382 outw(VGA_CR_PORT, 0x3100); 383 outw(VGA_CR_PORT, 0x3a05); 384 outw(VGA_CR_PORT, 0x6688); 385 outw(VGA_CR_PORT, 0x5800); /* disable linear addressing */ 386 outw(VGA_CR_PORT, 0x4500); /* disable H/W cursor */ 387 outw(VGA_SR_PORT, 0x5410); /* enable auto-centering */ 388 outw(VGA_SR_PORT, 0x561f); 389 outw(VGA_SR_PORT, 0x1b80); /* lock DCLK selection */ 390 outw(VGA_CR_PORT, 0x3900); /* lock S3 registers */ 391 outw(VGA_CR_PORT, 0x3800); 392 } 393 } 394 395 static void 396 clear_video_memory(void) 397 { 398 int i, j; 399 400 for (i = 0; i < LINES; i++) { 401 for (j = 0; j < COLS; j++) { 402 videomem[((i * COLS)+j) * 2] = 0x20; /* space */ 403 videomem[((i * COLS)+j) * 2 + 1] = 0x07; /* fg/bg */ 404 } 405 } 406 } 407 408 #endif /* VGA_RESET */ 409