1 /* $NetBSD: vga_subr.c,v 1.17 2004/03/24 17:26:53 drochner 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.17 2004/03/24 17:26:53 drochner Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <sys/queue.h> 36 #include <machine/bus.h> 37 38 #include <dev/ic/mc6845reg.h> 39 #include <dev/ic/pcdisplay.h> 40 #include <dev/ic/pcdisplayvar.h> 41 #include <dev/ic/vgareg.h> 42 #include <dev/ic/vgavar.h> 43 44 #include <dev/wscons/wsdisplayvar.h> 45 46 static void fontram(struct vga_handle *); 47 static void textram(struct vga_handle *); 48 #ifdef VGA_RESET 49 static void vga_initregs(struct vga_handle *); 50 #endif 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 #ifdef VGA_RESET 215 /* 216 * vga_reset(): 217 * Reset VGA registers to put it into 80x25 text mode. (mode 3) 218 * This function should be called from MD consinit() on ports 219 * whose firmware does not use text mode at boot time. 220 */ 221 void 222 vga_reset(vh, md_initfunc) 223 struct vga_handle *vh; 224 void (*md_initfunc)(struct vga_handle *); 225 { 226 u_int8_t reg; 227 228 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 229 return; 230 231 reg = bus_space_read_1(vh->vh_iot, vh->vh_ioh_vga, VGA_MISC_DATAR); 232 vh->vh_mono = !(reg & 0x01); 233 234 if (bus_space_map(vh->vh_iot, vh->vh_mono ? 0x3b0 : 0x3d0, 0x10, 235 0, &vh->vh_ioh_6845)) 236 goto out1; 237 238 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 239 goto out2; 240 241 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 242 vh->vh_mono ? 0x10000 : 0x18000, 0x8000, &vh->vh_memh)) 243 goto out3; 244 245 /* check if VGA already in text mode. */ 246 if ((vga_gdc_read(vh, misc) & 0x01) == 0) 247 goto out3; 248 249 /* initialize common VGA registers */ 250 vga_initregs(vh); 251 252 /* initialize chipset specific registers */ 253 if (md_initfunc != NULL) 254 (*md_initfunc)(vh); 255 256 delay(10000); 257 258 /* clear text buffer RAM */ 259 bus_space_set_region_2(vh->vh_memt, vh->vh_memh, 0, 260 ((BG_BLACK | FG_LIGHTGREY) << 8) | ' ', 80 * 25 /*XXX*/); 261 262 out3: 263 bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000); 264 out2: 265 bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10); 266 out1: 267 bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10); 268 } 269 270 /* 271 * values to initialize registers. 272 */ 273 274 /* miscellaneous output register */ 275 #define VGA_MISCOUT 0x66 276 277 /* sequencer registers */ 278 static const u_int8_t vga_ts[] = { 279 0x03, /* 00: reset */ 280 0x00, /* 01: clocking mode */ 281 0x03, /* 02: map mask */ 282 0x00, /* 03: character map select */ 283 0x02 /* 04: memory mode */ 284 }; 285 286 /* CRT controller registers */ 287 static const u_int8_t vga_crtc[] = { 288 0x5f, /* 00: horizontal total */ 289 0x4f, /* 01: horizontal display-enable end */ 290 0x50, /* 02: start horizontal blanking */ 291 0x82, /* 03: display skew control / end horizontal blanking */ 292 0x55, /* 04: start horizontal retrace pulse */ 293 0x81, /* 05: horizontal retrace delay / end horizontal retrace */ 294 0xbf, /* 06: vetical total */ 295 0x1f, /* 07: overflow register */ 296 0x00, /* 08: preset row scan */ 297 0x4f, /* 09: overflow / maximum scan line */ 298 0x0d, /* 0A: cursor off / cursor start */ 299 0x0e, /* 0B: cursor skew / cursor end */ 300 0x00, /* 0C: start regenerative buffer address high */ 301 0x00, /* 0D: start regenerative buffer address low */ 302 0x00, /* 0E: cursor location high */ 303 0x00, /* 0F: cursor location low */ 304 0x9c, /* 10: vertical retrace start */ 305 0x8e, /* 11: vertical interrupt / vertical retrace end */ 306 0x8f, /* 12: vertical display enable end */ 307 0x28, /* 13: logical line width */ 308 0x00, /* 14: underline location */ 309 0x96, /* 15: start vertical blanking */ 310 0xb9, /* 16: end vertical blanking */ 311 0xa3, /* 17: CRT mode control */ 312 0xff /* 18: line compare */ 313 }; 314 315 /* graphics controller registers */ 316 static const u_int8_t vga_gdc[] = { 317 0x00, /* 00: set/reset map */ 318 0x00, /* 01: enable set/reset */ 319 0x00, /* 02: color compare */ 320 0x00, /* 03: data rotate */ 321 0x00, /* 04: read map select */ 322 0x10, /* 05: graphics mode */ 323 0x0e, /* 06: miscellaneous */ 324 0x00, /* 07: color don't care */ 325 0xff /* 08: bit mask */ 326 }; 327 328 /* attribute controller registers */ 329 static const u_int8_t vga_atc[] = { 330 0x00, /* 00: internal palette 0 */ 331 0x01, /* 01: internal palette 1 */ 332 0x02, /* 02: internal palette 2 */ 333 0x03, /* 03: internal palette 3 */ 334 0x04, /* 04: internal palette 4 */ 335 0x05, /* 05: internal palette 5 */ 336 0x14, /* 06: internal palette 6 */ 337 0x07, /* 07: internal palette 7 */ 338 0x38, /* 08: internal palette 8 */ 339 0x39, /* 09: internal palette 9 */ 340 0x3a, /* 0A: internal palette 10 */ 341 0x3b, /* 0B: internal palette 11 */ 342 0x3c, /* 0C: internal palette 12 */ 343 0x3d, /* 0D: internal palette 13 */ 344 0x3e, /* 0E: internal palette 14 */ 345 0x3f, /* 0F: internal palette 15 */ 346 0x0c, /* 10: attribute mode control */ 347 0x00, /* 11: overscan color */ 348 0x0f, /* 12: color plane enable */ 349 0x08, /* 13: horizontal PEL panning */ 350 0x00 /* 14: color select */ 351 }; 352 353 /* video DAC palette registers */ 354 /* XXX only set up 16 colors used by internal palette in ATC regsters */ 355 static const u_int8_t vga_dacpal[] = { 356 /* R G B */ 357 0x00, 0x00, 0x00, /* BLACK */ 358 0x00, 0x00, 0x2a, /* BLUE */ 359 0x00, 0x2a, 0x00, /* GREEN */ 360 0x00, 0x2a, 0x2a, /* CYAN */ 361 0x2a, 0x00, 0x00, /* RED */ 362 0x2a, 0x00, 0x2a, /* MAGENTA */ 363 0x2a, 0x15, 0x00, /* BROWN */ 364 0x2a, 0x2a, 0x2a, /* LIGHTGREY */ 365 0x15, 0x15, 0x15, /* DARKGREY */ 366 0x15, 0x15, 0x3f, /* LIGHTBLUE */ 367 0x15, 0x3f, 0x15, /* LIGHTGREEN */ 368 0x15, 0x3f, 0x3f, /* LIGHTCYAN */ 369 0x3f, 0x15, 0x15, /* LIGHTRED */ 370 0x3f, 0x15, 0x3f, /* LIGHTMAGENTA */ 371 0x3f, 0x3f, 0x15, /* YELLOW */ 372 0x3f, 0x3f, 0x3f /* WHITE */ 373 }; 374 375 static void 376 vga_initregs(vh) 377 struct vga_handle *vh; 378 { 379 int i; 380 381 /* disable video */ 382 vga_ts_write(vh, mode, vga_ts[1] | VGA_TS_MODE_BLANK); 383 384 /* synchronous reset */ 385 vga_ts_write(vh, syncreset, 0x01); 386 /* set TS regsters */ 387 for (i = 2; i < VGA_TS_NREGS; i++) 388 _vga_ts_write(vh, i, vga_ts[i]); 389 /* clear synchronous reset */ 390 vga_ts_write(vh, syncreset, 0x03); 391 392 /* unprotect CRTC regsters */ 393 vga_6845_write(vh, vsynce, vga_6845_read(vh, vsynce) & ~0x80); 394 /* set CRTC regsters */ 395 for (i = 0; i < MC6845_NREGS; i++) 396 _vga_6845_write(vh, i, vga_crtc[i]); 397 398 /* set GDC regsters */ 399 for (i = 0; i < VGA_GDC_NREGS; i++) 400 _vga_gdc_write(vh, i, vga_gdc[i]); 401 402 /* set ATC regsters */ 403 for (i = 0; i < VGA_ATC_NREGS; i++) 404 _vga_attr_write(vh, i, vga_atc[i]); 405 406 /* set DAC palette */ 407 if (!vh->vh_mono) { 408 for (i = 0; i < 16; i++) { 409 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 410 VGA_DAC_ADDRW, vga_atc[i]); 411 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 412 VGA_DAC_PALETTE, vga_dacpal[i * 3 + 0]); 413 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 414 VGA_DAC_PALETTE, vga_dacpal[i * 3 + 1]); 415 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 416 VGA_DAC_PALETTE, vga_dacpal[i * 3 + 2]); 417 } 418 } 419 420 /* set misc output register */ 421 bus_space_write_1(vh->vh_iot, vh->vh_ioh_vga, 422 VGA_MISC_DATAW, VGA_MISCOUT | (vh->vh_mono ? 0 : 0x01)); 423 424 /* reenable video */ 425 vga_ts_write(vh, mode, vga_ts[1] & ~VGA_TS_MODE_BLANK); 426 } 427 #endif /* VGA_RESET */ 428