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