vgafb.c revision 1.2
1/* $OpenBSD: vgafb.c,v 1.2 2001/09/13 13:38:45 drahn Exp $ */ 2/* $NetBSD: vga.c,v 1.3 1996/12/02 22:24:54 cgd Exp $ */ 3 4/* 5 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 6 * All rights reserved. 7 * 8 * Author: Chris G. Demetriou 9 * 10 * Permission to use, copy, modify and distribute this software and 11 * its documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 */ 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kernel.h> 34#include <sys/device.h> 35#include <sys/buf.h> 36 37#include <vm/vm.h> 38#include <uvm/uvm_extern.h> 39 40#include <machine/bus.h> 41 42#include <dev/cons.h> 43#include <dev/ofw/openfirm.h> 44 45#include <dev/wscons/wsconsio.h> 46#include <dev/wscons/wsdisplayvar.h> 47#include <dev/wscons/wscons_raster.h> 48#include <dev/rcons/raster.h> 49 50#include <arch/macppc/pci/vgafbvar.h> 51 52/* parameters set by OF to detect console */ 53extern int cons_displaytype; 54extern bus_space_tag_t cons_membus; 55extern bus_space_handle_t cons_display_mem_h; 56extern bus_space_handle_t cons_display_ctl_h; 57extern int cons_width; 58extern int cons_linebytes; 59extern int cons_height; 60extern int cons_depth; 61extern int cons_display_ofh; 62 63struct cfdriver vgafb_cd = { 64 NULL, "vgafb", DV_DULL, 65}; 66 67void vgafb_cursor __P((void *, int, int, int)); 68void vgafb_putchar __P((void *, int, int, u_int, long)); 69void vgafb_copycols __P((void *, int, int, int, int)); 70void vgafb_erasecols __P((void *, int, int, int)); 71void vgafb_copyrows __P((void *, int, int, int)); 72void vgafb_eraserows __P((void *, int, int)); 73void vgafb_alloc_attr __P((void *c, int fg, int bg, int flags, long *)); 74 75void vgafb_setcolor __P((unsigned int index, u_int8_t r, u_int8_t g, u_int8_t b)); 76extern const char fontdata_8x16[]; 77 78struct vgafb_devconfig { 79 struct rcons dc_ri; 80}; 81struct raster vgafb_raster; 82 83 84struct vgafb_devconfig vgafb_console_dc; 85 86struct wsscreen_descr vgafb_stdscreen = { 87 "std", 88 0, 0, /* will be filled in -- XXX shouldn't, it's global */ 89 0, 90 0, 0, 91 WSSCREEN_REVERSE 92}; 93const struct wsscreen_descr *vgafb_scrlist[] = { 94 &vgafb_stdscreen, 95 /* XXX other formats, graphics screen? */ 96}; 97 98struct wsscreen_list vgafb_screenlist = { 99 sizeof(vgafb_scrlist) / sizeof(struct wsscreen_descr *), vgafb_scrlist 100}; 101 102 103struct wsdisplay_emulops vgafb_emulops = { 104 rcons_cursor, 105 rcons_mapchar, 106 rcons_putchar, 107 rcons_copycols, 108 rcons_erasecols, 109 rcons_copyrows, 110 rcons_eraserows, 111 rcons_alloc_attr 112}; 113 114struct wsdisplay_accessops vgafb_accessops = { 115 vgafb_ioctl, 116 vgafb_mmap, 117 vgafb_alloc_screen, 118 vgafb_free_screen, 119 vgafb_show_screen, 120 0 /* load_font */ 121}; 122 123int vgafb_print __P((void *, const char *)); 124int vgafb_getcmap __P((struct vgafb_config *vc, struct wsdisplay_cmap *cm)); 125int vgafb_putcmap __P((struct vgafb_config *vc, struct wsdisplay_cmap *cm)); 126 127#define FONT_WIDTH 8 128#define FONT_HEIGHT 16 129 130/* 131 * The following functions implement back-end configuration grabbing 132 * and attachment. 133 */ 134int 135vgafb_common_probe(iot, memt, iobase, iosize, membase, memsize, mmiobase, mmiosize) 136 bus_space_tag_t iot, memt; 137 u_int32_t iobase, membase, mmiobase; 138 size_t iosize, memsize, mmiosize; 139{ 140 bus_space_handle_t ioh_b, ioh_c, ioh_d, memh, mmioh; 141 int gotio_b, gotio_c, gotio_d, gotmem, gotmmio, rv; 142 143 gotio_b = gotio_c = gotio_d = gotmem = gotmmio = rv = 0; 144 145 if (iosize != 0) { 146 if (bus_space_map(iot, iobase+0x3b0, 0xc, 0, &ioh_b)) 147 goto bad; 148 gotio_b = 1; 149 if (bus_space_map(iot, iobase+0x3c0, 0x10, 0, &ioh_c)) 150 goto bad; 151 gotio_c = 1; 152 if (bus_space_map(iot, iobase+0x3d0, 0x10, 0, &ioh_d)) 153 goto bad; 154 gotio_d = 1; 155 } 156 if (mmiosize != 0) { 157 printf("vgafb_common_probe, mmio base %x size %x\n", 158 mmiobase, mmiosize); 159 if (bus_space_map(iot, mmiobase, mmiosize, 0, &mmioh)) 160 goto bad; 161 printf("vgafb_common_probe, mmio done\n"); 162 gotmmio = 1; 163 } 164#if 0 165 printf("vgafb_common_probe, mem base %x size %x memt %x\n", 166 membase, memsize, memt); 167#endif 168 169#if 0 170 if (bus_space_map(memt, membase, memsize, 0, &memh)) 171 goto bad; 172 gotmem = 1; 173 174 /* CR1 - Horiz. Display End */ 175 bus_space_write_1(iot, ioh_d, 4, 0x1); 176 width = bus_space_read_1(iot, ioh_d, 5); 177 /* this is not bit width yet */ 178 179 /* use CR17 - mode control for this?? */ 180 if ((width != 0xff) && (width < 600)) { 181 /* not accessable or in graphics mode? */ 182 goto bad; 183 } 184#endif 185 186#if 0 187 vgadata = bus_space_read_2(memt, memh, 0); 188 bus_space_write_2(memt, memh, 0, 0xa55a); 189 rv = (bus_space_read_2(memt, memh, 0) == 0xa55a); 190 bus_space_write_2(memt, memh, 0, vgadata); 191#else 192 rv = 1; 193#endif 194 195 196bad: 197 if (gotio_b) 198 bus_space_unmap(iot, ioh_b, 0xc); 199 if (gotio_c) 200 bus_space_unmap(iot, ioh_c, 0x10); 201 if (gotio_d) 202 bus_space_unmap(iot, ioh_d, 0x10); 203 if (gotmmio) 204 bus_space_unmap(memt, mmioh, mmiosize); 205 if (gotmem) 206 bus_space_unmap(memt, memh, memsize); 207 208 return (rv); 209} 210 211void 212vgafb_common_setup(iot, memt, vc, iobase, iosize, membase, memsize, mmiobase, mmiosize) 213 bus_space_tag_t iot, memt; 214 struct vgafb_config *vc; 215 u_int32_t iobase, membase, mmiobase; 216 size_t iosize, memsize, mmiosize; 217{ 218 219 vc->vc_iot = iot; 220 vc->vc_memt = memt; 221 vc->vc_paddr = membase; 222 223 if (iosize != 0) { 224 if (bus_space_map(vc->vc_iot, iobase+0x3b0, 0xc, 0, &vc->vc_ioh_b)) 225 panic("vgafb_common_setup: couldn't map io b"); 226 if (bus_space_map(vc->vc_iot, iobase+0x3c0, 0x10, 0, &vc->vc_ioh_c)) 227 panic("vgafb_common_setup: couldn't map io c"); 228 if (bus_space_map(vc->vc_iot, iobase+0x3d0, 0x10, 0, &vc->vc_ioh_d)) 229 panic("vgafb_common_setup: couldn't map io d"); 230 } 231 if (mmiosize != 0) { 232 if (bus_space_map(vc->vc_memt, mmiobase, mmiosize, 0, &vc->vc_mmioh)) 233 panic("vgafb_common_setup: couldn't map mmio"); 234 } 235#if 0 236 printf("commons setup mapping mem base %x size %x\n", membase, memsize); 237#endif 238 /* memsize should only be visable region for console */ 239 memsize = cons_height * cons_linebytes; 240 if (bus_space_map(vc->vc_memt, membase, memsize, 0, &vc->vc_memh)) 241 panic("vgafb_common_setup: couldn't map memory"); 242 cons_display_mem_h = vc->vc_memh; 243 vc->vc_ofh = cons_display_ofh; 244#if 0 245 printf("display_mem_h %x\n", cons_display_mem_h ); 246#endif 247 248#if 0 249 if (iosize != 0) { 250 /* CR1 - Horiz. Display End */ 251 bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x1); 252 width = bus_space_read_1(iot, vc->vc_ioh_d, 5); 253 /* (stored value + 1) * depth -> pixel width */ 254 width = ( width + 1 ) * 8; 255 256 /* CR1 - Horiz. Display End */ 257 bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x12); 258 { 259 u_int8_t t1, t2, t3; 260 bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x12); 261 t1 = bus_space_read_1(iot, vc->vc_ioh_d, 5); 262 263 bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x7); 264 t2 = bus_space_read_1(iot, vc->vc_ioh_d, 5); 265 height = t1 + ((t2&0x40) << 3) 266 + ((t2&0x02) << 7) + 1; 267 bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x17); 268 t3 = bus_space_read_1(iot, vc->vc_ioh_d, 5); 269 if (t3 & 0x04) { 270 height *= 2; 271 } 272 if (t1 == 0xff && t2 == 0xff && t3 == 0xff) { 273 /* iospace not working??? */ 274 /* hope, better guess than 2048x2048 */ 275 width = 640; 276 height = 480; 277 } 278 } 279 vc->vc_ncol = width / FONT_WIDTH; 280 vc->vc_nrow = height / FONT_HEIGHT; 281 } else { 282 /* iosize == 0 283 * default to 640x480 and hope 284 */ 285 vc->vc_ncol = 640 / FONT_WIDTH; 286 vc->vc_nrow = 480 / FONT_HEIGHT; 287 } 288 vc->vc_ncol = cons_width / FONT_WIDTH; 289 vc->vc_nrow = cons_height / FONT_HEIGHT; 290 printf(", %dx%d", vc->vc_ncol, vc->vc_nrow); 291#endif 292 293 vc->vc_crow = vc->vc_ccol = 0; /* Has to be some onscreen value */ 294 vc->vc_so = 0; 295 296 /* clear screen, frob cursor, etc.? */ 297 /* 298 */ 299 300#if defined(alpha) 301 /* 302 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!! 303 * XXX Therefore, though the comments say "blue bg", the code uses 304 * XXX the value for a red background! 305 */ 306 vc->vc_at = 0x40 | 0x0f; /* blue bg|white fg */ 307 vc->vc_so_at = 0x40 | 0x0f | 0x80; /* blue bg|white fg|blink */ 308#else 309 vc->vc_at = 0x00 | 0xf; /* black bg|white fg */ 310 vc->vc_so_at = 0x00 | 0xf | 0x80; /* black bg|white fg|blink */ 311#endif 312} 313 314void 315vgafb_wsdisplay_attach(parent, vc, console) 316 struct device *parent; 317 struct vgafb_config *vc; 318 int console; 319{ 320 struct wsemuldisplaydev_attach_args aa; 321 322 aa.console = console; 323 aa.scrdata = &vgafb_screenlist; 324 aa.accessops = &vgafb_accessops; 325 aa.accesscookie = vc; 326 327 config_found(parent, &aa, wsemuldisplaydevprint); 328} 329 330 331int 332vgafb_print(aux, pnp) 333 void *aux; 334 const char *pnp; 335{ 336 337 if (pnp) 338 printf("wsdisplay at %s", pnp); 339 return (UNCONF); 340} 341 342int 343vgafb_ioctl(v, cmd, data, flag, p) 344 void *v; 345 u_long cmd; 346 caddr_t data; 347 int flag; 348 struct proc *p; 349{ 350 struct vgafb_config *vc = v; 351 struct wsdisplay_fbinfo *wdf; 352 353 switch (cmd) { 354 case WSDISPLAYIO_GTYPE: 355 *(u_int *)data = WSDISPLAY_TYPE_PCIVGA; 356 return 0; 357 case WSDISPLAYIO_GINFO: 358 wdf = (void *)data; 359 wdf->height = cons_height; 360 wdf->width = cons_width; 361 wdf->depth = cons_depth; 362 wdf->cmsize = 256; 363 return 0; 364 365 case WSDISPLAYIO_LINEBYTES: 366 *(u_int *)data = cons_linebytes; 367 return 0; 368 369 case WSDISPLAYIO_GETCMAP: 370 return vgafb_getcmap(vc, (struct wsdisplay_cmap *)data); 371 372 case WSDISPLAYIO_PUTCMAP: 373 return vgafb_putcmap(vc, (struct wsdisplay_cmap *)data); 374 375 case WSDISPLAYIO_SVIDEO: 376 case WSDISPLAYIO_GVIDEO: 377 case WSDISPLAYIO_GCURPOS: 378 case WSDISPLAYIO_SCURPOS: 379 case WSDISPLAYIO_GCURMAX: 380 case WSDISPLAYIO_GCURSOR: 381 case WSDISPLAYIO_SCURSOR: 382 return -1; /* not supported yet */ 383 } 384 385 /* XXX */ 386 return -1; 387} 388 389paddr_t 390vgafb_mmap(v, offset, prot) 391 void *v; 392 off_t offset; 393 int prot; 394{ 395 struct vgafb_config *vc = v; 396 bus_space_handle_t h; 397 398 /* memsize... */ 399 if (offset >= 0x00000 && offset < 0x800000) /* 8MB of mem??? */ 400 h = vc->vc_paddr + offset; 401 /* XXX the following are probably wrong. we want physical addresses 402 here, not virtual ones */ 403 else if (offset >= 0x10000000 && offset < 0x10040000 ) 404 /* 256KB of iohb */ 405 h = vc->vc_ioh_b; 406 else if (offset >= 0x10040000 && offset < 0x10080000) 407 /* 256KB of iohc */ 408 h = vc->vc_ioh_c; 409 else if (offset >= 0x18880000 && offset < 0x100c0000) 410 /* 256KB of iohd */ 411 h = vc->vc_ioh_d; 412 else if (offset >= 0x20000000 && offset < 0x30000000) 413 /* mmiosize... */ 414 h = vc->vc_mmioh + (offset - 0x20000000); 415 else { 416 /* XXX - allow mapping of the actual physical 417 * device address, if the address is read from 418 * pci bus config space 419 */ 420 421 /* NEEDS TO BE RESTRICTED to valid addresses for this device */ 422 423 h = offset; 424 } 425 426#ifdef alpha 427 port = (u_int32_t *)(h << 5); 428 return alpha_btop(port); /* XXX */ 429#elif defined(i386) 430 port = (u_int32_t *)(h << 5); 431 return i386_btop(port); 432#elif defined(__powerpc__) 433 { 434 /* huh ??? */ 435 return h; 436 /* 437 return powerpc_btop(port); 438 */ 439 } 440#endif 441} 442 443 444void 445vgafb_cnprobe(cp) 446 struct consdev *cp; 447{ 448 if (cons_displaytype != 1) { 449 cp->cn_pri = CN_DEAD; 450 return; 451 } 452 453 cp->cn_pri = CN_REMOTE; 454 #if 0 455 for (j = 0; j < 2; j++) { 456 for (i = 0; i < cons_width * cons_height; i++) { 457 bus_space_write_1(cons_membus, 458 cons_display_mem_h, i, j); 459 460 } 461 } 462 #endif 463 464} 465 466extern struct raster_font fontdata8x16; 467void 468vgafb_cnattach(iot, memt, pc, bus, device, function) 469 void * pc; 470 bus_space_tag_t iot, memt; 471 int bus, device, function; 472{ 473 long defattr; 474 475 struct vgafb_devconfig *dc = &vgafb_console_dc; 476 struct rcons *ri = &dc->dc_ri; 477 ri->rc_sp = &vgafb_raster; 478 479 ri->rc_sp->width = cons_width; 480 ri->rc_sp->height = cons_height; 481 ri->rc_sp->depth = cons_depth; 482 ri->rc_sp->linelongs = cons_linebytes /4; /* XXX */ 483 ri->rc_sp->pixels = (void *)cons_display_mem_h; 484 ri->rc_crow = ri->rc_ccol = -1; 485 ri->rc_crowp = &ri->rc_crow; 486 ri->rc_ccolp = &ri->rc_ccol; 487 488 rcons_init(ri, 160, 160); 489 490 vgafb_stdscreen.nrows = ri->rc_maxrow; 491 vgafb_stdscreen.ncols = ri->rc_maxcol; 492 vgafb_stdscreen.textops = &vgafb_emulops; 493 rcons_alloc_attr(ri, 0, 0, 0, &defattr); 494 495 #if 0 496 { 497 int i; 498 for (i = 0; i < cons_width * cons_height; i++) { 499 bus_space_write_1(cons_membus, 500 cons_display_mem_h, i, 0x1); 501 502 } 503 } 504 #endif 505 { 506 int i; 507 for (i = 0; i < 256; i++) { 508 vgafb_setcolor(i, 255,255,255); 509 } 510 } 511 vgafb_setcolor(WSCOL_BLACK, 0, 0, 0); 512 vgafb_setcolor(255, 255, 255, 255); 513 vgafb_setcolor(WSCOL_RED, 255, 0, 0); 514 vgafb_setcolor(WSCOL_GREEN, 0, 255, 0); 515 vgafb_setcolor(WSCOL_BROWN, 154, 85, 46); 516 vgafb_setcolor(WSCOL_BLUE, 0, 0, 255); 517 vgafb_setcolor(WSCOL_MAGENTA, 255, 255, 0); 518 vgafb_setcolor(WSCOL_CYAN, 0, 255, 255); 519 vgafb_setcolor(WSCOL_WHITE, 255, 255, 255); 520 wsdisplay_cnattach(&vgafb_stdscreen, ri, 0, 0, defattr); 521} 522 523void 524vgafb_setcolor(index, r, g, b) 525 unsigned int index; 526 u_int8_t r, g, b; 527{ 528 OF_call_method_1("color!", cons_display_ofh, 4, r, g, b, index); 529} 530 531int 532vgafb_getcmap(vc, cm) 533 struct vgafb_config *vc; 534 struct wsdisplay_cmap *cm; 535{ 536 u_int index = cm->index; 537 u_int count = cm->count; 538 int error; 539 540 if (index >= 256 || count > 256 || index + count > 256) 541 return EINVAL; 542 543 error = copyout(&vc->vc_cmap_red[index], cm->red, count); 544 if (error) 545 return error; 546 error = copyout(&vc->vc_cmap_green[index], cm->green, count); 547 if (error) 548 return error; 549 error = copyout(&vc->vc_cmap_blue[index], cm->blue, count); 550 if (error) 551 return error; 552 553 return 0; 554} 555 556int 557vgafb_putcmap(vc, cm) 558 struct vgafb_config *vc; 559 struct wsdisplay_cmap *cm; 560{ 561 int index = cm->index; 562 int count = cm->count; 563 int i; 564 u_char *r, *g, *b; 565 566 if (cm->index >= 256 || cm->count > 256 || 567 (cm->index + cm->count) > 256) 568 return EINVAL; 569 if (!uvm_useracc(cm->red, cm->count, B_READ) || 570 !uvm_useracc(cm->green, cm->count, B_READ) || 571 !uvm_useracc(cm->blue, cm->count, B_READ)) 572 return EFAULT; 573 copyin(cm->red, &(vc->vc_cmap_red[index]), count); 574 copyin(cm->green, &(vc->vc_cmap_green[index]), count); 575 copyin(cm->blue, &(vc->vc_cmap_blue[index]), count); 576 577 r = &(vc->vc_cmap_red[index]); 578 g = &(vc->vc_cmap_green[index]); 579 b = &(vc->vc_cmap_blue[index]); 580 581 for (i = 0; i < count; i++) { 582 OF_call_method_1("color!", vc->vc_ofh, 4, *r, *g, *b, index); 583 r++, g++, b++, index++; 584 } 585 return 0; 586} 587