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