1 /* $NetBSD: agten.c,v 1.24 2010/01/29 23:50:01 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.24 2010/01/29 23:50:01 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 - 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 72 #include <dev/sbus/p9100reg.h> 73 #include <dev/ic/ibm561reg.h> 74 #include <dev/ic/i128reg.h> 75 #include <dev/ic/i128var.h> 76 77 #include <uvm/uvm_extern.h> 78 79 #include "opt_agten.h" 80 #include "ioconf.h" 81 82 static int agten_match(device_t, cfdata_t, void *); 83 static void agten_attach(device_t, device_t, void *); 84 85 static int agten_ioctl(void *, void *, u_long, void *, int, struct lwp *); 86 static paddr_t agten_mmap(void *, void *, off_t, int); 87 static void agten_init_screen(void *, struct vcons_screen *, int, long *); 88 89 struct agten_softc { 90 device_t sc_dev; /* base device */ 91 struct fbdevice sc_fb; /* frame buffer device */ 92 93 struct vcons_screen sc_console_screen; 94 struct wsscreen_descr sc_defaultscreen_descr; 95 const struct wsscreen_descr *sc_screens[1]; 96 struct wsscreen_list sc_screenlist; 97 98 bus_space_tag_t sc_bustag; 99 100 bus_space_handle_t sc_i128_fbh; 101 bus_size_t sc_i128_fbsz; 102 bus_space_handle_t sc_i128_regh; 103 bus_space_handle_t sc_p9100_regh; 104 bus_addr_t sc_glint_fb; 105 bus_addr_t sc_glint_regs; 106 uint32_t sc_glint_fbsz; 107 108 uint32_t sc_width; 109 uint32_t sc_height; /* panel width / height */ 110 uint32_t sc_stride; 111 uint32_t sc_depth; 112 113 int sc_cursor_x; 114 int sc_cursor_y; 115 int sc_video; /* video output enabled */ 116 117 /* some /dev/fb* stuff */ 118 int sc_fb_is_open; 119 120 union bt_cmap sc_cmap; /* Brooktree color map */ 121 122 int sc_mode; 123 uint32_t sc_bg; 124 struct vcons_data vd; 125 }; 126 127 CFATTACH_DECL_NEW(agten, sizeof(struct agten_softc), 128 agten_match, agten_attach, NULL, NULL); 129 130 131 static int agten_putcmap(struct agten_softc *, struct wsdisplay_cmap *); 132 static int agten_getcmap(struct agten_softc *, struct wsdisplay_cmap *); 133 static int agten_putpalreg(struct agten_softc *, uint8_t, uint8_t, 134 uint8_t, uint8_t); 135 static void agten_init(struct agten_softc *); 136 static void agten_gfx(struct agten_softc *); 137 static void agten_set_video(struct agten_softc *, int); 138 static int agten_get_video(struct agten_softc *); 139 140 static void agten_copycols(void *, int, int, int, int); 141 static void agten_erasecols(void *, int, int, int, long); 142 static void agten_copyrows(void *, int, int, int); 143 static void agten_eraserows(void *, int, int, long); 144 145 static void agten_move_cursor(struct agten_softc *, int, int); 146 static int agten_do_cursor(struct agten_softc *sc, 147 struct wsdisplay_cursor *); 148 static int agten_do_sun_cursor(struct agten_softc *sc, 149 struct fbcursor *); 150 151 static uint16_t util_interleave(uint8_t, uint8_t); 152 static uint16_t util_interleave_lin(uint8_t, uint8_t); 153 154 extern const u_char rasops_cmap[768]; 155 156 struct wsdisplay_accessops agten_accessops = { 157 agten_ioctl, 158 agten_mmap, 159 NULL, /* alloc_screen */ 160 NULL, /* free_screen */ 161 NULL, /* show_screen */ 162 NULL, /* load_font */ 163 NULL, /* pollc */ 164 NULL /* scroll */ 165 }; 166 167 /* /dev/fb* stuff */ 168 169 static int agten_fb_open(dev_t, int, int, struct lwp *); 170 static int agten_fb_close(dev_t, int, int, struct lwp *); 171 static int agten_fb_ioctl(dev_t, u_long, void *, int, struct lwp *); 172 static paddr_t agten_fb_mmap(dev_t, off_t, int); 173 static void agten_fb_unblank(device_t); 174 175 static struct fbdriver agtenfbdriver = { 176 agten_fb_unblank, agten_fb_open, agten_fb_close, agten_fb_ioctl, 177 nopoll, agten_fb_mmap, nokqfilter 178 }; 179 180 static inline void 181 agten_write_dac(struct agten_softc *sc, int reg, uint8_t val) 182 { 183 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, 184 0x200 + (reg << 2), (uint32_t)val << 16); 185 } 186 187 static inline void 188 agten_write_idx(struct agten_softc *sc, int offset) 189 { 190 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, 191 0x200 + (IBM561_ADDR_LOW << 2), (offset & 0xff) << 16); 192 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, 193 0x200 + (IBM561_ADDR_HIGH << 2), ((offset >> 8) & 0xff) << 16); 194 } 195 196 static inline void 197 agten_write_dac_10(struct agten_softc *sc, int reg, uint16_t val) 198 { 199 agten_write_dac(sc, reg, (val >> 2) & 0xff); 200 agten_write_dac(sc, reg, (val & 0x3) << 6); 201 } 202 203 static int 204 agten_match(device_t dev, cfdata_t cf, void *aux) 205 { 206 struct sbus_attach_args *sa = aux; 207 208 if (strcmp("PFU,aga", sa->sa_name) == 0) 209 return 100; 210 return 0; 211 } 212 213 static void 214 agten_attach(device_t parent, device_t dev, void *aux) 215 { 216 struct agten_softc *sc = device_private(dev); 217 struct sbus_attach_args *sa = aux; 218 struct fbdevice *fb = &sc->sc_fb; 219 struct wsemuldisplaydev_attach_args aa; 220 struct rasops_info *ri; 221 long defattr; 222 uint32_t reg; 223 int node = sa->sa_node; 224 int console; 225 226 sc->sc_dev = dev; 227 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 228 "default", 229 0, 0, 230 NULL, 231 8, 16, 232 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 233 NULL 234 }; 235 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 236 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 237 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 238 sc->sc_fb_is_open = 0; 239 sc->sc_video = -1; 240 sc->sc_bustag = sa->sa_bustag; 241 242 sc->sc_width = prom_getpropint(node, "ffb_width", 1152); 243 sc->sc_height = prom_getpropint(node, "ffb_height", 900); 244 sc->sc_depth = prom_getpropint(node, "ffb_depth", 8); 245 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); 246 247 reg = prom_getpropint(node, "i128_fb_physaddr", -1); 248 sc->sc_i128_fbsz = prom_getpropint(node, "i128_fb_size", -1); 249 if (sbus_bus_map(sc->sc_bustag, 250 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg, 251 round_page(sc->sc_stride * sc->sc_height), 252 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 253 &sc->sc_i128_fbh) != 0) { 254 255 aprint_error_dev(dev, "unable to map the framebuffer\n"); 256 return; 257 } 258 fb->fb_pixels = bus_space_vaddr(sc->sc_bustag, sc->sc_i128_fbh); 259 260 reg = prom_getpropint(node, "i128_reg_physaddr", -1); 261 if (sbus_bus_map(sc->sc_bustag, 262 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg, 263 0x10000, 0, &sc->sc_i128_regh) != 0) { 264 265 aprint_error_dev(dev, "unable to map I128 registers\n"); 266 return; 267 } 268 269 reg = prom_getpropint(node, "p9100_reg_physaddr", -1); 270 if (sbus_bus_map(sc->sc_bustag, 271 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg, 272 0x8000, 0, &sc->sc_p9100_regh) != 0) { 273 274 aprint_error_dev(dev, "unable to map P9100 registers\n"); 275 return; 276 } 277 278 reg = prom_getpropint(node, "glint_fb0_physaddr", -1); 279 sc->sc_glint_fb = sbus_bus_addr(sc->sc_bustag, 280 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg); 281 sc->sc_glint_fbsz = prom_getpropint(node, "glint_lb_size", -1); 282 reg = prom_getpropint(node, "glint_reg_physaddr", -1); 283 sc->sc_glint_regs = sbus_bus_addr(sc->sc_bustag, 284 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg); 285 286 #if 0 287 bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO, 288 agten_intr, sc); 289 #endif 290 291 printf(": %dx%d\n", sc->sc_width, sc->sc_height); 292 agten_init(sc); 293 294 console = fb_is_console(node); 295 296 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 297 &agten_accessops); 298 sc->vd.init_screen = agten_init_screen; 299 300 ri = &sc->sc_console_screen.scr_ri; 301 302 if (console) { 303 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 304 &defattr); 305 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 306 307 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 308 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 309 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 310 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 311 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 312 defattr); 313 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, 314 sc->sc_width, sc->sc_height, 315 ri->ri_devcmap[(defattr >> 16) & 0xff]); 316 vcons_replay_msgbuf(&sc->sc_console_screen); 317 } else { 318 /* 319 * since we're not the console we can postpone the rest 320 * until someone actually allocates a screen for us 321 */ 322 } 323 324 /* Initialize the default color map. */ 325 326 aa.console = console; 327 aa.scrdata = &sc->sc_screenlist; 328 aa.accessops = &agten_accessops; 329 aa.accesscookie = &sc->vd; 330 331 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 332 333 fb->fb_driver = &agtenfbdriver; 334 fb->fb_device = sc->sc_dev; 335 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK; 336 fb->fb_type.fb_type = FBTYPE_AG10E; 337 fb->fb_type.fb_cmsize = 256; /* doesn't matter, we're always 24bit */ 338 fb->fb_type.fb_size = sc->sc_glint_fbsz; 339 fb->fb_type.fb_width = sc->sc_width; 340 fb->fb_type.fb_height = sc->sc_height; 341 fb->fb_type.fb_depth = 32; 342 fb->fb_linebytes = sc->sc_stride << 2; 343 fb_attach(fb, console); 344 agten_set_video(sc, 1); /* make sure video's on */ 345 } 346 347 static int 348 agten_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 349 struct lwp *l) 350 { 351 struct vcons_data *vd = v; 352 struct agten_softc *sc = vd->cookie; 353 struct wsdisplay_fbinfo *wdf; 354 struct vcons_screen *ms = vd->active; 355 356 switch (cmd) { 357 358 case WSDISPLAYIO_GTYPE: 359 *(u_int *)data = WSDISPLAY_TYPE_AG10; 360 return 0; 361 362 case WSDISPLAYIO_GINFO: 363 if (ms == NULL) 364 return ENODEV; 365 wdf = (void *)data; 366 wdf->height = ms->scr_ri.ri_height; 367 wdf->width = ms->scr_ri.ri_width; 368 wdf->depth = 32; 369 wdf->cmsize = 256; 370 return 0; 371 372 case WSDISPLAYIO_GVIDEO: 373 *(int *)data = sc->sc_video; 374 return 0; 375 376 case WSDISPLAYIO_SVIDEO: 377 agten_set_video(sc, *(int *)data); 378 return 0; 379 380 case WSDISPLAYIO_GETCMAP: 381 return agten_getcmap(sc, 382 (struct wsdisplay_cmap *)data); 383 384 case WSDISPLAYIO_PUTCMAP: 385 return agten_putcmap(sc, 386 (struct wsdisplay_cmap *)data); 387 388 case WSDISPLAYIO_LINEBYTES: 389 *(u_int *)data = sc->sc_stride << 2; 390 return 0; 391 392 case WSDISPLAYIO_SMODE: 393 { 394 int new_mode = *(int*)data; 395 if (new_mode != sc->sc_mode) { 396 sc->sc_mode = new_mode; 397 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 398 agten_init(sc); 399 vcons_redraw_screen(ms); 400 } else { 401 agten_gfx(sc); 402 } 403 } 404 } 405 return 0; 406 407 case WSDISPLAYIO_GCURPOS: 408 { 409 struct wsdisplay_curpos *cp = (void *)data; 410 411 cp->x = sc->sc_cursor_x; 412 cp->y = sc->sc_cursor_y; 413 } 414 return 0; 415 416 case WSDISPLAYIO_SCURPOS: 417 { 418 struct wsdisplay_curpos *cp = (void *)data; 419 420 agten_move_cursor(sc, cp->x, cp->y); 421 } 422 return 0; 423 424 case WSDISPLAYIO_GCURMAX: 425 { 426 struct wsdisplay_curpos *cp = (void *)data; 427 428 cp->x = 64; 429 cp->y = 64; 430 } 431 return 0; 432 433 case WSDISPLAYIO_SCURSOR: 434 { 435 struct wsdisplay_cursor *cursor = (void *)data; 436 437 return agten_do_cursor(sc, cursor); 438 } 439 } 440 return EPASSTHROUGH; 441 } 442 443 static paddr_t 444 agten_mmap(void *v, void *vs, off_t offset, int prot) 445 { 446 struct vcons_data *vd = v; 447 struct agten_softc *sc = vd->cookie; 448 449 if (offset < sc->sc_glint_fbsz) 450 return bus_space_mmap(sc->sc_bustag, sc->sc_glint_fb, offset, 451 prot, BUS_SPACE_MAP_LINEAR); 452 return -1; 453 } 454 455 static void 456 agten_init_screen(void *cookie, struct vcons_screen *scr, 457 int existing, long *defattr) 458 { 459 struct agten_softc *sc = cookie; 460 struct rasops_info *ri = &scr->scr_ri; 461 462 ri->ri_depth = sc->sc_depth; 463 ri->ri_width = sc->sc_width; 464 ri->ri_height = sc->sc_height; 465 ri->ri_stride = sc->sc_stride; 466 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 467 468 ri->ri_bits = (char *)sc->sc_fb.fb_pixels; 469 470 if (existing) { 471 ri->ri_flg |= RI_CLEAR; 472 } 473 474 rasops_init(ri, sc->sc_height / 8, sc->sc_width / 8); 475 ri->ri_caps = WSSCREEN_WSCOLORS; 476 477 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 478 sc->sc_width / ri->ri_font->fontwidth); 479 480 ri->ri_hw = scr; 481 ri->ri_ops.copyrows = agten_copyrows; 482 ri->ri_ops.eraserows = agten_eraserows; 483 ri->ri_ops.copycols = agten_copycols; 484 ri->ri_ops.erasecols = agten_erasecols; 485 486 } 487 488 static int 489 agten_putcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm) 490 { 491 u_int index = cm->index; 492 u_int count = cm->count; 493 int i, error; 494 u_char rbuf[256], gbuf[256], bbuf[256]; 495 u_char *r, *g, *b; 496 497 if (cm->index >= 256 || cm->count > 256 || 498 (cm->index + cm->count) > 256) 499 return EINVAL; 500 error = copyin(cm->red, &rbuf[index], count); 501 if (error) 502 return error; 503 error = copyin(cm->green, &gbuf[index], count); 504 if (error) 505 return error; 506 error = copyin(cm->blue, &bbuf[index], count); 507 if (error) 508 return error; 509 510 r = &rbuf[index]; 511 g = &gbuf[index]; 512 b = &bbuf[index]; 513 514 for (i = 0; i < count; i++) { 515 agten_putpalreg(sc, index, *r, *g, *b); 516 index++; 517 r++, g++, b++; 518 } 519 return 0; 520 } 521 522 static int 523 agten_getcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm) 524 { 525 u_int index = cm->index; 526 u_int count = cm->count; 527 int error, i; 528 uint8_t red[256], green[256], blue[256]; 529 530 if (index >= 255 || count > 256 || index + count > 256) 531 return EINVAL; 532 533 i = index; 534 while (i < (index + count)) { 535 red[i] = sc->sc_cmap.cm_map[i][0]; 536 green[i] = sc->sc_cmap.cm_map[i][1]; 537 blue[i] = sc->sc_cmap.cm_map[i][2]; 538 i++; 539 } 540 error = copyout(&red[index], cm->red, count); 541 if (error) 542 return error; 543 error = copyout(&green[index], cm->green, count); 544 if (error) 545 return error; 546 error = copyout(&blue[index], cm->blue, count); 547 if (error) 548 return error; 549 550 return 0; 551 } 552 553 static int 554 agten_putpalreg(struct agten_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 555 uint8_t b) 556 { 557 558 sc->sc_cmap.cm_map[idx][0] = r; 559 sc->sc_cmap.cm_map[idx][1] = g; 560 sc->sc_cmap.cm_map[idx][2] = b; 561 agten_write_idx(sc, IBM561_CMAP_TABLE + idx); 562 agten_write_dac(sc, IBM561_CMD_CMAP, r); 563 agten_write_dac(sc, IBM561_CMD_CMAP, g); 564 agten_write_dac(sc, IBM561_CMD_CMAP, b); 565 return 0; 566 } 567 568 static void 569 agten_init(struct agten_softc *sc) 570 { 571 int i, j; 572 uint32_t src, srcw; 573 volatile uint32_t junk; 574 575 /* first we set up the colour map */ 576 j = 0; 577 for (i = 0; i < 256; i++) { 578 579 agten_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1], 580 rasops_cmap[j + 2]); 581 j += 3; 582 } 583 584 /* then we set up a linear LUT for 24bit colour */ 585 agten_write_idx(sc, IBM561_CMAP_TABLE + 256); 586 for (i = 0; i < 256; i++) { 587 agten_write_dac(sc, IBM561_CMD_CMAP, i); 588 agten_write_dac(sc, IBM561_CMD_CMAP, i); 589 agten_write_dac(sc, IBM561_CMD_CMAP, i); 590 } 591 592 /* and the linear gamma maps */ 593 agten_write_idx(sc, IBM561_RED_GAMMA_TABLE); 594 for (i = 0; i < 0x3ff; i+= 4) 595 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i); 596 agten_write_idx(sc, IBM561_GREEN_GAMMA_TABLE); 597 for (i = 0; i < 0x3ff; i+= 4) 598 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i); 599 agten_write_idx(sc, IBM561_BLUE_GAMMA_TABLE); 600 for (i = 0; i < 0x3ff; i+= 4) 601 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i); 602 603 /* enable outputs, RGB mode */ 604 agten_write_idx(sc, IBM561_CONFIG_REG3); 605 agten_write_dac(sc, IBM561_CMD, CR3_SERIAL_CLK_CTRL | CR3_RGB); 606 607 /* MUX 4:1 basic, 8bit overlay, 8bit WIDs */ 608 agten_write_idx(sc, IBM561_CONFIG_REG1); 609 agten_write_dac(sc, IBM561_CMD, CR1_MODE_4_1_BASIC | CR1_OVL_8BPP | 610 CR1_WID_8); 611 612 /* use external clock, enable video output */ 613 agten_write_idx(sc, IBM561_CONFIG_REG2); 614 agten_write_dac(sc, IBM561_CMD, CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | 615 CR2_PIXEL_CLOCK_SELECT | CR2_ENABLE_RGB_OUTPUT); 616 617 /* now set up some window attributes */ 618 619 /* 620 * direct colour, 24 bit, transparency off, LUT from 0x100 621 * we need to use direct colour and a linear LUT because for some 622 * reason true color mode gives messed up colours 623 */ 624 agten_write_idx(sc, IBM561_FB_WINTYPE); 625 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x100 | FB_PIXEL_24BIT | 626 FB_MODE_DIRECT); 627 628 /* use gamma LUTs, no crosshair, 0 is transparent */ 629 agten_write_idx(sc, IBM561_AUXFB_WINTYPE); 630 agten_write_dac(sc, IBM561_CMD_FB_WAT, 0x0); 631 632 /* overlay is 8 bit, opaque */ 633 agten_write_idx(sc, IBM561_OL_WINTYPE); 634 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x00); 635 636 /* now we fill the WID fb with zeroes */ 637 src = 0; 638 srcw = sc->sc_width << 16 | sc->sc_height; 639 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, FOREGROUND_COLOR, 640 0x0); 641 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, BACKGROUND_COLOR, 642 0x0); 643 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RASTER_OP, ROP_PAT); 644 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, COORD_INDEX, 0); 645 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, src); 646 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, srcw); 647 junk = bus_space_read_4(sc->sc_bustag, sc->sc_p9100_regh, COMMAND_QUAD); 648 649 /* initialize the cursor registers */ 650 651 /* initialize the Imagine 128 */ 652 i128_init(sc->sc_bustag, sc->sc_i128_regh, sc->sc_stride, 8); 653 } 654 655 static void 656 agten_gfx(struct agten_softc *sc) 657 { 658 /* enable overlay transparency on colour 0x00 */ 659 agten_write_idx(sc, IBM561_OL_WINTYPE); 660 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, OL_MODE_TRANSP_ENABLE); 661 662 /* then blit the overlay full of 0x00 */ 663 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, sc->sc_width, 664 sc->sc_height, 0); 665 666 /* ... so we can see the 24bit framebuffer */ 667 } 668 669 static void 670 agten_set_video(struct agten_softc *sc, int flag) 671 { 672 uint8_t reg = 673 CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | CR2_PIXEL_CLOCK_SELECT; 674 675 if (flag == sc->sc_video) 676 return; 677 678 agten_write_idx(sc, IBM561_CONFIG_REG2); 679 agten_write_dac(sc, IBM561_CMD, flag ? reg | CR2_ENABLE_RGB_OUTPUT : 680 reg); 681 682 sc->sc_video = flag; 683 } 684 685 static int 686 agten_get_video(struct agten_softc *sc) 687 { 688 689 return sc->sc_video; 690 } 691 692 static void 693 agten_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 694 { 695 struct rasops_info *ri = cookie; 696 struct vcons_screen *scr = ri->ri_hw; 697 struct agten_softc *sc = scr->scr_cookie; 698 int32_t xs, xd, y, width, height; 699 700 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 701 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 702 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 703 width = ri->ri_font->fontwidth * ncols; 704 height = ri->ri_font->fontheight; 705 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, xs, y, xd, y, width, 706 height, CR_COPY); 707 } 708 709 static void 710 agten_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 711 { 712 struct rasops_info *ri = cookie; 713 struct vcons_screen *scr = ri->ri_hw; 714 struct agten_softc *sc = scr->scr_cookie; 715 int32_t x, y, width, height, bg; 716 717 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 718 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 719 width = ri->ri_font->fontwidth * ncols; 720 height = ri->ri_font->fontheight; 721 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 722 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg); 723 } 724 725 static void 726 agten_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 727 { 728 struct rasops_info *ri = cookie; 729 struct vcons_screen *scr = ri->ri_hw; 730 struct agten_softc *sc = scr->scr_cookie; 731 int32_t x, ys, yd, width, height; 732 733 x = ri->ri_xorigin; 734 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 735 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 736 width = ri->ri_emuwidth; 737 height = ri->ri_font->fontheight * nrows; 738 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, ys, x, yd, width, 739 height, CR_COPY); 740 } 741 742 static void 743 agten_eraserows(void *cookie, int row, int nrows, long fillattr) 744 { 745 struct rasops_info *ri = cookie; 746 struct vcons_screen *scr = ri->ri_hw; 747 struct agten_softc *sc = scr->scr_cookie; 748 int32_t x, y, width, height, bg; 749 750 if ((row == 0) && (nrows == ri->ri_rows)) { 751 x = y = 0; 752 width = ri->ri_width; 753 height = ri->ri_height; 754 } else { 755 x = ri->ri_xorigin; 756 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 757 width = ri->ri_emuwidth; 758 height = ri->ri_font->fontheight * nrows; 759 } 760 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 761 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg); 762 } 763 764 static void 765 agten_move_cursor(struct agten_softc *sc, int x, int y) 766 { 767 768 sc->sc_cursor_x = x; 769 sc->sc_cursor_y = y; 770 agten_write_idx(sc, IBM561_CURSOR_X_REG); 771 agten_write_dac(sc, IBM561_CMD, x & 0xff); 772 agten_write_dac(sc, IBM561_CMD, (x >> 8) & 0xff); 773 agten_write_dac(sc, IBM561_CMD, y & 0xff); 774 agten_write_dac(sc, IBM561_CMD, (y >> 8) & 0xff); 775 } 776 777 static int 778 agten_do_cursor(struct agten_softc *sc, struct wsdisplay_cursor *cur) 779 { 780 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 781 782 agten_write_idx(sc, IBM561_CURS_CNTL_REG); 783 agten_write_dac(sc, IBM561_CMD, cur->enable ? 784 CURS_ENABLE : 0); 785 } 786 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 787 788 agten_write_idx(sc, IBM561_HOTSPOT_X_REG); 789 agten_write_dac(sc, IBM561_CMD, cur->hot.x); 790 agten_write_dac(sc, IBM561_CMD, cur->hot.y); 791 } 792 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 793 794 agten_move_cursor(sc, cur->pos.x, cur->pos.y); 795 } 796 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 797 int i; 798 799 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2); 800 for (i = 0; i < cur->cmap.count; i++) { 801 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]); 802 agten_write_dac(sc, IBM561_CMD_CMAP, 803 cur->cmap.green[i]); 804 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]); 805 } 806 } 807 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 808 int i; 809 uint16_t tmp; 810 811 agten_write_idx(sc, IBM561_CURSOR_BITMAP); 812 for (i = 0; i < 512; i++) { 813 tmp = util_interleave(cur->mask[i], cur->image[i]); 814 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff); 815 agten_write_dac(sc, IBM561_CMD, tmp & 0xff); 816 } 817 } 818 return 0; 819 } 820 821 static int 822 agten_do_sun_cursor(struct agten_softc *sc, struct fbcursor *cur) 823 { 824 if (cur->set & FB_CUR_SETCUR) { 825 826 agten_write_idx(sc, IBM561_CURS_CNTL_REG); 827 agten_write_dac(sc, IBM561_CMD, cur->enable ? 828 CURS_ENABLE : 0); 829 } 830 if (cur->set & FB_CUR_SETHOT) { 831 832 agten_write_idx(sc, IBM561_HOTSPOT_X_REG); 833 agten_write_dac(sc, IBM561_CMD, cur->hot.x); 834 agten_write_dac(sc, IBM561_CMD, cur->hot.y); 835 } 836 if (cur->set & FB_CUR_SETPOS) { 837 838 agten_move_cursor(sc, cur->pos.x, cur->pos.y); 839 } 840 if (cur->set & FB_CUR_SETCMAP) { 841 int i; 842 843 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2); 844 for (i = 0; i < cur->cmap.count; i++) { 845 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]); 846 agten_write_dac(sc, IBM561_CMD_CMAP, 847 cur->cmap.green[i]); 848 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]); 849 } 850 } 851 if (cur->set & FB_CUR_SETSHAPE) { 852 int i; 853 uint16_t tmp; 854 855 agten_write_idx(sc, IBM561_CURSOR_BITMAP); 856 for (i = 0; i < 512; i++) { 857 tmp = util_interleave_lin(cur->mask[i], cur->image[i]); 858 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff); 859 agten_write_dac(sc, IBM561_CMD, tmp & 0xff); 860 } 861 } 862 return 0; 863 } 864 865 uint16_t 866 util_interleave(uint8_t b1, uint8_t b2) 867 { 868 int i; 869 uint16_t ret = 0; 870 uint16_t mask = 0x8000; 871 uint8_t mask8 = 0x01; 872 873 for (i = 0; i < 8; i++) { 874 if (b1 & mask8) 875 ret |= mask; 876 mask = mask >> 1; 877 if (b2 & mask8) 878 ret |= mask; 879 mask = mask >> 1; 880 mask8 = mask8 << 1; 881 } 882 return ret; 883 } 884 885 uint16_t 886 util_interleave_lin(uint8_t b1, uint8_t b2) 887 { 888 int i; 889 uint16_t ret = 0; 890 uint16_t mask = 0x8000; 891 uint8_t mask8 = 0x80; 892 893 for (i = 0; i < 8; i++) { 894 if (b1 & mask8) 895 ret |= mask; 896 mask = mask >> 1; 897 if (b2 & mask8) 898 ret |= mask; 899 mask = mask >> 1; 900 mask8 = mask8 >> 1; 901 } 902 return ret; 903 } 904 905 /* and now the /dev/fb* stuff */ 906 static void 907 agten_fb_unblank(device_t dev) 908 { 909 struct agten_softc *sc = device_private(dev); 910 911 agten_init(sc); 912 agten_set_video(sc, 1); 913 } 914 915 static int 916 agten_fb_open(dev_t dev, int flags, int mode, struct lwp *l) 917 { 918 struct agten_softc *sc; 919 920 sc = device_lookup_private(&agten_cd, minor(dev)); 921 if (sc == NULL) 922 return (ENXIO); 923 if (sc->sc_fb_is_open) 924 return 0; 925 926 sc->sc_fb_is_open++; 927 agten_gfx(sc); 928 929 return (0); 930 } 931 932 static int 933 agten_fb_close(dev_t dev, int flags, int mode, struct lwp *l) 934 { 935 struct agten_softc *sc; 936 937 sc = device_lookup_private(&agten_cd, minor(dev)); 938 939 sc->sc_fb_is_open--; 940 if (sc->sc_fb_is_open < 0) 941 sc->sc_fb_is_open = 0; 942 943 if (sc->sc_fb_is_open == 0) { 944 agten_init(sc); 945 vcons_redraw_screen(sc->vd.active); 946 } 947 948 return (0); 949 } 950 951 static int 952 agten_fb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 953 { 954 struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev)); 955 struct fbgattr *fba; 956 int error; 957 958 switch (cmd) { 959 960 case FBIOGTYPE: 961 *(struct fbtype *)data = sc->sc_fb.fb_type; 962 break; 963 964 case FBIOGATTR: 965 fba = (struct fbgattr *)data; 966 fba->real_type = sc->sc_fb.fb_type.fb_type; 967 fba->owner = 0; /* XXX ??? */ 968 fba->fbtype = sc->sc_fb.fb_type; 969 fba->sattr.flags = 0; 970 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 971 fba->sattr.dev_specific[0] = -1; 972 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 973 fba->emu_types[1] = -1; 974 break; 975 976 case FBIOGETCMAP: 977 #define p ((struct fbcmap *)data) 978 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 979 980 case FBIOPUTCMAP: 981 /* copy to software map */ 982 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 983 if (error) 984 return (error); 985 /* now blast them into the chip */ 986 /* don't bother - we're 24bit */ 987 #undef p 988 break; 989 990 case FBIOGVIDEO: 991 *(int *)data = agten_get_video(sc); 992 break; 993 994 case FBIOSVIDEO: 995 agten_set_video(sc, *(int *)data); 996 break; 997 998 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 999 #define p ((struct fbcursor *)data) 1000 #define pc (&sc->sc_cursor) 1001 1002 case FBIOGCURSOR: 1003 /* does anyone use this ioctl?! */ 1004 p->set = FB_CUR_SETALL; /* close enough, anyway */ 1005 p->enable = 1; 1006 p->pos.x = sc->sc_cursor_x; 1007 p->pos.y = sc->sc_cursor_y; 1008 p->size.x = 64; 1009 p->size.y = 64; 1010 break; 1011 1012 case FBIOSCURSOR: 1013 agten_do_sun_cursor(sc, p); 1014 break; 1015 1016 #undef p 1017 #undef cc 1018 1019 case FBIOGCURPOS: 1020 { 1021 struct fbcurpos *cp = (struct fbcurpos *)data; 1022 cp->x = sc->sc_cursor_x; 1023 cp->y = sc->sc_cursor_y; 1024 } 1025 break; 1026 1027 case FBIOSCURPOS: 1028 { 1029 struct fbcurpos *cp = (struct fbcurpos *)data; 1030 agten_move_cursor(sc, cp->x, cp->y); 1031 } 1032 break; 1033 1034 case FBIOGCURMAX: 1035 /* max cursor size is 64x64 */ 1036 ((struct fbcurpos *)data)->x = 64; 1037 ((struct fbcurpos *)data)->y = 64; 1038 break; 1039 1040 default: 1041 return (ENOTTY); 1042 } 1043 return (0); 1044 } 1045 1046 static paddr_t 1047 agten_fb_mmap(dev_t dev, off_t off, int prot) 1048 { 1049 struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev)); 1050 1051 /* 1052 * mappings are subject to change 1053 * for now we put the framebuffer at offset 0 and the GLint registers 1054 * right after that. We may want to expose more register ranges and 1055 * probably will want to map the 2nd framebuffer as well 1056 */ 1057 1058 if (off < 0) 1059 return EINVAL; 1060 1061 if (off >= sc->sc_glint_fbsz + 0x10000) 1062 return EINVAL; 1063 1064 if (off < sc->sc_glint_fbsz) { 1065 return (bus_space_mmap(sc->sc_bustag, 1066 sc->sc_glint_fb, 1067 off, 1068 prot, 1069 BUS_SPACE_MAP_LINEAR)); 1070 } 1071 1072 off -= sc->sc_glint_fbsz; 1073 if (off < 0x10000) { 1074 return (bus_space_mmap(sc->sc_bustag, 1075 sc->sc_glint_regs, 1076 off, 1077 prot, 1078 BUS_SPACE_MAP_LINEAR)); 1079 } 1080 return EINVAL; 1081 } 1082