1 /* $NetBSD: ofb.c,v 1.26 2002/03/17 19:40:44 atatat Exp $ */ 2 3 /* 4 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/buf.h> 32 #include <sys/conf.h> 33 #include <sys/device.h> 34 #include <sys/ioctl.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/systm.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #include <dev/pci/pcidevs.h> 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 45 #include <dev/wscons/wsconsio.h> 46 #include <dev/wscons/wsdisplayvar.h> 47 #include <dev/rasops/rasops.h> 48 49 #include <dev/ofw/openfirm.h> 50 #include <dev/ofw/ofw_pci.h> 51 52 #include <machine/bat.h> 53 #include <machine/bus.h> 54 #include <machine/autoconf.h> 55 #include <machine/grfioctl.h> 56 57 #include <macppc/dev/ofbvar.h> 58 59 #if OFB_ENABLE_CACHE 60 int ofb_enable_cache = 1; 61 #else 62 int ofb_enable_cache = 0; 63 #endif 64 65 int ofbmatch __P((struct device *, struct cfdata *, void *)); 66 void ofbattach __P((struct device *, struct device *, void *)); 67 int ofbprint __P((void *, const char *)); 68 69 struct cfattach ofb_ca = { 70 sizeof(struct ofb_softc), ofbmatch, ofbattach, 71 }; 72 73 struct ofb_devconfig ofb_console_dc; 74 75 struct wsscreen_descr ofb_stdscreen = { 76 "std", 77 0, 0, /* will be filled in -- XXX shouldn't, it's global */ 78 0, 79 0, 0, 80 WSSCREEN_REVERSE 81 }; 82 83 const struct wsscreen_descr *_ofb_scrlist[] = { 84 &ofb_stdscreen, 85 /* XXX other formats, graphics screen? */ 86 }; 87 88 struct wsscreen_list ofb_screenlist = { 89 sizeof(_ofb_scrlist) / sizeof(struct wsscreen_descr *), _ofb_scrlist 90 }; 91 92 static int ofb_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 93 static paddr_t ofb_mmap __P((void *, off_t, int)); 94 static int ofb_alloc_screen __P((void *, const struct wsscreen_descr *, 95 void **, int *, int *, long *)); 96 static void ofb_free_screen __P((void *, void *)); 97 static int ofb_show_screen __P((void *, void *, int, 98 void (*) (void *, int, int), void *)); 99 static int copy_rom_font __P((void)); 100 101 struct wsdisplay_accessops ofb_accessops = { 102 ofb_ioctl, 103 ofb_mmap, 104 ofb_alloc_screen, 105 ofb_free_screen, 106 ofb_show_screen, 107 0 /* load_font */ 108 }; 109 110 static struct wsdisplay_font openfirm6x11; 111 112 static void ofb_common_init __P((int, struct ofb_devconfig *)); 113 static int ofb_getcmap __P((struct ofb_softc *, struct wsdisplay_cmap *)); 114 static int ofb_putcmap __P((struct ofb_softc *, struct wsdisplay_cmap *)); 115 116 int 117 ofbmatch(parent, match, aux) 118 struct device *parent; 119 struct cfdata *match; 120 void *aux; 121 { 122 struct pci_attach_args *pa = aux; 123 124 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && 125 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_CONTROL) 126 return 1; 127 128 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY) 129 return 1; 130 131 return 0; 132 } 133 134 void 135 ofbattach(parent, self, aux) 136 struct device *parent, *self; 137 void *aux; 138 { 139 struct ofb_softc *sc = (struct ofb_softc *)self; 140 struct pci_attach_args *pa = aux; 141 struct wsemuldisplaydev_attach_args a; 142 int console, node; 143 struct ofb_devconfig *dc; 144 char devinfo[256]; 145 146 console = ofb_is_console(); 147 148 if (console) { 149 dc = &ofb_console_dc; 150 node = dc->dc_node; 151 sc->nscreens = 1; 152 } else { 153 int i, len, screenbytes; 154 155 dc = malloc(sizeof(struct ofb_devconfig), M_DEVBUF, M_WAITOK); 156 memset(dc, 0, sizeof(struct ofb_devconfig)); 157 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 158 if (node == 0) { 159 printf(": ofdev not found\n"); 160 return; 161 } 162 163 /* XXX There are two child screens on PowerBook. */ 164 memset(devinfo, 0, sizeof(devinfo)); 165 OF_getprop(node, "device_type", devinfo, sizeof(devinfo)); 166 len = strlen(devinfo); 167 if (strcmp(devinfo + len - 7, "-parent") == 0) 168 node = OF_child(node); 169 170 ofb_common_init(node, dc); 171 172 screenbytes = dc->dc_ri.ri_stride * dc->dc_ri.ri_height; 173 for (i = 0; i < screenbytes; i += sizeof(u_int32_t)) 174 *(u_int32_t *)(dc->dc_paddr + i) = 0xffffffff; 175 } 176 sc->sc_dc = dc; 177 178 /* XXX */ 179 if (OF_getprop(node, "assigned-addresses", sc->sc_addrs, 180 sizeof(sc->sc_addrs)) == -1) { 181 node = OF_parent(node); 182 OF_getprop(node, "assigned-addresses", sc->sc_addrs, 183 sizeof(sc->sc_addrs)); 184 } 185 186 if (dc->dc_paddr == 0) { 187 printf(": cannot map framebuffer\n"); 188 return; 189 } 190 191 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); 192 printf(": %s\n", devinfo); 193 printf("%s: %d x %d, %dbpp\n", self->dv_xname, 194 dc->dc_ri.ri_width, dc->dc_ri.ri_height, dc->dc_ri.ri_depth); 195 196 sc->sc_cmap_red[0] = sc->sc_cmap_green[0] = sc->sc_cmap_blue[0] = 0; 197 sc->sc_cmap_red[15] = sc->sc_cmap_red[255] = 0xff; 198 sc->sc_cmap_green[15] = sc->sc_cmap_green[255] = 0xff; 199 sc->sc_cmap_blue[15] = sc->sc_cmap_blue[255] = 0xff; 200 201 a.console = console; 202 a.scrdata = &ofb_screenlist; 203 a.accessops = &ofb_accessops; 204 a.accesscookie = sc; 205 206 config_found(self, &a, wsemuldisplaydevprint); 207 } 208 209 void 210 ofb_common_init(node, dc) 211 int node; 212 struct ofb_devconfig *dc; 213 { 214 struct rasops_info *ri = &dc->dc_ri; 215 int32_t addr, width, height, linebytes, depth; 216 217 dc->dc_node = node; 218 if (dc->dc_ih == 0) { 219 char name[64]; 220 221 memset(name, 0, 64); 222 OF_package_to_path(node, name, sizeof(name)); 223 dc->dc_ih = OF_open(name); 224 } 225 226 /* XXX /chaos/control doesn't have "width", "height", ... */ 227 width = height = -1; 228 if (OF_getprop(node, "width", &width, 4) != 4) 229 OF_interpret("screen-width", 1, &width); 230 if (OF_getprop(node, "height", &height, 4) != 4) 231 OF_interpret("screen-height", 1, &height); 232 if (OF_getprop(node, "linebytes", &linebytes, 4) != 4) 233 linebytes = width; /* XXX */ 234 if (OF_getprop(node, "depth", &depth, 4) != 4) 235 depth = 8; /* XXX */ 236 if (OF_getprop(node, "address", &addr, 4) != 4) 237 OF_interpret("frame-buffer-adr", 1, &addr); 238 239 if (width == -1 || height == -1 || addr == 0 || addr == -1) 240 return; 241 242 dc->dc_paddr = addr; /* PA of the frame buffer */ 243 244 /* Make sure 0/0/0 is black and 255/255/255 is white. */ 245 OF_call_method_1("color!", dc->dc_ih, 4, 0, 0, 0, 0); 246 OF_call_method_1("color!", dc->dc_ih, 4, 255, 255, 255, 255); 247 248 /* Enable write-through cache. */ 249 if (ofb_enable_cache && battable[0xc].batu == 0) { 250 battable[0xc].batl = BATL(addr & 0xf0000000, BAT_W, BAT_PP_RW); 251 battable[0xc].batu = BATL(0xc0000000, BAT_BL_256M, BAT_Vs); 252 addr &= 0x0fffffff; 253 addr |= 0xc0000000; 254 } 255 256 /* initialize rasops */ 257 ri->ri_width = width; 258 ri->ri_height = height; 259 ri->ri_depth = depth; 260 ri->ri_stride = linebytes; 261 ri->ri_bits = (char *)addr; 262 ri->ri_flg = RI_FORCEMONO | RI_FULLCLEAR | RI_CENTER; 263 264 /* If screen is smaller than 1024x768, use small font. */ 265 if ((width < 1024 || height < 768) && copy_rom_font() == 0) { 266 int cols, rows; 267 268 OF_interpret("#lines", 1, &rows); 269 OF_interpret("#columns", 1, &cols); 270 271 ri->ri_font = &openfirm6x11; 272 ri->ri_wsfcookie = -1; /* not using wsfont */ 273 rasops_init(ri, rows, cols); 274 275 ri->ri_xorigin = 2; 276 ri->ri_yorigin = 3; 277 ri->ri_bits = (char *)addr + ri->ri_xorigin + 278 ri->ri_stride * ri->ri_yorigin; 279 } else { 280 rasops_init(ri, 24, 80); 281 rasops_reconfig(ri, (height - 2) / ri->ri_font->fontheight, 282 ((width - 2) / ri->ri_font->fontwidth) & ~7); 283 } 284 285 /* black on white */ 286 ri->ri_devcmap[0] = 0xffffffff; /* bg */ 287 ri->ri_devcmap[1] = 0; /* fg */ 288 289 ofb_stdscreen.nrows = ri->ri_rows; 290 ofb_stdscreen.ncols = ri->ri_cols; 291 ofb_stdscreen.textops = &ri->ri_ops; 292 ofb_stdscreen.capabilities = ri->ri_caps; 293 } 294 295 int 296 ofb_is_console() 297 { 298 int chosen, stdout, node; 299 char type[16]; 300 301 chosen = OF_finddevice("/chosen"); 302 OF_getprop(chosen, "stdout", &stdout, 4); 303 node = OF_instance_to_package(stdout); 304 OF_getprop(node, "device_type", type, sizeof(type)); 305 if (strcmp(type, "display") == 0) 306 return 1; 307 else 308 return 0; 309 } 310 311 int 312 ofb_ioctl(v, cmd, data, flag, p) 313 void *v; 314 u_long cmd; 315 caddr_t data; 316 int flag; 317 struct proc *p; 318 { 319 struct ofb_softc *sc = v; 320 struct ofb_devconfig *dc = sc->sc_dc; 321 struct wsdisplay_fbinfo *wdf; 322 struct grfinfo *gm; 323 324 switch (cmd) { 325 case WSDISPLAYIO_GTYPE: 326 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; /* XXX ? */ 327 return 0; 328 329 case WSDISPLAYIO_GINFO: 330 wdf = (void *)data; 331 wdf->height = dc->dc_ri.ri_height; 332 wdf->width = dc->dc_ri.ri_width; 333 wdf->depth = dc->dc_ri.ri_depth; 334 wdf->cmsize = 256; 335 return 0; 336 337 case WSDISPLAYIO_GETCMAP: 338 return ofb_getcmap(sc, (struct wsdisplay_cmap *)data); 339 340 case WSDISPLAYIO_PUTCMAP: 341 return ofb_putcmap(sc, (struct wsdisplay_cmap *)data); 342 343 /* XXX There are no way to know framebuffer pa from a user program. */ 344 case GRFIOCGINFO: 345 gm = (void *)data; 346 memset(gm, 0, sizeof(struct grfinfo)); 347 gm->gd_fbaddr = (caddr_t)dc->dc_paddr; 348 gm->gd_fbrowbytes = dc->dc_ri.ri_stride; 349 return 0; 350 } 351 return EPASSTHROUGH; 352 } 353 354 paddr_t 355 ofb_mmap(v, offset, prot) 356 void *v; 357 off_t offset; 358 int prot; 359 { 360 struct ofb_softc *sc = v; 361 struct ofb_devconfig *dc = sc->sc_dc; 362 struct rasops_info *ri = &dc->dc_ri; 363 u_int32_t *ap = sc->sc_addrs; 364 paddr_t pa; 365 int i; 366 367 if (offset >=0 && offset < (ri->ri_stride * ri->ri_height)) 368 return dc->dc_paddr + offset; 369 370 pa = offset; 371 for (i = 0; i < 6; i++) { 372 switch (ap[0] & OFW_PCI_PHYS_HI_SPACEMASK) { 373 case OFW_PCI_PHYS_HI_SPACE_MEM32: 374 if (pa >= ap[2] && pa < ap[2] + ap[4]) 375 return pa; 376 /* XXX I/O space? */ 377 } 378 ap += 5; 379 } 380 381 return -1; 382 } 383 384 int 385 ofb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 386 void *v; 387 const struct wsscreen_descr *type; 388 void **cookiep; 389 int *curxp, *curyp; 390 long *attrp; 391 { 392 struct ofb_softc *sc = v; 393 struct rasops_info *ri = &sc->sc_dc->dc_ri; 394 long defattr; 395 396 if (sc->nscreens > 0) 397 return (ENOMEM); 398 399 *cookiep = ri; /* one and only for now */ 400 *curxp = 0; 401 *curyp = 0; 402 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr); 403 *attrp = defattr; 404 sc->nscreens++; 405 return 0; 406 } 407 408 void 409 ofb_free_screen(v, cookie) 410 void *v; 411 void *cookie; 412 { 413 struct ofb_softc *sc = v; 414 415 if (sc->sc_dc == &ofb_console_dc) 416 panic("ofb_free_screen: console"); 417 418 sc->nscreens--; 419 } 420 421 int 422 ofb_show_screen(v, cookie, waitok, cb, cbarg) 423 void *v; 424 void *cookie; 425 int waitok; 426 void (*cb) __P((void *, int, int)); 427 void *cbarg; 428 { 429 430 return (0); 431 } 432 433 int 434 ofb_cnattach() 435 { 436 struct ofb_devconfig *dc = &ofb_console_dc; 437 struct rasops_info *ri = &dc->dc_ri; 438 long defattr; 439 int crow = 0; 440 int chosen, stdout, node; 441 442 chosen = OF_finddevice("/chosen"); 443 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 444 node = OF_instance_to_package(stdout); 445 dc->dc_ih = stdout; 446 447 /* get current cursor position */ 448 OF_interpret("line#", 1, &crow); 449 450 /* move (rom monitor) cursor to the lowest line - 1 */ 451 OF_interpret("#lines 2 - to line#", 0); 452 453 ofb_common_init(node, dc); 454 455 if (ri->ri_width >= 1024 && ri->ri_height >= 768) { 456 int i, screenbytes = ri->ri_stride * ri->ri_height; 457 458 for (i = 0; i < screenbytes; i += sizeof(u_int32_t)) 459 *(u_int32_t *)(dc->dc_paddr + i) = 0xffffffff; 460 crow = 0; 461 } 462 463 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr); 464 wsdisplay_cnattach(&ofb_stdscreen, ri, 0, crow, defattr); 465 466 return 0; 467 } 468 469 int 470 copy_rom_font() 471 { 472 u_char *romfont; 473 int char_width, char_height; 474 int chosen, mmu, m, e; 475 476 /* Get ROM FONT address. */ 477 OF_interpret("font-adr", 1, &romfont); 478 if (romfont == NULL) 479 return -1; 480 481 chosen = OF_finddevice("/chosen"); 482 OF_getprop(chosen, "mmu", &mmu, 4); 483 484 /* 485 * Convert to physcal address. We cannot access to Open Firmware's 486 * virtual address space. 487 */ 488 OF_call_method("translate", mmu, 1, 3, romfont, &romfont, &m, &e); 489 490 /* Get character size */ 491 OF_interpret("char-width", 1, &char_width); 492 OF_interpret("char-height", 1, &char_height); 493 494 openfirm6x11.name = "Open Firmware"; 495 openfirm6x11.firstchar = 32; 496 openfirm6x11.numchars = 96; 497 openfirm6x11.encoding = WSDISPLAY_FONTENC_ISO; 498 openfirm6x11.fontwidth = char_width; 499 openfirm6x11.fontheight = char_height; 500 openfirm6x11.stride = 1; 501 openfirm6x11.bitorder = WSDISPLAY_FONTORDER_L2R; 502 openfirm6x11.byteorder = WSDISPLAY_FONTORDER_L2R; 503 openfirm6x11.data = romfont; 504 505 return 0; 506 } 507 508 int 509 ofb_getcmap(sc, cm) 510 struct ofb_softc *sc; 511 struct wsdisplay_cmap *cm; 512 { 513 u_int index = cm->index; 514 u_int count = cm->count; 515 int error; 516 517 if (index >= 256 || count > 256 || index + count > 256) 518 return EINVAL; 519 520 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 521 if (error) 522 return error; 523 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 524 if (error) 525 return error; 526 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 527 if (error) 528 return error; 529 530 return 0; 531 } 532 533 int 534 ofb_putcmap(sc, cm) 535 struct ofb_softc *sc; 536 struct wsdisplay_cmap *cm; 537 { 538 struct ofb_devconfig *dc = sc->sc_dc; 539 u_int index = cm->index; 540 u_int count = cm->count; 541 int i; 542 u_char *r, *g, *b; 543 544 if (cm->index >= 256 || cm->count > 256 || 545 (cm->index + cm->count) > 256) 546 return EINVAL; 547 if (!uvm_useracc(cm->red, cm->count, B_READ) || 548 !uvm_useracc(cm->green, cm->count, B_READ) || 549 !uvm_useracc(cm->blue, cm->count, B_READ)) 550 return EFAULT; 551 copyin(cm->red, &sc->sc_cmap_red[index], count); 552 copyin(cm->green, &sc->sc_cmap_green[index], count); 553 copyin(cm->blue, &sc->sc_cmap_blue[index], count); 554 555 r = &sc->sc_cmap_red[index]; 556 g = &sc->sc_cmap_green[index]; 557 b = &sc->sc_cmap_blue[index]; 558 559 for (i = 0; i < count; i++) { 560 OF_call_method_1("color!", dc->dc_ih, 4, *r, *g, *b, index); 561 r++, g++, b++, index++; 562 } 563 564 return 0; 565 } 566