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