vgafb.c revision 1.54
1/* $OpenBSD: vgafb.c,v 1.54 2013/08/27 21:00:52 mpi 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/device.h> 34 35#include <machine/bus.h> 36 37#include <dev/wscons/wsconsio.h> 38#include <dev/wscons/wsdisplayvar.h> 39#include <dev/rasops/rasops.h> 40 41#include <dev/ofw/openfirm.h> 42#include <macppc/macppc/ofw_machdep.h> 43 44#include <dev/pci/pcireg.h> 45#include <dev/pci/pcivar.h> 46#include <dev/pci/vga_pcivar.h> 47 48struct vga_config { 49 bus_space_tag_t vc_memt; 50 bus_space_handle_t vc_memh; 51 52 /* Colormap */ 53 u_char vc_cmap_red[256]; 54 u_char vc_cmap_green[256]; 55 u_char vc_cmap_blue[256]; 56 57 struct rasops_info ri; 58 59 bus_addr_t iobase, membase, mmiobase; 60 bus_size_t iosize, memsize, mmiosize; 61 62 int vc_backlight_on; 63 u_int vc_mode; 64}; 65 66int vgafb_ioctl(void *, u_long, caddr_t, int, struct proc *); 67paddr_t vgafb_mmap(void *, off_t, int); 68int vgafb_alloc_screen(void *, const struct wsscreen_descr *, void **, 69 int *, int *, long *); 70void vgafb_free_screen(void *, void *); 71int vgafb_show_screen(void *, void *, int, void (*cb)(void *, int, int), 72 void *); 73void vgafb_burn(void *v, u_int , u_int); 74void vgafb_restore_default_colors(struct vga_config *); 75int vgafb_is_console(int); 76void vgafb_wsdisplay_attach(struct device *, struct vga_config *); 77int vgafb_mapregs(struct vga_config *, struct pci_attach_args *); 78 79struct vga_config vgafbcn; 80 81struct wsscreen_descr vgafb_stdscreen = { 82 "std", 83 0, 0, 84 0, 85 0, 0, 86 WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 87 WSSCREEN_REVERSE | WSSCREEN_WSCOLORS 88}; 89 90const struct wsscreen_descr *vgafb_scrlist[] = { 91 &vgafb_stdscreen, 92}; 93 94struct wsscreen_list vgafb_screenlist = { 95 nitems(vgafb_scrlist), vgafb_scrlist 96}; 97 98struct wsdisplay_accessops vgafb_accessops = { 99 vgafb_ioctl, 100 vgafb_mmap, 101 vgafb_alloc_screen, 102 vgafb_free_screen, 103 vgafb_show_screen, 104 NULL, /* load_font */ 105 NULL, /* scrollback */ 106 NULL, /* getchar */ 107 vgafb_burn, /* burner */ 108}; 109 110int vgafb_getcmap(struct vga_config *vc, struct wsdisplay_cmap *cm); 111int vgafb_putcmap(struct vga_config *vc, struct wsdisplay_cmap *cm); 112 113int vgafb_match(struct device *, void *, void *); 114void vgafb_attach(struct device *, struct device *, void *); 115 116const struct cfattach vgafb_ca = { 117 sizeof(struct device), vgafb_match, vgafb_attach, 118}; 119 120struct cfdriver vgafb_cd = { 121 NULL, "vgafb", DV_DULL, 122}; 123 124#ifdef APERTURE 125extern int allowaperture; 126#endif 127 128int 129vgafb_match(struct device *parent, void *match, void *aux) 130{ 131 struct pci_attach_args *pa = aux; 132 int node; 133 134 if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0) { 135 /* 136 * XXX Graphic cards found in iMac G3 have a ``Misc'' 137 * subclass, match them all. 138 */ 139 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY || 140 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_MISC) 141 return (0); 142 } 143 144 /* 145 * XXX Non-console devices do not get configured by the PROM, 146 * XXX so do not attach them yet. 147 */ 148 node = PCITAG_NODE(pa->pa_tag); 149 if (!vgafb_is_console(node)) 150 return (0); 151 152 return (1); 153} 154 155void 156vgafb_attach(struct device *parent, struct device *self, void *aux) 157{ 158 struct pci_attach_args *pa = aux; 159 struct vga_config *vc = &vgafbcn; 160 161 if (vgafb_mapregs(vc, pa)) 162 return; 163 164 vgafb_wsdisplay_attach(self, vc); 165} 166 167void 168vgafb_restore_default_colors(struct vga_config *vc) 169{ 170 const uint8_t *color; 171 int i; 172 173 for (i = 0; i < 256; i++) { 174 175 color = &rasops_cmap[i * 3]; 176 177 vc->vc_cmap_red[i] = color[0]; 178 vc->vc_cmap_green[i] = color[1]; 179 vc->vc_cmap_blue[i] = color[2]; 180 } 181 182 of_setcolors(0, 256, vc->vc_cmap_red, vc->vc_cmap_green, 183 vc->vc_cmap_blue); 184} 185 186void 187vgafb_wsdisplay_attach(struct device *parent, struct vga_config *vc) 188{ 189 struct wsemuldisplaydev_attach_args aa; 190 struct rasops_info *ri = &vc->ri; 191 long defattr; 192 193 ri->ri_flg = RI_CENTER | RI_VCONS | RI_WRONLY; 194 rasops_init(ri, 160, 160); 195 196 ri->ri_ops.alloc_attr(ri->ri_active, 0, 0, 0, &defattr); 197 wsdisplay_cnattach(&vgafb_stdscreen, ri->ri_active, 0, 0, defattr); 198 199 aa.console = 1; 200 aa.scrdata = &vgafb_screenlist; 201 aa.accessops = &vgafb_accessops; 202 aa.accesscookie = vc; 203 aa.defaultscreens = 0; 204 205 /* no need to keep the burner function if no hw support */ 206 if (cons_backlight_available == 0) 207 vgafb_accessops.burn_screen = NULL; 208 else { 209 vc->vc_backlight_on = WSDISPLAYIO_VIDEO_OFF; 210 vgafb_burn(vc, WSDISPLAYIO_VIDEO_ON, 0); /* paranoia */ 211 } 212 213 config_found(parent, &aa, wsemuldisplaydevprint); 214} 215 216int 217vgafb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 218{ 219 struct vga_config *vc = v; 220 struct wsdisplay_fbinfo *wdf; 221 222 switch (cmd) { 223 case WSDISPLAYIO_GTYPE: 224 *(u_int *)data = WSDISPLAY_TYPE_PCIVGA; 225 return 0; 226 case WSDISPLAYIO_GINFO: 227 wdf = (void *)data; 228 wdf->height = cons_height; 229 wdf->width = cons_width; 230 wdf->depth = cons_depth; 231 wdf->cmsize = 256; 232 return 0; 233 234 case WSDISPLAYIO_LINEBYTES: 235 *(u_int *)data = cons_linebytes; 236 return 0; 237 238 case WSDISPLAYIO_GETCMAP: 239 return vgafb_getcmap(vc, (struct wsdisplay_cmap *)data); 240 241 case WSDISPLAYIO_PUTCMAP: 242 return vgafb_putcmap(vc, (struct wsdisplay_cmap *)data); 243 244 case WSDISPLAYIO_SMODE: 245 vc->vc_mode = *(u_int *)data; 246 /* track the state of the display, 247 * if returning to WSDISPLAYIO_MODE_EMUL 248 * restore the last palette, workaround for 249 * bad accellerated X servers that does not restore 250 * the correct palette. 251 */ 252 if (cons_depth == 8) 253 vgafb_restore_default_colors(vc); 254 break; 255 256 case WSDISPLAYIO_GETPARAM: 257 { 258 struct wsdisplay_param *dp = (struct wsdisplay_param *)data; 259 260 switch (dp->param) { 261 case WSDISPLAYIO_PARAM_BRIGHTNESS: 262 if (cons_backlight_available != 0) { 263 dp->min = MIN_BRIGHTNESS; 264 dp->max = MAX_BRIGHTNESS; 265 dp->curval = cons_brightness; 266 return 0; 267 } 268 return -1; 269 case WSDISPLAYIO_PARAM_BACKLIGHT: 270 if (cons_backlight_available != 0) { 271 dp->min = 0; 272 dp->max = 1; 273 dp->curval = vc->vc_backlight_on; 274 return 0; 275 } else 276 return -1; 277 } 278 } 279 return -1; 280 281 case WSDISPLAYIO_SETPARAM: 282 { 283 struct wsdisplay_param *dp = (struct wsdisplay_param *)data; 284 285 switch (dp->param) { 286 case WSDISPLAYIO_PARAM_BRIGHTNESS: 287 if (cons_backlight_available == 1) { 288 of_setbrightness(dp->curval); 289 return 0; 290 } else 291 return -1; 292 case WSDISPLAYIO_PARAM_BACKLIGHT: 293 if (cons_backlight_available != 0) { 294 vgafb_burn(vc, 295 dp->curval ? WSDISPLAYIO_VIDEO_ON : 296 WSDISPLAYIO_VIDEO_OFF, 0); 297 return 0; 298 } else 299 return -1; 300 } 301 } 302 return -1; 303 304 case WSDISPLAYIO_SVIDEO: 305 case WSDISPLAYIO_GVIDEO: 306 break; 307 308 case WSDISPLAYIO_GCURPOS: 309 case WSDISPLAYIO_SCURPOS: 310 case WSDISPLAYIO_GCURMAX: 311 case WSDISPLAYIO_GCURSOR: 312 case WSDISPLAYIO_SCURSOR: 313 default: 314 return -1; /* not supported yet */ 315 } 316 317 return (0); 318} 319 320paddr_t 321vgafb_mmap(void *v, off_t off, int prot) 322{ 323 struct vga_config *vc = v; 324 325 if (off & PGOFSET) 326 return (-1); 327 328 switch (vc->vc_mode) { 329 case WSDISPLAYIO_MODE_MAPPED: 330#ifdef APERTURE 331 if (allowaperture == 0) 332 return (-1); 333#endif 334 335 if (vc->mmiosize == 0) 336 return (-1); 337 338 if (off >= vc->membase && off < (vc->membase + vc->memsize)) 339 return (off); 340 341 if (off >= vc->mmiobase && off < (vc->mmiobase + vc->mmiosize)) 342 return (off); 343 break; 344 345 case WSDISPLAYIO_MODE_DUMBFB: 346 if (off >= 0x00000 && off < vc->memsize) 347 return (vc->membase + off); 348 break; 349 350 } 351 352 return (-1); 353} 354 355int 356vgafb_is_console(int node) 357{ 358 extern int fbnode; 359 360 return (fbnode == node); 361} 362 363int 364vgafb_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check) 365{ 366 struct vga_config *vc = &vgafbcn; 367 struct rasops_info *ri = &vc->ri; 368 long defattr; 369 370 vc->vc_memt = memt; 371 vc->membase = cons_addr; 372 vc->memsize = cons_linebytes * cons_height; 373 vc->vc_memh = (bus_space_handle_t)mapiodev(vc->membase, vc->memsize); 374 375 if (cons_depth == 8) 376 vgafb_restore_default_colors(vc); 377 378 ri->ri_flg = RI_FULLCLEAR | RI_CLEAR; 379 ri->ri_depth = cons_depth; 380 ri->ri_bits = (void *)vc->vc_memh; 381 ri->ri_width = cons_width; 382 ri->ri_height = cons_height; 383 ri->ri_stride = cons_linebytes; 384 ri->ri_hw = vc; 385 386 rasops_init(ri, 160, 160); 387 388 vgafb_stdscreen.nrows = ri->ri_rows; 389 vgafb_stdscreen.ncols = ri->ri_cols; 390 vgafb_stdscreen.textops = &ri->ri_ops; 391 392 ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr); 393 394 wsdisplay_cnattach(&vgafb_stdscreen, ri, 0, 0, defattr); 395 396 return (0); 397} 398 399int 400vgafb_getcmap(struct vga_config *vc, struct wsdisplay_cmap *cm) 401{ 402 u_int index = cm->index; 403 u_int count = cm->count; 404 int error; 405 406 if (index >= 256 || count > 256 - index) 407 return EINVAL; 408 409 error = copyout(&vc->vc_cmap_red[index], cm->red, count); 410 if (error) 411 return error; 412 error = copyout(&vc->vc_cmap_green[index], cm->green, count); 413 if (error) 414 return error; 415 error = copyout(&vc->vc_cmap_blue[index], cm->blue, count); 416 if (error) 417 return error; 418 419 return 0; 420} 421 422int 423vgafb_putcmap(struct vga_config *vc, struct wsdisplay_cmap *cm) 424{ 425 u_int index = cm->index; 426 u_int count = cm->count; 427 int error; 428 u_int8_t *r, *g, *b; 429 430 if (index >= 256 || count > 256 - index) 431 return EINVAL; 432 433 if ((error = copyin(cm->red, &vc->vc_cmap_red[index], count)) != 0) 434 return (error); 435 if ((error = copyin(cm->green, &vc->vc_cmap_green[index], count)) != 0) 436 return (error); 437 if ((error = copyin(cm->blue, &vc->vc_cmap_blue[index], count)) != 0) 438 return (error); 439 440 r = &(vc->vc_cmap_red[index]); 441 g = &(vc->vc_cmap_green[index]); 442 b = &(vc->vc_cmap_blue[index]); 443 444 of_setcolors(index, count, r, g, b); 445 446 return 0; 447} 448 449void 450vgafb_burn(void *v, u_int on, u_int flags) 451{ 452 struct vga_config *vc = v; 453 454 if (vc->vc_backlight_on != on) { 455 of_setbacklight(on == WSDISPLAYIO_VIDEO_ON); 456 vc->vc_backlight_on = on; 457 } 458} 459 460int 461vgafb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 462 int *curxp, int *curyp, long *attrp) 463{ 464 struct vga_config *vc = v; 465 struct rasops_info *ri = &vc->ri; 466 467 return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp); 468} 469 470void 471vgafb_free_screen(void *v, void *cookie) 472{ 473 struct vga_config *vc = v; 474 struct rasops_info *ri = &vc->ri; 475 476 return rasops_free_screen(ri, cookie); 477} 478 479int 480vgafb_show_screen(void *v, void *cookie, int waitok, 481 void (*cb)(void *, int, int), void *cbarg) 482{ 483 struct vga_config *vc = v; 484 struct rasops_info *ri = &vc->ri; 485 486 if (cookie == ri->ri_active) 487 return (0); 488 489 return rasops_show_screen(ri, cookie, waitok, cb, cbarg); 490} 491 492int 493vgafb_mapregs(struct vga_config *vc, struct pci_attach_args *pa) 494{ 495 bus_addr_t ba; 496 bus_size_t bs; 497 int hasio = 0, hasmem = 0, hasmmio = 0; 498 uint32_t i, cf; 499 int rv; 500 501 for (i = PCI_MAPREG_START; i <= PCI_MAPREG_PPB_END; i += 4) { 502 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, i); 503 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) { 504 if (hasio) 505 continue; 506 rv = pci_io_find(pa->pa_pc, pa->pa_tag, i, 507 &vc->iobase, &vc->iosize); 508 if (rv != 0) { 509#if notyet 510 if (rv != ENOENT) 511 printf("%s: failed to find io at 0x%x\n", 512 DEVNAME(sc), i); 513#endif 514 continue; 515 } 516 hasio = 1; 517 } else { 518 /* Memory mapping... frame memory or mmio? */ 519 rv = pci_mem_find(pa->pa_pc, pa->pa_tag, i, 520 &ba, &bs, NULL); 521 if (rv != 0) { 522#if notyet 523 if (rv != ENOENT) 524 printf("%s: failed to find mem at 0x%x\n", 525 DEVNAME(sc), i); 526#endif 527 continue; 528 } 529 530 if (bs == 0 /* || ba == 0 */) { 531 /* ignore this entry */ 532 } else if (hasmem == 0) { 533 /* 534 * first memory slot found goes into memory, 535 * this is for the case of no mmio 536 */ 537 vc->membase = ba; 538 vc->memsize = bs; 539 hasmem = 1; 540 } else { 541 /* 542 * Oh, we have a second `memory' 543 * region, is this region the vga memory 544 * or mmio, we guess that memory is 545 * the larger of the two. 546 */ 547 if (vc->memsize >= bs) { 548 /* this is the mmio */ 549 vc->mmiobase = ba; 550 vc->mmiosize = bs; 551 hasmmio = 1; 552 } else { 553 /* this is the memory */ 554 vc->mmiobase = vc->membase; 555 vc->mmiosize = vc->memsize; 556 vc->membase = ba; 557 vc->memsize = bs; 558 } 559 } 560 } 561 } 562 563 /* failure to initialize io ports should not prevent attachment */ 564 if (hasmem == 0) { 565 printf(": could not find memory space\n"); 566 return (1); 567 } 568 569 if (hasmmio) 570 printf (", mmio"); 571 printf("\n"); 572 573 return (0); 574} 575