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