1 /* $NetBSD: vga_subr.c,v 1.18 2004/07/29 22:29:37 jmmv Exp $ */ 2 3 /* 4 * Copyright (c) 1998 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 /* for WSDISPLAY_BORDER_COLOR */ 30 #include "opt_wsdisplay_border.h" 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: vga_subr.c,v 1.18 2004/07/29 22:29:37 jmmv Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/queue.h> 39 #include <machine/bus.h> 40 41 #include <dev/ic/mc6845reg.h> 42 #include <dev/ic/pcdisplay.h> 43 #include <dev/ic/pcdisplayvar.h> 44 #include <dev/ic/vgareg.h> 45 #include <dev/ic/vgavar.h> 46 47 #include <dev/wscons/wsdisplayvar.h> 48 49 static void fontram(struct vga_handle *); 50 static void textram(struct vga_handle *); 51 #ifdef VGA_RESET 52 static void vga_initregs(struct vga_handle *); 53 #endif 54 55 static void 56 fontram(struct vga_handle *vh) 57 { 58 59 /* program sequencer to access character generator */ 60 61 vga_ts_write(vh, syncreset, 0x01); /* synchronous reset */ 62 vga_ts_write(vh, wrplmask, 0x04); /* write to map 2 */ 63 vga_ts_write(vh, memmode, 0x07); /* sequential addressing */ 64 vga_ts_write(vh, syncreset, 0x03); /* clear synchronous reset */ 65 66 /* program graphics controller to access character generator */ 67 68 vga_gdc_write(vh, rdplanesel, 0x02); /* select map 2 for CPU reads */ 69 vga_gdc_write(vh, mode, 0x00); /* disable odd-even addressing */ 70 vga_gdc_write(vh, misc, 0x04); /* map starts at 0xA000 */ 71 } 72 73 static void 74 textram(struct vga_handle *vh) 75 { 76 77 /* program sequencer to access video ram */ 78 79 vga_ts_write(vh, syncreset, 0x01); /* synchronous reset */ 80 vga_ts_write(vh, wrplmask, 0x03); /* write to map 0 & 1 */ 81 vga_ts_write(vh, memmode, 0x03); /* odd-even addressing */ 82 vga_ts_write(vh, syncreset, 0x03); /* clear synchronous reset */ 83 84 /* program graphics controller for text mode */ 85 86 vga_gdc_write(vh, rdplanesel, 0x00); /* select map 0 for CPU reads */ 87 vga_gdc_write(vh, mode, 0x10); /* enable odd-even addressing */ 88 /* map starts at 0xb800 or 0xb000 (mono) */ 89 vga_gdc_write(vh, misc, (vh->vh_mono ? 0x0a : 0x0e)); 90 } 91 92 #ifndef VGA_RASTERCONSOLE 93 void 94 vga_loadchars(struct vga_handle *vh, int fontset, int first, int num, int lpc, 95 const char *data) 96 { 97 int offset, i, j, s; 98 99 /* fontset number swizzle done in vga_setfontset() */ 100 offset = (fontset << 13) | (first << 5); 101 102 s = splhigh(); 103 fontram(vh); 104 105 for (i = 0; i < num; i++) 106 for (j = 0; j < lpc; j++) 107 bus_space_write_1(vh->vh_memt, vh->vh_allmemh, 108 offset + (i << 5) + j, data[i * lpc + j]); 109 110 textram(vh); 111 splx(s); 112 } 113 114 void 115 vga_readoutchars(struct vga_handle *vh, int fontset, int first, int num, 116 int lpc, char *data) 117 { 118 int offset, i, j, s; 119 120 /* fontset number swizzle done in vga_setfontset() */ 121 offset = (fontset << 13) | (first << 5); 122 123 s = splhigh(); 124 fontram(vh); 125 126 for (i = 0; i < num; i++) 127 for (j = 0; j < lpc; j++) 128 data[i * lpc + j] = bus_space_read_1(vh->vh_memt, 129 vh->vh_allmemh, offset + (i << 5) + j); 130 131 textram(vh); 132 splx(s); 133 } 134 135 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL 136 void 137 vga_copyfont01(struct vga_handle *vh) 138 { 139 int s; 140 141 s = splhigh(); 142 fontram(vh); 143 144 bus_space_copy_region_1(vh->vh_memt, vh->vh_allmemh, 0, 145 vh->vh_allmemh, 1 << 13, 1 << 13); 146 147 textram(vh); 148 splx(s); 149 } 150 #endif 151 152 void 153 vga_setfontset(struct vga_handle *vh, int fontset1, int fontset2) 154 { 155 u_int8_t cmap; 156 static const u_int8_t cmaptaba[] = { 157 0x00, 0x10, 0x01, 0x11, 158 0x02, 0x12, 0x03, 0x13 159 }; 160 static const u_int8_t cmaptabb[] = { 161 0x00, 0x20, 0x04, 0x24, 162 0x08, 0x28, 0x0c, 0x2c 163 }; 164 165 /* extended font if fontset1 != fontset2 */ 166 cmap = cmaptaba[fontset1] | cmaptabb[fontset2]; 167 168 vga_ts_write(vh, fontsel, cmap); 169 } 170 171 void 172 vga_setscreentype(struct vga_handle *vh, const struct wsscreen_descr *type) 173 { 174 175 vga_6845_write(vh, maxrow, type->fontheight - 1); 176 177 /* lo byte */ 178 vga_6845_write(vh, vde, type->fontheight * type->nrows - 1); 179 180 #ifndef PCDISPLAY_SOFTCURSOR 181 /* set cursor to last 2 lines */ 182 vga_6845_write(vh, curstart, type->fontheight - 2); 183 vga_6845_write(vh, curend, type->fontheight - 1); 184 #endif 185 /* 186 * disable colour plane 3 if needed for font selection 187 */ 188 if (type->capabilities & WSSCREEN_HILIT) { 189 /* 190 * these are the screens which don't support 191 * 512-character fonts 192 */ 193 vga_attr_write(vh, colplen, 0x0f); 194 } else 195 vga_attr_write(vh, colplen, 0x07); 196 } 197 198 #else /* !VGA_RASTERCONSOLE */ 199 void 200 vga_load_builtinfont(struct vga_handle *vh, u_int8_t *font, int firstchar, 201 int numchars) 202 { 203 int i, s; 204 205 s = splhigh(); 206 fontram(vh); 207 208 for (i = firstchar; i < firstchar + numchars; i++) 209 bus_space_read_region_1(vh->vh_memt, vh->vh_allmemh, i * 32, 210 font + i * 16, 16); 211 212 textram(vh); 213 splx(s); 214 } 215 #endif /* !VGA_RASTERCONSOLE */ 216 217 #ifdef VGA_RESET 218 /* 219 * vga_reset(): 220 * Reset VGA registers to put it into 80x25 text mode. (mode 3) 221 * This function should be called from MD consinit() on ports 222 * whose firmware does not use text mode at boot time. 223 */ 224 void 225 vga_reset(vh, md_initfunc) 226 struct vga_handle *vh; 227 void (*md_initfunc)(struct vga_handle *); 228 { 229 u_int8_t reg; 230 231 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 232 return; 233 234 reg = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAR); 235 vh->vh_mono = !(reg & 0x01); 236 237 if (bus_space_map(vh->vh_iot, vh->vh_mono ? 0x3b0 : 0x3d0, 0x10, 238 0, &vh->vh_ioh_6845)) 239 goto out1; 240 241 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 242 goto out2; 243 244 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 245 vh->vh_mono ? 0x10000 : 0x18000, 0x8000, &vh->vh_memh)) 246 goto out3; 247 248 /* check if VGA already in text mode. */ 249 if ((vga_gdc_read(vh, misc) & 0x01) == 0) 250 goto out3; 251 252 /* initialize common VGA registers */ 253 vga_initregs(vh); 254 255 /* initialize chipset specific registers */ 256 if (md_initfunc != NULL) 257 (*md_initfunc)(vh); 258 259 delay(10000); 260 261 /* clear text buffer RAM */ 262 bus_space_set_region_2(vh->vh_memt, vh->vh_memh, 0, 263 ((BG_BLACK | FG_LIGHTGREY) << 8) | ' ', 80 * 25 /*XXX*/); 264 265 out3: 266 bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000); 267 out2: 268 bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10); 269 out1: 270 bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10); 271 } 272 273 /* 274 * values to initialize registers. 275 */ 276 277 /* miscellaneous output register */ 278 #define VGA_MISCOUT 0x66 279 280 /* sequencer registers */ 281 static const u_int8_t vga_ts[] = { 282 0x03, /* 00: reset */ 283 0x00, /* 01: clocking mode */ 284 0x03, /* 02: map mask */ 285 0x00, /* 03: character map select */ 286 0x02 /* 04: memory mode */ 287 }; 288 289 /* CRT controller registers */ 290 static const u_int8_t vga_crtc[] = { 291 0x5f, /* 00: horizontal total */ 292 0x4f, /* 01: horizontal display-enable end */ 293 0x50, /* 02: start horizontal blanking */ 294 0x82, /* 03: display skew control / end horizontal blanking */ 295 0x55, /* 04: start horizontal retrace pulse */ 296 0x81, /* 05: horizontal retrace delay / end horizontal retrace */ 297 0xbf, /* 06: vetical total */ 298 0x1f, /* 07: overflow register */ 299 0x00, /* 08: preset row scan */ 300 0x4f, /* 09: overflow / maximum scan line */ 301 0x0d, /* 0A: cursor off / cursor start */ 302 0x0e, /* 0B: cursor skew / cursor end */ 303 0x00, /* 0C: start regenerative buffer address high */ 304 0x00, /* 0D: start regenerative buffer address low */ 305 0x00, /* 0E: cursor location high */ 306 0x00, /* 0F: cursor location low */ 307 0x9c, /* 10: vertical retrace start */ 308 0x8e, /* 11: vertical interrupt / vertical retrace end */ 309 0x8f, /* 12: vertical display enable end */ 310 0x28, /* 13: logical line width */ 311 0x00, /* 14: underline location */ 312 0x96, /* 15: start vertical blanking */ 313 0xb9, /* 16: end vertical blanking */ 314 0xa3, /* 17: CRT mode control */ 315 0xff /* 18: line compare */ 316 }; 317 318 /* graphics controller registers */ 319 static const u_int8_t vga_gdc[] = { 320 0x00, /* 00: set/reset map */ 321 0x00, /* 01: enable set/reset */ 322 0x00, /* 02: color compare */ 323 0x00, /* 03: data rotate */ 324 0x00, /* 04: read map select */ 325 0x10, /* 05: graphics mode */ 326 0x0e, /* 06: miscellaneous */ 327 0x00, /* 07: color don't care */ 328 0xff /* 08: bit mask */ 329 }; 330 331 /* attribute controller registers */ 332 static const u_int8_t vga_atc[] = { 333 0x00, /* 00: internal palette 0 */ 334 0x01, /* 01: internal palette 1 */ 335 0x02, /* 02: internal palette 2 */ 336 0x03, /* 03: internal palette 3 */ 337 0x04, /* 04: internal palette 4 */ 338 0x05, /* 05: internal palette 5 */ 339 0x14, /* 06: internal palette 6 */ 340 0x07, /* 07: internal palette 7 */ 341 0x38, /* 08: internal palette 8 */ 342 0x39, /* 09: internal palette 9 */ 343 0x3a, /* 0A: internal palette 10 */ 344 0x3b, /* 0B: internal palette 11 */ 345 0x3c, /* 0C: internal palette 12 */ 346 0x3d, /* 0D: internal palette 13 */ 347 0x3e, /* 0E: internal palette 14 */ 348 0x3f, /* 0F: internal palette 15 */ 349 0x0c, /* 10: attribute mode control */ 350 WSDISPLAY_BORDER_COLOR, /* 11: overscan color */ 351 0x0f, /* 12: color plane enable */ 352 0x08, /* 13: horizontal PEL panning */ 353 0x00 /* 14: color select */ 354 }; 355 356 /* video DAC palette registers */ 357 /* XXX only set up 16 colors used by internal palette in ATC regsters */ 358 static const u_int8_t vga_dacpal[] = { 359 /* R G B */ 360 0x00, 0x00, 0x00, /* BLACK */ 361 0x00, 0x00, 0x2a, /* BLUE */ 362 0x00, 0x2a, 0x00, /* GREEN */ 363 0x00, 0x2a, 0x2a, /* CYAN */ 364 0x2a, 0x00, 0x00, /* RED */ 365 0x2a, 0x00, 0x2a, /* MAGENTA */ 366 0x2a, 0x15, 0x00, /* BROWN */ 367 0x2a, 0x2a, 0x2a, /* LIGHTGREY */ 368 0x15, 0x15, 0x15, /* DARKGREY */ 369 0x15, 0x15, 0x3f, /* LIGHTBLUE */ 370 0x15, 0x3f, 0x15, /* LIGHTGREEN */ 371 0x15, 0x3f, 0x3f, /* LIGHTCYAN */ 372 0x3f, 0x15, 0x15, /* LIGHTRED */ 373 0x3f, 0x15, 0x3f, /* LIGHTMAGENTA */ 374 0x3f, 0x3f, 0x15, /* YELLOW */ 375 0x3f, 0x3f, 0x3f /* WHITE */ 376 }; 377 378 static void 379 vga_initregs(vh) 380 struct vga_handle *vh; 381 { 382 int i; 383 384 /* disable video */ 385 vga_ts_write(vh, mode, vga_ts[1] | VGA_TS_MODE_BLANK); 386 387 /* synchronous reset */ 388 vga_ts_write(vh, syncreset, 0x01); 389 /* set TS regsters */ 390 for (i = 2; i < VGA_TS_NREGS; i++) 391 _vga_ts_write(vh, i, vga_ts[i]); 392 /* clear synchronous reset */ 393 vga_ts_write(vh, syncreset, 0x03); 394 395 /* unprotect CRTC regsters */ 396 vga_6845_write(vh, vsynce, vga_6845_read(vh, vsynce) & ~0x80); 397 /* set CRTC regsters */ 398 for (i = 0; i < MC6845_NREGS; i++) 399 _vga_6845_write(vh, i, vga_crtc[i]); 400 401 /* set GDC regsters */ 402 for (i = 0; i < VGA_GDC_NREGS; i++) 403 _vga_gdc_write(vh, i, vga_gdc[i]); 404 405 /* set ATC regsters */ 406 for (i = 0; i < VGA_ATC_NREGS; i++) 407 _vga_attr_write(vh, i, vga_atc[i]); 408 409 /* set DAC palette */ 410 if (!vh->vh_mono) { 411 for (i = 0; i < 16; i++) { 412 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 413 VGA_DAC_ADDRW, vga_atc[i]); 414 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 415 VGA_DAC_PALETTE, vga_dacpal[i * 3 + 0]); 416 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 417 VGA_DAC_PALETTE, vga_dacpal[i * 3 + 1]); 418 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 419 VGA_DAC_PALETTE, vga_dacpal[i * 3 + 2]); 420 } 421 } 422 423 /* set misc output register */ 424 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 425 VGA_MISC_DATAW, VGA_MISCOUT | (vh->vh_mono ? 0 : 0x01)); 426 427 /* reenable video */ 428 vga_ts_write(vh, mode, vga_ts[1] & ~VGA_TS_MODE_BLANK); 429 } 430 #endif /* VGA_RESET */ 431