1/* $NetBSD: vreset.c,v 1.11 2023/05/06 21:34:40 andvar 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 52static void write_attr(u_int8_t, u_int8_t, u_int8_t); 53static void set_text_regs(void); 54static void set_text_clut(int); 55static void load_font(u_int8_t *); 56static void unlock_S3(void); 57static void clear_video_memory(void); 58 59extern char *videomem; 60 61typedef struct vga_reg { 62 u_int8_t idx; 63 u_int8_t val; 64} vga_reg_t; 65 66static 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 74static 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 102static 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 registers */ 117static 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 137static 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 161void 162vga_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 */ 234static void 235write_attr(u_int8_t index, u_int8_t data, u_int8_t videoOn) 236{ 237 238 (void)inb(0x3da); /* reset attr addr toggle */ 239 if (videoOn) 240 outb(0x3c0, (index & 0x1F) | 0x20); 241 else 242 outb(0x3c0, (index & 0x1F)); 243 outb(0x3c0, data); 244} 245 246static void 247set_text_regs(void) 248{ 249 int i; 250 251 for (i = 0; i < SRREGS; i++) { 252 outb(VGA_SR_PORT, SR_regs[i].idx); 253 outb(VGA_SR_PORT + 1, SR_regs[i].val); 254 } 255 for (i = 0; i < CRREGS; i++) { 256 outb(VGA_CR_PORT, CR_regs[i].idx); 257 outb(VGA_CR_PORT + 1, CR_regs[i].val); 258 } 259 for (i = 0; i < GRREGS; i++) { 260 outb(VGA_GR_PORT, GR_regs[i].idx); 261 outb(VGA_GR_PORT + 1, GR_regs[i].val); 262 } 263 264 outb(0x3c2, 0x67); /* MISC */ 265 outb(0x3c6, 0xff); /* MASK */ 266 267 for (i = 0; i < 0x14; i++) 268 write_attr(i, vga_atc[i], 0); 269 write_attr(0x14, 0x00, 1); /* color select; video on */ 270} 271 272static void 273set_text_clut(int shift) 274{ 275 int i; 276 277 outb(0x3C6, 0xFF); 278 inb(0x3C7); 279 outb(0x3C8, 0); 280 inb(0x3C7); 281 282 for (i = 0; i < (16 * 3); ) { 283 outb(0x3c9, vga_dacpal[i++] << shift); 284 outb(0x3c9, vga_dacpal[i++] << shift); 285 outb(0x3c9, vga_dacpal[i++] << shift); 286 } 287} 288 289static void 290load_font(u_int8_t *ISA_mem) 291{ 292 int i, j; 293 u_int8_t *font_page = (u_int8_t *)&ISA_mem[0xA0000]; 294 295 outb(0x3C2, 0x67); 296 inb(0x3DA); /* Reset Attr toggle */ 297 298 outb(0x3C0, 0x30); 299 outb(0x3C0, 0x01); /* graphics mode */ 300 outw(0x3C4, 0x0001); /* reset sequencer */ 301 outw(0x3C4, 0x0204); /* write to plane 2 */ 302 outw(0x3C4, 0x0406); /* enable plane graphics */ 303 outw(0x3C4, 0x0003); /* reset sequencer */ 304 outw(0x3CE, 0x0402); /* read plane 2 */ 305 outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ 306 outw(0x3CE, 0x0605); /* set graphics mode */ 307 308 for (i = 0; i < sizeof(font); i += 16) { 309 for (j = 0; j < 16; j++) { 310 __asm__ volatile("eieio" ::: "memory"); 311 font_page[(2*i)+j] = font[i+j]; 312 } 313 } 314} 315 316static void 317unlock_S3(void) 318{ 319 int s3_devid; 320 321 outw(VGA_CR_PORT, 0x3848); 322 outw(VGA_CR_PORT, 0x39a5); 323 outb(VGA_CR_PORT, 0x2d); 324 s3_devid = inb(VGA_CR_DATA) << 8; 325 outb(VGA_CR_PORT, 0x2e); 326 s3_devid |= inb(VGA_CR_DATA); 327 328 if (s3_devid != 0x8812) { 329 /* from the S3 manual */ 330 outb(0x46E8, 0x10); /* Put into setup mode */ 331 outb(0x3C3, 0x10); 332 outb(0x102, 0x01); /* Enable registers */ 333 outb(0x46E8, 0x08); /* Enable video */ 334 outb(0x3C3, 0x08); 335 outb(0x4AE8, 0x00); 336 outb(VGA_CR_PORT, 0x38); /* Unlock all registers */ 337 outb(VGA_CR_DATA, 0x48); 338 outb(VGA_CR_PORT, 0x39); 339 outb(VGA_CR_DATA, 0xA5); 340 outb(VGA_CR_PORT, 0x40); 341 outb(VGA_CR_DATA, inb(0x3D5)|0x01); 342 outb(VGA_CR_PORT, 0x33); 343 outb(VGA_CR_DATA, inb(0x3D5)&~0x52); 344 outb(VGA_CR_PORT, 0x35); 345 outb(VGA_CR_DATA, inb(0x3D5)&~0x30); 346 outb(VGA_CR_PORT, 0x3A); 347 outb(VGA_CR_DATA, 0x00); 348 outb(VGA_CR_PORT, 0x53); 349 outb(VGA_CR_DATA, 0x00); 350 outb(VGA_CR_PORT, 0x31); 351 outb(VGA_CR_DATA, inb(0x3D5)&~0x4B); 352 outb(VGA_CR_PORT, 0x58); 353 354 outb(VGA_CR_DATA, 0); 355 356 outb(VGA_CR_PORT, 0x54); 357 outb(VGA_CR_DATA, 0x38); 358 outb(VGA_CR_PORT, 0x60); 359 outb(VGA_CR_DATA, 0x07); 360 outb(VGA_CR_PORT, 0x61); 361 outb(VGA_CR_DATA, 0x80); 362 outb(VGA_CR_PORT, 0x62); 363 outb(VGA_CR_DATA, 0xA1); 364 outb(VGA_CR_PORT, 0x69); /* High order bits for cursor address */ 365 outb(VGA_CR_DATA, 0); 366 367 outb(VGA_CR_PORT, 0x32); 368 outb(VGA_CR_DATA, inb(0x3D5)&~0x10); 369 } else { 370 /* IBM Portable 860 */ 371 outw(VGA_SR_PORT, 0x0806); 372 outw(VGA_SR_PORT, 0x1041); 373 outw(VGA_SR_PORT, 0x1128); 374 outw(VGA_CR_PORT, 0x4000); 375 outw(VGA_CR_PORT, 0x3100); 376 outw(VGA_CR_PORT, 0x3a05); 377 outw(VGA_CR_PORT, 0x6688); 378 outw(VGA_CR_PORT, 0x5800); /* disable linear addressing */ 379 outw(VGA_CR_PORT, 0x4500); /* disable H/W cursor */ 380 outw(VGA_SR_PORT, 0x5410); /* enable auto-centering */ 381 outw(VGA_SR_PORT, 0x561f); 382 outw(VGA_SR_PORT, 0x1b80); /* lock DCLK selection */ 383 outw(VGA_CR_PORT, 0x3900); /* lock S3 registers */ 384 outw(VGA_CR_PORT, 0x3800); 385 } 386} 387 388static void 389clear_video_memory(void) 390{ 391 int i, j; 392 393 for (i = 0; i < LINES; i++) { 394 for (j = 0; j < COLS; j++) { 395 videomem[((i * COLS)+j) * 2] = 0x20; /* space */ 396 videomem[((i * COLS)+j) * 2 + 1] = 0x07; /* fg/bg */ 397 } 398 } 399} 400 401#endif /* VGA_RESET */ 402