1 /* $NetBSD: agten.c,v 1.31 2013/07/30 19:24:26 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: agten.c,v 1.31 2013/07/30 19:24:26 macallan Exp $"); 31 32 /* 33 * a driver for the Fujitsu AG-10e SBus framebuffer 34 * 35 * this thing is Frankenstein's Monster among graphics boards. 36 * it contains three graphics chips: 37 * a GLint 300SX - 24bit stuff, double-buffered 38 * an Imagine 128 which provides an 8bit overlay 39 * a Weitek P9100 which provides WIDs 40 * so here we need to mess only with the P9100 and the I128 - for X we just 41 * hide the overlay and let the Xserver mess with the GLint 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/device.h> 48 #include <sys/proc.h> 49 #include <sys/mutex.h> 50 #include <sys/ioctl.h> 51 #include <sys/kernel.h> 52 #include <sys/systm.h> 53 #include <sys/conf.h> 54 55 #include <dev/sun/fbio.h> 56 #include <dev/sun/fbvar.h> 57 #include <dev/sun/btreg.h> 58 #include <dev/sun/btvar.h> 59 60 #include <sys/bus.h> 61 #include <machine/autoconf.h> 62 63 #include <dev/sbus/sbusvar.h> 64 65 #include <dev/wscons/wsconsio.h> 66 #include <dev/wscons/wsdisplayvar.h> 67 #include <dev/rasops/rasops.h> 68 #include <dev/wsfont/wsfont.h> 69 70 #include <dev/wscons/wsdisplay_vconsvar.h> 71 #include <dev/wscons/wsdisplay_glyphcachevar.h> 72 73 #include <dev/sbus/p9100reg.h> 74 #include <dev/ic/ibm561reg.h> 75 #include <dev/ic/i128reg.h> 76 #include <dev/ic/i128var.h> 77 78 #include "opt_agten.h" 79 #include "ioconf.h" 80 81 static int agten_match(device_t, cfdata_t, void *); 82 static void agten_attach(device_t, device_t, void *); 83 84 static int agten_ioctl(void *, void *, u_long, void *, int, struct lwp *); 85 static paddr_t agten_mmap(void *, void *, off_t, int); 86 static void agten_init_screen(void *, struct vcons_screen *, int, long *); 87 88 struct agten_softc { 89 device_t sc_dev; /* base device */ 90 struct fbdevice sc_fb; /* frame buffer device */ 91 92 struct vcons_screen sc_console_screen; 93 struct wsscreen_descr sc_defaultscreen_descr; 94 const struct wsscreen_descr *sc_screens[1]; 95 struct wsscreen_list sc_screenlist; 96 97 bus_space_tag_t sc_bustag; 98 99 bus_space_handle_t sc_i128_fbh; 100 bus_size_t sc_i128_fbsz; 101 bus_space_handle_t sc_i128_regh; 102 bus_space_handle_t sc_p9100_regh; 103 bus_addr_t sc_glint_fb; 104 bus_addr_t sc_glint_regs; 105 uint32_t sc_glint_fbsz; 106 107 uint32_t sc_width; 108 uint32_t sc_height; /* panel width / height */ 109 uint32_t sc_stride; 110 uint32_t sc_depth; 111 112 int sc_cursor_x; 113 int sc_cursor_y; 114 int sc_video; /* video output enabled */ 115 116 /* some /dev/fb* stuff */ 117 int sc_fb_is_open; 118 119 union bt_cmap sc_cmap; /* Brooktree color map */ 120 121 int sc_mode; 122 uint32_t sc_bg; 123 124 void (*sc_putchar)(void *, int, int, u_int, long); 125 126 struct vcons_data vd; 127 glyphcache sc_gc; 128 }; 129 130 CFATTACH_DECL_NEW(agten, sizeof(struct agten_softc), 131 agten_match, agten_attach, NULL, NULL); 132 133 134 static int agten_putcmap(struct agten_softc *, struct wsdisplay_cmap *); 135 static int agten_getcmap(struct agten_softc *, struct wsdisplay_cmap *); 136 static int agten_putpalreg(struct agten_softc *, uint8_t, uint8_t, 137 uint8_t, uint8_t); 138 static void agten_init(struct agten_softc *); 139 static void agten_init_cmap(struct agten_softc *, struct rasops_info *); 140 static void agten_gfx(struct agten_softc *); 141 static void agten_set_video(struct agten_softc *, int); 142 static int agten_get_video(struct agten_softc *); 143 144 static void agten_bitblt(void *, int, int, int, int, int, int, int); 145 static void agten_rectfill(void *, int, int, int, int, long); 146 147 static void agten_putchar(void *, int, int, u_int, long); 148 static void agten_cursor(void *, int, int, int); 149 static void agten_copycols(void *, int, int, int, int); 150 static void agten_erasecols(void *, int, int, int, long); 151 static void agten_copyrows(void *, int, int, int); 152 static void agten_eraserows(void *, int, int, long); 153 154 static void agten_move_cursor(struct agten_softc *, int, int); 155 static int agten_do_cursor(struct agten_softc *sc, 156 struct wsdisplay_cursor *); 157 static int agten_do_sun_cursor(struct agten_softc *sc, 158 struct fbcursor *); 159 160 static uint16_t util_interleave(uint8_t, uint8_t); 161 static uint16_t util_interleave_lin(uint8_t, uint8_t); 162 163 extern const u_char rasops_cmap[768]; 164 165 struct wsdisplay_accessops agten_accessops = { 166 agten_ioctl, 167 agten_mmap, 168 NULL, /* alloc_screen */ 169 NULL, /* free_screen */ 170 NULL, /* show_screen */ 171 NULL, /* load_font */ 172 NULL, /* pollc */ 173 NULL /* scroll */ 174 }; 175 176 /* /dev/fb* stuff */ 177 178 static int agten_fb_open(dev_t, int, int, struct lwp *); 179 static int agten_fb_close(dev_t, int, int, struct lwp *); 180 static int agten_fb_ioctl(dev_t, u_long, void *, int, struct lwp *); 181 static paddr_t agten_fb_mmap(dev_t, off_t, int); 182 static void agten_fb_unblank(device_t); 183 184 static struct fbdriver agtenfbdriver = { 185 agten_fb_unblank, agten_fb_open, agten_fb_close, agten_fb_ioctl, 186 nopoll, agten_fb_mmap, nokqfilter 187 }; 188 189 static inline void 190 agten_write_dac(struct agten_softc *sc, int reg, uint8_t val) 191 { 192 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, 193 0x200 + (reg << 2), (uint32_t)val << 16); 194 } 195 196 static inline void 197 agten_write_idx(struct agten_softc *sc, int offset) 198 { 199 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, 200 0x200 + (IBM561_ADDR_LOW << 2), (offset & 0xff) << 16); 201 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, 202 0x200 + (IBM561_ADDR_HIGH << 2), ((offset >> 8) & 0xff) << 16); 203 } 204 205 static inline void 206 agten_write_dac_10(struct agten_softc *sc, int reg, uint16_t val) 207 { 208 agten_write_dac(sc, reg, (val >> 2) & 0xff); 209 agten_write_dac(sc, reg, (val & 0x3) << 6); 210 } 211 212 static int 213 agten_match(device_t dev, cfdata_t cf, void *aux) 214 { 215 struct sbus_attach_args *sa = aux; 216 217 if (strcmp("PFU,aga", sa->sa_name) == 0) 218 return 100; 219 return 0; 220 } 221 222 static void 223 agten_attach(device_t parent, device_t dev, void *aux) 224 { 225 struct agten_softc *sc = device_private(dev); 226 struct sbus_attach_args *sa = aux; 227 struct fbdevice *fb = &sc->sc_fb; 228 struct wsemuldisplaydev_attach_args aa; 229 struct rasops_info *ri; 230 long defattr; 231 uint32_t reg; 232 int node = sa->sa_node; 233 int console; 234 235 sc->sc_dev = dev; 236 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 237 "default", 238 0, 0, 239 NULL, 240 8, 16, 241 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 242 NULL 243 }; 244 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 245 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 246 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 247 sc->sc_fb_is_open = 0; 248 sc->sc_video = -1; 249 sc->sc_bustag = sa->sa_bustag; 250 sc->sc_putchar = NULL; 251 252 sc->sc_width = prom_getpropint(node, "ffb_width", 1152); 253 sc->sc_height = prom_getpropint(node, "ffb_height", 900); 254 sc->sc_depth = prom_getpropint(node, "ffb_depth", 8); 255 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); 256 257 reg = prom_getpropint(node, "i128_fb_physaddr", -1); 258 sc->sc_i128_fbsz = prom_getpropint(node, "i128_fb_size", -1); 259 if (sbus_bus_map(sc->sc_bustag, 260 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg, 261 round_page(sc->sc_stride * sc->sc_height), 262 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 263 &sc->sc_i128_fbh) != 0) { 264 265 aprint_error_dev(dev, "unable to map the framebuffer\n"); 266 return; 267 } 268 fb->fb_pixels = bus_space_vaddr(sc->sc_bustag, sc->sc_i128_fbh); 269 270 reg = prom_getpropint(node, "i128_reg_physaddr", -1); 271 if (sbus_bus_map(sc->sc_bustag, 272 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg, 273 0x10000, 0, &sc->sc_i128_regh) != 0) { 274 275 aprint_error_dev(dev, "unable to map I128 registers\n"); 276 return; 277 } 278 279 reg = prom_getpropint(node, "p9100_reg_physaddr", -1); 280 if (sbus_bus_map(sc->sc_bustag, 281 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg, 282 0x8000, 0, &sc->sc_p9100_regh) != 0) { 283 284 aprint_error_dev(dev, "unable to map P9100 registers\n"); 285 return; 286 } 287 288 reg = prom_getpropint(node, "glint_fb0_physaddr", -1); 289 sc->sc_glint_fb = sbus_bus_addr(sc->sc_bustag, 290 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg); 291 sc->sc_glint_fbsz = prom_getpropint(node, "glint_lb_size", -1); 292 reg = prom_getpropint(node, "glint_reg_physaddr", -1); 293 sc->sc_glint_regs = sbus_bus_addr(sc->sc_bustag, 294 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg); 295 296 #if 0 297 bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO, 298 agten_intr, sc); 299 #endif 300 301 printf(": %dx%d\n", sc->sc_width, sc->sc_height); 302 agten_init(sc); 303 304 console = fb_is_console(node); 305 306 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 307 &agten_accessops); 308 sc->vd.init_screen = agten_init_screen; 309 310 ri = &sc->sc_console_screen.scr_ri; 311 312 sc->sc_gc.gc_bitblt = agten_bitblt; 313 sc->sc_gc.gc_rectfill = agten_rectfill; 314 sc->sc_gc.gc_blitcookie = sc; 315 sc->sc_gc.gc_rop = CR_COPY; 316 317 #if defined(AGTEN_DEBUG) 318 sc->sc_height -= 200; 319 #endif 320 321 if (console) { 322 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 323 &defattr); 324 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 325 326 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 327 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 328 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 329 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 330 glyphcache_init(&sc->sc_gc, 331 sc->sc_height + 5, 332 (0x400000 / sc->sc_stride) - sc->sc_height - 5, 333 sc->sc_width, 334 ri->ri_font->fontwidth, 335 ri->ri_font->fontheight, 336 defattr); 337 338 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 339 defattr); 340 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, 341 sc->sc_width, sc->sc_height, 342 ri->ri_devcmap[(defattr >> 16) & 0xff]); 343 vcons_replay_msgbuf(&sc->sc_console_screen); 344 } else { 345 /* 346 * since we're not the console we can postpone the rest 347 * until someone actually allocates a screen for us 348 */ 349 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 350 /* do some minimal setup to avoid weirdnesses later */ 351 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 352 &defattr); 353 } else 354 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 355 356 glyphcache_init(&sc->sc_gc, 357 sc->sc_height + 5, 358 (0x400000 / sc->sc_stride) - sc->sc_height - 5, 359 sc->sc_width, 360 ri->ri_font->fontwidth, 361 ri->ri_font->fontheight, 362 defattr); 363 } 364 365 /* Initialize the default color map. */ 366 agten_init_cmap(sc, ri); 367 368 aa.console = console; 369 aa.scrdata = &sc->sc_screenlist; 370 aa.accessops = &agten_accessops; 371 aa.accesscookie = &sc->vd; 372 373 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 374 375 fb->fb_driver = &agtenfbdriver; 376 fb->fb_device = sc->sc_dev; 377 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK; 378 fb->fb_type.fb_type = FBTYPE_AG10E; 379 fb->fb_type.fb_cmsize = 256; /* doesn't matter, we're always 24bit */ 380 fb->fb_type.fb_size = sc->sc_glint_fbsz; 381 fb->fb_type.fb_width = sc->sc_width; 382 fb->fb_type.fb_height = sc->sc_height; 383 fb->fb_type.fb_depth = 32; 384 fb->fb_linebytes = sc->sc_stride << 2; 385 fb_attach(fb, console); 386 agten_set_video(sc, 1); /* make sure video's on */ 387 } 388 389 static int 390 agten_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 391 struct lwp *l) 392 { 393 struct vcons_data *vd = v; 394 struct agten_softc *sc = vd->cookie; 395 struct wsdisplay_fbinfo *wdf; 396 struct vcons_screen *ms = vd->active; 397 398 switch (cmd) { 399 400 case WSDISPLAYIO_GTYPE: 401 *(u_int *)data = WSDISPLAY_TYPE_AG10; 402 return 0; 403 404 case WSDISPLAYIO_GINFO: 405 if (ms == NULL) 406 return ENODEV; 407 wdf = (void *)data; 408 wdf->height = ms->scr_ri.ri_height; 409 wdf->width = ms->scr_ri.ri_width; 410 wdf->depth = 32; 411 wdf->cmsize = 256; 412 return 0; 413 414 case WSDISPLAYIO_GVIDEO: 415 *(int *)data = sc->sc_video; 416 return 0; 417 418 case WSDISPLAYIO_SVIDEO: 419 agten_set_video(sc, *(int *)data); 420 return 0; 421 422 case WSDISPLAYIO_GETCMAP: 423 return agten_getcmap(sc, 424 (struct wsdisplay_cmap *)data); 425 426 case WSDISPLAYIO_PUTCMAP: 427 return agten_putcmap(sc, 428 (struct wsdisplay_cmap *)data); 429 430 case WSDISPLAYIO_LINEBYTES: 431 *(u_int *)data = sc->sc_stride << 2; 432 return 0; 433 434 case WSDISPLAYIO_SMODE: 435 { 436 int new_mode = *(int*)data; 437 if (new_mode != sc->sc_mode) { 438 sc->sc_mode = new_mode; 439 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 440 agten_init(sc); 441 agten_init_cmap(sc, 442 &ms->scr_ri); 443 vcons_redraw_screen(ms); 444 } else { 445 agten_gfx(sc); 446 } 447 } 448 } 449 return 0; 450 451 case WSDISPLAYIO_GCURPOS: 452 { 453 struct wsdisplay_curpos *cp = (void *)data; 454 455 cp->x = sc->sc_cursor_x; 456 cp->y = sc->sc_cursor_y; 457 } 458 return 0; 459 460 case WSDISPLAYIO_SCURPOS: 461 { 462 struct wsdisplay_curpos *cp = (void *)data; 463 464 agten_move_cursor(sc, cp->x, cp->y); 465 } 466 return 0; 467 468 case WSDISPLAYIO_GCURMAX: 469 { 470 struct wsdisplay_curpos *cp = (void *)data; 471 472 cp->x = 64; 473 cp->y = 64; 474 } 475 return 0; 476 477 case WSDISPLAYIO_SCURSOR: 478 { 479 struct wsdisplay_cursor *cursor = (void *)data; 480 481 return agten_do_cursor(sc, cursor); 482 } 483 } 484 return EPASSTHROUGH; 485 } 486 487 static paddr_t 488 agten_mmap(void *v, void *vs, off_t offset, int prot) 489 { 490 struct vcons_data *vd = v; 491 struct agten_softc *sc = vd->cookie; 492 493 if (offset < sc->sc_glint_fbsz) 494 return bus_space_mmap(sc->sc_bustag, sc->sc_glint_fb, offset, 495 prot, BUS_SPACE_MAP_LINEAR); 496 return -1; 497 } 498 499 static void 500 agten_init_screen(void *cookie, struct vcons_screen *scr, 501 int existing, long *defattr) 502 { 503 struct agten_softc *sc = cookie; 504 struct rasops_info *ri = &scr->scr_ri; 505 506 ri->ri_depth = sc->sc_depth; 507 ri->ri_width = sc->sc_width; 508 ri->ri_height = sc->sc_height; 509 ri->ri_stride = sc->sc_stride; 510 ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_8BIT_IS_RGB | RI_ENABLE_ALPHA; 511 512 ri->ri_bits = (char *)sc->sc_fb.fb_pixels; 513 514 if (existing) { 515 ri->ri_flg |= RI_CLEAR; 516 } 517 518 rasops_init(ri, 0, 0); 519 sc->sc_putchar = ri->ri_ops.putchar; 520 521 ri->ri_caps = WSSCREEN_WSCOLORS; 522 523 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 524 sc->sc_width / ri->ri_font->fontwidth); 525 526 ri->ri_hw = scr; 527 ri->ri_ops.putchar = agten_putchar; 528 ri->ri_ops.cursor = agten_cursor; 529 ri->ri_ops.copyrows = agten_copyrows; 530 ri->ri_ops.eraserows = agten_eraserows; 531 ri->ri_ops.copycols = agten_copycols; 532 ri->ri_ops.erasecols = agten_erasecols; 533 534 } 535 536 static int 537 agten_putcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm) 538 { 539 u_int index = cm->index; 540 u_int count = cm->count; 541 int i, error; 542 u_char rbuf[256], gbuf[256], bbuf[256]; 543 u_char *r, *g, *b; 544 545 if (cm->index >= 256 || cm->count > 256 || 546 (cm->index + cm->count) > 256) 547 return EINVAL; 548 error = copyin(cm->red, &rbuf[index], count); 549 if (error) 550 return error; 551 error = copyin(cm->green, &gbuf[index], count); 552 if (error) 553 return error; 554 error = copyin(cm->blue, &bbuf[index], count); 555 if (error) 556 return error; 557 558 r = &rbuf[index]; 559 g = &gbuf[index]; 560 b = &bbuf[index]; 561 562 for (i = 0; i < count; i++) { 563 agten_putpalreg(sc, index, *r, *g, *b); 564 index++; 565 r++, g++, b++; 566 } 567 return 0; 568 } 569 570 static int 571 agten_getcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm) 572 { 573 u_int index = cm->index; 574 u_int count = cm->count; 575 int error, i; 576 uint8_t red[256], green[256], blue[256]; 577 578 if (index >= 255 || count > 256 || index + count > 256) 579 return EINVAL; 580 581 i = index; 582 while (i < (index + count)) { 583 red[i] = sc->sc_cmap.cm_map[i][0]; 584 green[i] = sc->sc_cmap.cm_map[i][1]; 585 blue[i] = sc->sc_cmap.cm_map[i][2]; 586 i++; 587 } 588 error = copyout(&red[index], cm->red, count); 589 if (error) 590 return error; 591 error = copyout(&green[index], cm->green, count); 592 if (error) 593 return error; 594 error = copyout(&blue[index], cm->blue, count); 595 if (error) 596 return error; 597 598 return 0; 599 } 600 601 static int 602 agten_putpalreg(struct agten_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 603 uint8_t b) 604 { 605 606 sc->sc_cmap.cm_map[idx][0] = r; 607 sc->sc_cmap.cm_map[idx][1] = g; 608 sc->sc_cmap.cm_map[idx][2] = b; 609 agten_write_idx(sc, IBM561_CMAP_TABLE + idx); 610 agten_write_dac(sc, IBM561_CMD_CMAP, r); 611 agten_write_dac(sc, IBM561_CMD_CMAP, g); 612 agten_write_dac(sc, IBM561_CMD_CMAP, b); 613 return 0; 614 } 615 616 static void 617 agten_init(struct agten_softc *sc) 618 { 619 int i; 620 uint32_t src, srcw; 621 volatile uint32_t junk; 622 623 /* then we set up a linear LUT for 24bit colour */ 624 agten_write_idx(sc, IBM561_CMAP_TABLE + 256); 625 for (i = 0; i < 256; i++) { 626 agten_write_dac(sc, IBM561_CMD_CMAP, i); 627 agten_write_dac(sc, IBM561_CMD_CMAP, i); 628 agten_write_dac(sc, IBM561_CMD_CMAP, i); 629 } 630 631 /* and the linear gamma maps */ 632 agten_write_idx(sc, IBM561_RED_GAMMA_TABLE); 633 for (i = 0; i < 0x3ff; i+= 4) 634 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i); 635 agten_write_idx(sc, IBM561_GREEN_GAMMA_TABLE); 636 for (i = 0; i < 0x3ff; i+= 4) 637 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i); 638 agten_write_idx(sc, IBM561_BLUE_GAMMA_TABLE); 639 for (i = 0; i < 0x3ff; i+= 4) 640 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i); 641 642 /* enable outputs, RGB mode */ 643 agten_write_idx(sc, IBM561_CONFIG_REG3); 644 agten_write_dac(sc, IBM561_CMD, CR3_SERIAL_CLK_CTRL | CR3_RGB); 645 646 /* MUX 4:1 basic, 8bit overlay, 8bit WIDs */ 647 agten_write_idx(sc, IBM561_CONFIG_REG1); 648 agten_write_dac(sc, IBM561_CMD, CR1_MODE_4_1_BASIC | CR1_OVL_8BPP | 649 CR1_WID_8); 650 651 /* use external clock, enable video output */ 652 agten_write_idx(sc, IBM561_CONFIG_REG2); 653 agten_write_dac(sc, IBM561_CMD, CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | 654 CR2_PIXEL_CLOCK_SELECT | CR2_ENABLE_RGB_OUTPUT); 655 656 /* now set up some window attributes */ 657 658 /* 659 * direct colour, 24 bit, transparency off, LUT from 0x100 660 * we need to use direct colour and a linear LUT because for some 661 * reason true color mode gives messed up colours 662 */ 663 agten_write_idx(sc, IBM561_FB_WINTYPE); 664 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x100 | FB_PIXEL_24BIT | 665 FB_MODE_DIRECT); 666 667 /* use gamma LUTs, no crosshair, 0 is transparent */ 668 agten_write_idx(sc, IBM561_AUXFB_WINTYPE); 669 agten_write_dac(sc, IBM561_CMD_FB_WAT, 0x0); 670 671 /* overlay is 8 bit, opaque */ 672 agten_write_idx(sc, IBM561_OL_WINTYPE); 673 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x00); 674 675 /* now we fill the WID fb with zeroes */ 676 src = 0; 677 srcw = sc->sc_width << 16 | sc->sc_height; 678 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, FOREGROUND_COLOR, 679 0x0); 680 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, BACKGROUND_COLOR, 681 0x0); 682 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RASTER_OP, ROP_PAT); 683 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, COORD_INDEX, 0); 684 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, src); 685 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, srcw); 686 junk = bus_space_read_4(sc->sc_bustag, sc->sc_p9100_regh, COMMAND_QUAD); 687 688 /* initialize the cursor registers */ 689 690 /* initialize the Imagine 128 */ 691 i128_init(sc->sc_bustag, sc->sc_i128_regh, sc->sc_stride, 8); 692 } 693 694 static void 695 agten_init_cmap(struct agten_softc *sc, struct rasops_info *ri) 696 { 697 int i, j; 698 uint8_t cmap[768]; 699 700 rasops_get_cmap(ri, cmap, 768); 701 j = 0; 702 for (i = 0; i < 256; i++) { 703 704 agten_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 705 j += 3; 706 } 707 } 708 709 static void 710 agten_gfx(struct agten_softc *sc) 711 { 712 /* enable overlay transparency on colour 0x00 */ 713 agten_write_idx(sc, IBM561_OL_WINTYPE); 714 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, OL_MODE_TRANSP_ENABLE); 715 716 /* then blit the overlay full of 0x00 */ 717 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, sc->sc_width, 718 sc->sc_height, 0); 719 720 /* ... so we can see the 24bit framebuffer */ 721 } 722 723 static void 724 agten_set_video(struct agten_softc *sc, int flag) 725 { 726 uint8_t reg = 727 CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | CR2_PIXEL_CLOCK_SELECT; 728 729 if (flag == sc->sc_video) 730 return; 731 732 agten_write_idx(sc, IBM561_CONFIG_REG2); 733 agten_write_dac(sc, IBM561_CMD, flag ? reg | CR2_ENABLE_RGB_OUTPUT : 734 reg); 735 736 sc->sc_video = flag; 737 } 738 739 static int 740 agten_get_video(struct agten_softc *sc) 741 { 742 743 return sc->sc_video; 744 } 745 746 static void 747 agten_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he, 748 int rop) 749 { 750 struct agten_softc *sc = cookie; 751 752 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, 753 xs, ys, xd, yd, wi, he, rop); 754 } 755 756 static void 757 agten_rectfill(void *cookie, int x, int y, int wi, int he, long fg) 758 { 759 struct agten_softc *sc = cookie; 760 struct vcons_screen *scr = sc->vd.active; 761 uint32_t col; 762 763 if (scr == NULL) 764 return; 765 col = scr->scr_ri.ri_devcmap[fg]; 766 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he, col); 767 } 768 769 static void 770 agten_putchar(void *cookie, int row, int col, u_int c, long attr) 771 { 772 struct rasops_info *ri = cookie; 773 struct wsdisplay_font *font = PICK_FONT(ri, c); 774 struct vcons_screen *scr = ri->ri_hw; 775 struct agten_softc *sc = scr->scr_cookie; 776 uint32_t fg, bg; 777 int x, y, wi, he, rv; 778 779 wi = font->fontwidth; 780 he = font->fontheight; 781 782 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 783 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 784 785 x = ri->ri_xorigin + col * wi; 786 y = ri->ri_yorigin + row * he; 787 788 if (c == 0x20) { 789 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he, 790 bg); 791 if (attr & 1) 792 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, 793 y + he - 2, wi, 1, fg); 794 return; 795 } 796 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 797 if (rv == GC_OK) 798 return; 799 i128_sync(sc->sc_bustag, sc->sc_i128_regh); 800 sc->sc_putchar(cookie, row, col, c, attr & ~1); 801 802 if (rv == GC_ADD) { 803 glyphcache_add(&sc->sc_gc, c, x, y); 804 } else { 805 if (attr & 1) 806 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, 807 y + he - 2, wi, 1, fg); 808 } 809 } 810 811 static void 812 agten_cursor(void *cookie, int on, int row, int col) 813 { 814 struct rasops_info *ri = cookie; 815 struct vcons_screen *scr = ri->ri_hw; 816 struct agten_softc *sc = scr->scr_cookie; 817 int x, y, wi,he; 818 819 wi = ri->ri_font->fontwidth; 820 he = ri->ri_font->fontheight; 821 822 if (ri->ri_flg & RI_CURSOR) { 823 x = ri->ri_ccol * wi + ri->ri_xorigin; 824 y = ri->ri_crow * he + ri->ri_yorigin; 825 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he, 826 CR_COPY_INV); 827 ri->ri_flg &= ~RI_CURSOR; 828 } 829 830 ri->ri_crow = row; 831 ri->ri_ccol = col; 832 833 if (on) 834 { 835 x = ri->ri_ccol * wi + ri->ri_xorigin; 836 y = ri->ri_crow * he + ri->ri_yorigin; 837 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he, 838 CR_COPY_INV); 839 ri->ri_flg |= RI_CURSOR; 840 } 841 } 842 843 static void 844 agten_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 845 { 846 struct rasops_info *ri = cookie; 847 struct vcons_screen *scr = ri->ri_hw; 848 struct agten_softc *sc = scr->scr_cookie; 849 int32_t xs, xd, y, width, height; 850 851 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 852 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 853 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 854 width = ri->ri_font->fontwidth * ncols; 855 height = ri->ri_font->fontheight; 856 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, xs, y, xd, y, width, 857 height, CR_COPY); 858 } 859 860 static void 861 agten_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 862 { 863 struct rasops_info *ri = cookie; 864 struct vcons_screen *scr = ri->ri_hw; 865 struct agten_softc *sc = scr->scr_cookie; 866 int32_t x, y, width, height, bg; 867 868 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 869 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 870 width = ri->ri_font->fontwidth * ncols; 871 height = ri->ri_font->fontheight; 872 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 873 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg); 874 } 875 876 static void 877 agten_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 878 { 879 struct rasops_info *ri = cookie; 880 struct vcons_screen *scr = ri->ri_hw; 881 struct agten_softc *sc = scr->scr_cookie; 882 int32_t x, ys, yd, width, height; 883 884 x = ri->ri_xorigin; 885 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 886 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 887 width = ri->ri_emuwidth; 888 height = ri->ri_font->fontheight * nrows; 889 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, ys, x, yd, width, 890 height, CR_COPY); 891 } 892 893 static void 894 agten_eraserows(void *cookie, int row, int nrows, long fillattr) 895 { 896 struct rasops_info *ri = cookie; 897 struct vcons_screen *scr = ri->ri_hw; 898 struct agten_softc *sc = scr->scr_cookie; 899 int32_t x, y, width, height, bg; 900 901 if ((row == 0) && (nrows == ri->ri_rows)) { 902 x = y = 0; 903 width = ri->ri_width; 904 height = ri->ri_height; 905 } else { 906 x = ri->ri_xorigin; 907 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 908 width = ri->ri_emuwidth; 909 height = ri->ri_font->fontheight * nrows; 910 } 911 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 912 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg); 913 } 914 915 static void 916 agten_move_cursor(struct agten_softc *sc, int x, int y) 917 { 918 919 sc->sc_cursor_x = x; 920 sc->sc_cursor_y = y; 921 agten_write_idx(sc, IBM561_CURSOR_X_REG); 922 agten_write_dac(sc, IBM561_CMD, x & 0xff); 923 agten_write_dac(sc, IBM561_CMD, (x >> 8) & 0xff); 924 agten_write_dac(sc, IBM561_CMD, y & 0xff); 925 agten_write_dac(sc, IBM561_CMD, (y >> 8) & 0xff); 926 } 927 928 static int 929 agten_do_cursor(struct agten_softc *sc, struct wsdisplay_cursor *cur) 930 { 931 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 932 933 agten_write_idx(sc, IBM561_CURS_CNTL_REG); 934 agten_write_dac(sc, IBM561_CMD, cur->enable ? 935 CURS_ENABLE : 0); 936 } 937 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 938 939 agten_write_idx(sc, IBM561_HOTSPOT_X_REG); 940 agten_write_dac(sc, IBM561_CMD, cur->hot.x); 941 agten_write_dac(sc, IBM561_CMD, cur->hot.y); 942 } 943 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 944 945 agten_move_cursor(sc, cur->pos.x, cur->pos.y); 946 } 947 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 948 int i; 949 950 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2); 951 for (i = 0; i < cur->cmap.count; i++) { 952 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]); 953 agten_write_dac(sc, IBM561_CMD_CMAP, 954 cur->cmap.green[i]); 955 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]); 956 } 957 } 958 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 959 int i; 960 uint16_t tmp; 961 962 agten_write_idx(sc, IBM561_CURSOR_BITMAP); 963 for (i = 0; i < 512; i++) { 964 tmp = util_interleave(cur->mask[i], cur->image[i]); 965 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff); 966 agten_write_dac(sc, IBM561_CMD, tmp & 0xff); 967 } 968 } 969 return 0; 970 } 971 972 static int 973 agten_do_sun_cursor(struct agten_softc *sc, struct fbcursor *cur) 974 { 975 if (cur->set & FB_CUR_SETCUR) { 976 977 agten_write_idx(sc, IBM561_CURS_CNTL_REG); 978 agten_write_dac(sc, IBM561_CMD, cur->enable ? 979 CURS_ENABLE : 0); 980 } 981 if (cur->set & FB_CUR_SETHOT) { 982 983 agten_write_idx(sc, IBM561_HOTSPOT_X_REG); 984 agten_write_dac(sc, IBM561_CMD, cur->hot.x); 985 agten_write_dac(sc, IBM561_CMD, cur->hot.y); 986 } 987 if (cur->set & FB_CUR_SETPOS) { 988 989 agten_move_cursor(sc, cur->pos.x, cur->pos.y); 990 } 991 if (cur->set & FB_CUR_SETCMAP) { 992 int i; 993 994 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2); 995 for (i = 0; i < cur->cmap.count; i++) { 996 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]); 997 agten_write_dac(sc, IBM561_CMD_CMAP, 998 cur->cmap.green[i]); 999 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]); 1000 } 1001 } 1002 if (cur->set & FB_CUR_SETSHAPE) { 1003 int i; 1004 uint16_t tmp; 1005 1006 agten_write_idx(sc, IBM561_CURSOR_BITMAP); 1007 for (i = 0; i < 512; i++) { 1008 tmp = util_interleave_lin(cur->mask[i], cur->image[i]); 1009 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff); 1010 agten_write_dac(sc, IBM561_CMD, tmp & 0xff); 1011 } 1012 } 1013 return 0; 1014 } 1015 1016 uint16_t 1017 util_interleave(uint8_t b1, uint8_t b2) 1018 { 1019 int i; 1020 uint16_t ret = 0; 1021 uint16_t mask = 0x8000; 1022 uint8_t mask8 = 0x01; 1023 1024 for (i = 0; i < 8; i++) { 1025 if (b1 & mask8) 1026 ret |= mask; 1027 mask = mask >> 1; 1028 if (b2 & mask8) 1029 ret |= mask; 1030 mask = mask >> 1; 1031 mask8 = mask8 << 1; 1032 } 1033 return ret; 1034 } 1035 1036 uint16_t 1037 util_interleave_lin(uint8_t b1, uint8_t b2) 1038 { 1039 int i; 1040 uint16_t ret = 0; 1041 uint16_t mask = 0x8000; 1042 uint8_t mask8 = 0x80; 1043 1044 for (i = 0; i < 8; i++) { 1045 if (b1 & mask8) 1046 ret |= mask; 1047 mask = mask >> 1; 1048 if (b2 & mask8) 1049 ret |= mask; 1050 mask = mask >> 1; 1051 mask8 = mask8 >> 1; 1052 } 1053 return ret; 1054 } 1055 1056 /* and now the /dev/fb* stuff */ 1057 static void 1058 agten_fb_unblank(device_t dev) 1059 { 1060 struct agten_softc *sc = device_private(dev); 1061 1062 agten_init(sc); 1063 agten_set_video(sc, 1); 1064 } 1065 1066 static int 1067 agten_fb_open(dev_t dev, int flags, int mode, struct lwp *l) 1068 { 1069 struct agten_softc *sc; 1070 1071 sc = device_lookup_private(&agten_cd, minor(dev)); 1072 if (sc == NULL) 1073 return (ENXIO); 1074 if (sc->sc_fb_is_open) 1075 return 0; 1076 1077 sc->sc_fb_is_open++; 1078 agten_gfx(sc); 1079 1080 return (0); 1081 } 1082 1083 static int 1084 agten_fb_close(dev_t dev, int flags, int mode, struct lwp *l) 1085 { 1086 struct agten_softc *sc; 1087 1088 sc = device_lookup_private(&agten_cd, minor(dev)); 1089 1090 sc->sc_fb_is_open--; 1091 if (sc->sc_fb_is_open < 0) 1092 sc->sc_fb_is_open = 0; 1093 1094 if (sc->sc_fb_is_open == 0) { 1095 agten_init(sc); 1096 vcons_redraw_screen(sc->vd.active); 1097 } 1098 1099 return (0); 1100 } 1101 1102 static int 1103 agten_fb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 1104 { 1105 struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev)); 1106 struct fbgattr *fba; 1107 int error; 1108 1109 switch (cmd) { 1110 1111 case FBIOGTYPE: 1112 *(struct fbtype *)data = sc->sc_fb.fb_type; 1113 break; 1114 1115 case FBIOGATTR: 1116 fba = (struct fbgattr *)data; 1117 fba->real_type = sc->sc_fb.fb_type.fb_type; 1118 fba->owner = 0; /* XXX ??? */ 1119 fba->fbtype = sc->sc_fb.fb_type; 1120 fba->sattr.flags = 0; 1121 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 1122 fba->sattr.dev_specific[0] = -1; 1123 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 1124 fba->emu_types[1] = -1; 1125 break; 1126 1127 case FBIOGETCMAP: 1128 #define p ((struct fbcmap *)data) 1129 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 1130 1131 case FBIOPUTCMAP: 1132 /* copy to software map */ 1133 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 1134 if (error) 1135 return (error); 1136 /* now blast them into the chip */ 1137 /* don't bother - we're 24bit */ 1138 #undef p 1139 break; 1140 1141 case FBIOGVIDEO: 1142 *(int *)data = agten_get_video(sc); 1143 break; 1144 1145 case FBIOSVIDEO: 1146 agten_set_video(sc, *(int *)data); 1147 break; 1148 1149 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 1150 #define p ((struct fbcursor *)data) 1151 #define pc (&sc->sc_cursor) 1152 1153 case FBIOGCURSOR: 1154 /* does anyone use this ioctl?! */ 1155 p->set = FB_CUR_SETALL; /* close enough, anyway */ 1156 p->enable = 1; 1157 p->pos.x = sc->sc_cursor_x; 1158 p->pos.y = sc->sc_cursor_y; 1159 p->size.x = 64; 1160 p->size.y = 64; 1161 break; 1162 1163 case FBIOSCURSOR: 1164 agten_do_sun_cursor(sc, p); 1165 break; 1166 1167 #undef p 1168 #undef cc 1169 1170 case FBIOGCURPOS: 1171 { 1172 struct fbcurpos *cp = (struct fbcurpos *)data; 1173 cp->x = sc->sc_cursor_x; 1174 cp->y = sc->sc_cursor_y; 1175 } 1176 break; 1177 1178 case FBIOSCURPOS: 1179 { 1180 struct fbcurpos *cp = (struct fbcurpos *)data; 1181 agten_move_cursor(sc, cp->x, cp->y); 1182 } 1183 break; 1184 1185 case FBIOGCURMAX: 1186 /* max cursor size is 64x64 */ 1187 ((struct fbcurpos *)data)->x = 64; 1188 ((struct fbcurpos *)data)->y = 64; 1189 break; 1190 1191 default: 1192 return (ENOTTY); 1193 } 1194 return (0); 1195 } 1196 1197 static paddr_t 1198 agten_fb_mmap(dev_t dev, off_t off, int prot) 1199 { 1200 struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev)); 1201 1202 /* 1203 * mappings are subject to change 1204 * for now we put the framebuffer at offset 0 and the GLint registers 1205 * right after that. We may want to expose more register ranges and 1206 * probably will want to map the 2nd framebuffer as well 1207 */ 1208 1209 if (off < 0) 1210 return EINVAL; 1211 1212 if (off >= sc->sc_glint_fbsz + 0x10000) 1213 return EINVAL; 1214 1215 if (off < sc->sc_glint_fbsz) { 1216 return (bus_space_mmap(sc->sc_bustag, 1217 sc->sc_glint_fb, 1218 off, 1219 prot, 1220 BUS_SPACE_MAP_LINEAR)); 1221 } 1222 1223 off -= sc->sc_glint_fbsz; 1224 if (off < 0x10000) { 1225 return (bus_space_mmap(sc->sc_bustag, 1226 sc->sc_glint_regs, 1227 off, 1228 prot, 1229 BUS_SPACE_MAP_LINEAR)); 1230 } 1231 return EINVAL; 1232 } 1233