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