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