1 /* $NetBSD: zx.c,v 1.26 2009/03/29 07:24:56 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Driver for the Sun ZX display adapter. This would be called 'leo', but 34 * NetBSD/amiga already has a driver by that name. The XFree86 and Linux 35 * drivers were used as "living documentation" when writing this; thanks 36 * to the authors. 37 * 38 * Issues (which can be solved with wscons, happily enough): 39 * 40 * o There is lots of unnecessary mucking about rasops in here, primarily 41 * to appease the sparc fb code. 42 * 43 * o RASTERCONSOLE is required. X needs the board set up correctly, and 44 * that's difficult to reconcile with using the PROM for output. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: zx.c,v 1.26 2009/03/29 07:24:56 tsutsui Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/device.h> 53 #include <sys/ioctl.h> 54 #include <sys/malloc.h> 55 #include <sys/mman.h> 56 #include <sys/tty.h> 57 #include <sys/conf.h> 58 #include <sys/syslog.h> 59 #include <sys/buf.h> 60 61 #include <sys/bus.h> 62 #include <machine/autoconf.h> 63 64 #include <uvm/uvm_extern.h> 65 66 #include <dev/sun/fbio.h> 67 #include <dev/sun/fbvar.h> 68 69 #include <dev/sbus/zxreg.h> 70 #include <dev/sbus/zxvar.h> 71 #include <dev/sbus/sbusvar.h> 72 73 #include <dev/wscons/wsconsio.h> 74 75 #ifndef RASTERCONSOLE 76 #error Sorry, this driver needs the RASTERCONSOLE option 77 #endif 78 79 #define ZX_STD_ROP (ZX_ROP_NEW | ZX_ATTR_WE_ENABLE | \ 80 ZX_ATTR_OE_ENABLE | ZX_ATTR_FORCE_WID) 81 82 void zx_attach(struct device *, struct device *, void *); 83 int zx_match(struct device *, struct cfdata *, void *); 84 85 void zx_blank(struct device *); 86 int zx_cmap_put(struct zx_softc *); 87 void zx_copyrect(struct rasops_info *, int, int, int, int, int, int); 88 int zx_cross_loadwid(struct zx_softc *, u_int, u_int, u_int); 89 int zx_cross_wait(struct zx_softc *); 90 void zx_fillrect(struct rasops_info *, int, int, int, int, long, int); 91 int zx_intr(void *); 92 void zx_reset(struct zx_softc *); 93 void zx_unblank(struct device *); 94 95 void zx_cursor_blank(struct zx_softc *); 96 void zx_cursor_color(struct zx_softc *); 97 void zx_cursor_move(struct zx_softc *); 98 void zx_cursor_set(struct zx_softc *); 99 void zx_cursor_unblank(struct zx_softc *); 100 101 void zx_copycols(void *, int, int, int, int); 102 void zx_copyrows(void *, int, int, int); 103 void zx_cursor(void *, int, int, int); 104 void zx_do_cursor(struct rasops_info *); 105 void zx_erasecols(void *, int, int, int, long); 106 void zx_eraserows(void *, int, int, long); 107 void zx_putchar(void *, int, int, u_int, long); 108 109 struct zx_mmo { 110 off_t mo_va; 111 off_t mo_pa; 112 off_t mo_size; 113 } static const zx_mmo[] = { 114 { ZX_FB0_VOFF, ZX_OFF_SS0, 0x00800000 }, 115 { ZX_LC0_VOFF, ZX_OFF_LC_SS0_USR, 0x00001000 }, 116 { ZX_LD0_VOFF, ZX_OFF_LD_SS0, 0x00001000 }, 117 { ZX_LX0_CURSOR_VOFF, ZX_OFF_LX_CURSOR, 0x00001000 }, 118 { ZX_FB1_VOFF, ZX_OFF_SS1, 0x00800000 }, 119 { ZX_LC1_VOFF, ZX_OFF_LC_SS1_USR, 0x00001000 }, 120 { ZX_LD1_VOFF, ZX_OFF_LD_SS1, 0x00001000 }, 121 { ZX_LX_KRN_VOFF, ZX_OFF_LX_CROSS, 0x00001000 }, 122 { ZX_LC0_KRN_VOFF, ZX_OFF_LC_SS0_KRN, 0x00001000 }, 123 { ZX_LC1_KRN_VOFF, ZX_OFF_LC_SS1_KRN, 0x00001000 }, 124 { ZX_LD_GBL_VOFF, ZX_OFF_LD_GBL, 0x00001000 }, 125 }; 126 127 CFATTACH_DECL(zx, sizeof(struct zx_softc), 128 zx_match, zx_attach, NULL, NULL); 129 130 extern struct cfdriver zx_cd; 131 132 dev_type_open(zxopen); 133 dev_type_close(zxclose); 134 dev_type_ioctl(zxioctl); 135 dev_type_mmap(zxmmap); 136 137 static struct fbdriver zx_fbdriver = { 138 zx_unblank, zxopen, zxclose, zxioctl, nopoll, zxmmap 139 }; 140 141 int 142 zx_match(struct device *parent, struct cfdata *cf, void *aux) 143 { 144 struct sbus_attach_args *sa; 145 146 sa = (struct sbus_attach_args *)aux; 147 148 return (strcmp(sa->sa_name, "SUNW,leo") == 0); 149 } 150 151 void 152 zx_attach(struct device *parent, struct device *self, void *args) 153 { 154 struct zx_softc *sc; 155 struct sbus_attach_args *sa; 156 bus_space_handle_t bh; 157 bus_space_tag_t bt; 158 struct fbdevice *fb; 159 struct rasops_info *ri; 160 int width, height; 161 int isconsole; 162 163 sc = device_private(self); 164 sa = args; 165 fb = &sc->sc_fb; 166 ri = &fb->fb_rinfo; 167 bt = sa->sa_bustag; 168 sc->sc_bt = bt; 169 170 sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset); 171 172 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_SS0, 173 0x800000, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 174 aprint_error_dev(self, "can't map bits\n"); 175 return; 176 } 177 fb->fb_pixels = (void *)bus_space_vaddr(bt, bh); 178 sc->sc_pixels = (u_int32_t *)fb->fb_pixels; 179 180 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LC_SS0_USR, 181 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 182 aprint_error_dev(self, "can't map zc\n"); 183 return; 184 } 185 sc->sc_bhzc = bh; 186 187 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS0, 188 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 189 aprint_error_dev(self, "can't map ld/ss0\n"); 190 return; 191 } 192 sc->sc_bhzdss0 = bh; 193 194 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS1, 195 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 196 aprint_error_dev(self, "can't map ld/ss1\n"); 197 return; 198 } 199 sc->sc_bhzdss1 = bh; 200 201 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CROSS, 202 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 203 aprint_error_dev(self, "can't map zx\n"); 204 return; 205 } 206 sc->sc_bhzx = bh; 207 208 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CURSOR, 209 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 210 aprint_error_dev(self, "can't map zcu\n"); 211 return; 212 } 213 sc->sc_bhzcu = bh; 214 215 fb->fb_driver = &zx_fbdriver; 216 fb->fb_device = &sc->sc_dv; 217 fb->fb_flags = device_cfdata(&sc->sc_dv)->cf_flags & FB_USERMASK; 218 fb->fb_pfour = NULL; 219 fb->fb_linebytes = prom_getpropint(sa->sa_node, "linebytes", 8192); 220 221 width = prom_getpropint(sa->sa_node, "width", 1280); 222 height = prom_getpropint(sa->sa_node, "height", 1024); 223 fb_setsize_obp(fb, 32, width, height, sa->sa_node); 224 225 fb->fb_type.fb_cmsize = 256; 226 fb->fb_type.fb_depth = 32; 227 fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes; 228 fb->fb_type.fb_type = FBTYPE_SUNLEO; 229 230 printf(": %d x %d", fb->fb_type.fb_width, fb->fb_type.fb_height); 231 isconsole = fb_is_console(sa->sa_node); 232 if (isconsole) 233 printf(" (console)"); 234 printf("\n"); 235 236 sbus_establish(&sc->sc_sd, &sc->sc_dv); 237 if (sa->sa_nintr != 0) 238 bus_intr_establish(bt, sa->sa_pri, IPL_NONE, zx_intr, sc); 239 240 sc->sc_cmap = malloc(768, M_DEVBUF, M_NOWAIT); 241 fb_attach(&sc->sc_fb, isconsole); 242 zx_reset(sc); 243 244 /* 245 * Attach to rcons. XXX At this point, rasops_do_cursor() will be 246 * called before we get our hooks in place. So, we mask off access 247 * to the framebuffer until it's done. 248 */ 249 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 1); 250 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk, 0); 251 252 fbrcons_init(&sc->sc_fb); 253 254 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 0); 255 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk, 0xffffffff); 256 257 ri->ri_hw = sc; 258 ri->ri_do_cursor = zx_do_cursor; 259 ri->ri_ops.copycols = zx_copycols; 260 ri->ri_ops.copyrows = zx_copyrows; 261 ri->ri_ops.erasecols = zx_erasecols; 262 ri->ri_ops.eraserows = zx_eraserows; 263 ri->ri_ops.putchar = zx_putchar; 264 265 sc->sc_fontw = ri->ri_font->fontwidth; 266 sc->sc_fonth = ri->ri_font->fontheight; 267 } 268 269 int 270 zxopen(dev_t dev, int flags, int mode, struct lwp *l) 271 { 272 273 if (device_lookup(&zx_cd, minor(dev)) == NULL) 274 return (ENXIO); 275 return (0); 276 } 277 278 int 279 zxclose(dev_t dev, int flags, int mode, struct lwp *l) 280 { 281 struct zx_softc *sc; 282 283 sc = device_lookup_private(&zx_cd, minor(dev)); 284 285 zx_reset(sc); 286 zx_cursor_blank(sc); 287 return (0); 288 } 289 290 int 291 zxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 292 { 293 struct zx_softc *sc; 294 struct fbcmap *cm; 295 struct fbcursor *cu; 296 uint32_t curbits[2][32]; 297 int rv, v, count, i; 298 299 sc = device_lookup_private(&zx_cd, minor(dev)); 300 301 switch (cmd) { 302 case FBIOGTYPE: 303 *(struct fbtype *)data = sc->sc_fb.fb_type; 304 break; 305 306 case FBIOGATTR: 307 #define fba ((struct fbgattr *)data) 308 fba->real_type = sc->sc_fb.fb_type.fb_type; 309 fba->owner = 0; /* XXX ??? */ 310 fba->fbtype = sc->sc_fb.fb_type; 311 fba->sattr.flags = 0; 312 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 313 fba->sattr.dev_specific[0] = -1; 314 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 315 fba->emu_types[1] = -1; 316 fba->emu_types[2] = -1; 317 #undef fba 318 break; 319 320 case FBIOGVIDEO: 321 *(int *)data = ((sc->sc_flags & ZX_BLANKED) != 0); 322 break; 323 324 case FBIOSVIDEO: 325 if (*(int *)data) 326 zx_unblank(&sc->sc_dv); 327 else 328 zx_blank(&sc->sc_dv); 329 break; 330 331 case FBIOGETCMAP: 332 cm = (struct fbcmap *)data; 333 if (cm->index > 256 || cm->count > 256 - cm->index) 334 return (EINVAL); 335 rv = copyout(sc->sc_cmap + cm->index, cm->red, cm->count); 336 if (rv == 0) 337 rv = copyout(sc->sc_cmap + 256 + cm->index, cm->green, 338 cm->count); 339 if (rv == 0) 340 rv = copyout(sc->sc_cmap + 512 + cm->index, cm->blue, 341 cm->count); 342 return (rv); 343 344 case FBIOPUTCMAP: 345 cm = (struct fbcmap *)data; 346 if (cm->index > 256 || cm->count > 256 - cm->index) 347 return (EINVAL); 348 rv = copyin(cm->red, sc->sc_cmap + cm->index, cm->count); 349 if (rv == 0) 350 rv = copyin(cm->green, sc->sc_cmap + 256 + cm->index, 351 cm->count); 352 if (rv == 0) 353 rv = copyin(cm->blue, sc->sc_cmap + 512 + cm->index, 354 cm->count); 355 zx_cmap_put(sc); 356 return (rv); 357 358 case FBIOGCURPOS: 359 *(struct fbcurpos *)data = sc->sc_curpos; 360 break; 361 362 case FBIOSCURPOS: 363 sc->sc_curpos = *(struct fbcurpos *)data; 364 zx_cursor_move(sc); 365 break; 366 367 case FBIOGCURMAX: 368 ((struct fbcurpos *)data)->x = 32; 369 ((struct fbcurpos *)data)->y = 32; 370 break; 371 372 case FBIOSCURSOR: 373 cu = (struct fbcursor *)data; 374 v = cu->set; 375 376 if ((v & FB_CUR_SETSHAPE) != 0) { 377 if ((u_int)cu->size.x > 32 || (u_int)cu->size.y > 32) 378 return (EINVAL); 379 count = cu->size.y * 4; 380 rv = copyin(cu->mask, curbits[0], count); 381 if (rv) 382 return rv; 383 rv = copyin(cu->image, curbits[1], count); 384 if (rv) 385 return rv; 386 } 387 if ((v & FB_CUR_SETCUR) != 0) { 388 if (cu->enable) 389 zx_cursor_unblank(sc); 390 else 391 zx_cursor_blank(sc); 392 } 393 if ((v & (FB_CUR_SETPOS | FB_CUR_SETHOT)) != 0) { 394 if ((v & FB_CUR_SETPOS) != 0) 395 sc->sc_curpos = cu->pos; 396 if ((v & FB_CUR_SETHOT) != 0) 397 sc->sc_curhot = cu->hot; 398 zx_cursor_move(sc); 399 } 400 if ((v & FB_CUR_SETCMAP) != 0) { 401 if (cu->cmap.index > 2 || 402 cu->cmap.count > 2 - cu->cmap.index) 403 return (EINVAL); 404 for (i = 0; i < cu->cmap.count; i++) { 405 if ((v = fubyte(&cu->cmap.red[i])) < 0) 406 return (EFAULT); 407 sc->sc_curcmap[i + cu->cmap.index + 0] = v; 408 if ((v = fubyte(&cu->cmap.green[i])) < 0) 409 return (EFAULT); 410 sc->sc_curcmap[i + cu->cmap.index + 2] = v; 411 if ((v = fubyte(&cu->cmap.blue[i])) < 0) 412 return (EFAULT); 413 sc->sc_curcmap[i + cu->cmap.index + 4] = v; 414 } 415 zx_cursor_color(sc); 416 } 417 if ((v & FB_CUR_SETSHAPE) != 0) { 418 sc->sc_cursize = cu->size; 419 count = cu->size.y * 4; 420 memset(sc->sc_curbits, 0, sizeof(sc->sc_curbits)); 421 memcpy(sc->sc_curbits[0], curbits[0], count); 422 memcpy(sc->sc_curbits[1], curbits[1], count); 423 zx_cursor_set(sc); 424 } 425 break; 426 427 case FBIOGCURSOR: 428 cu = (struct fbcursor *)data; 429 430 cu->set = FB_CUR_SETALL; 431 cu->enable = ((sc->sc_flags & ZX_CURSOR) != 0); 432 cu->pos = sc->sc_curpos; 433 cu->hot = sc->sc_curhot; 434 cu->size = sc->sc_cursize; 435 436 if (cu->image != NULL) { 437 count = sc->sc_cursize.y * 4; 438 rv = copyout(sc->sc_curbits[1], cu->image, count); 439 if (rv) 440 return (rv); 441 rv = copyout(sc->sc_curbits[0], cu->mask, count); 442 if (rv) 443 return (rv); 444 } 445 if (cu->cmap.red != NULL) { 446 if (cu->cmap.index > 2 || 447 cu->cmap.count > 2 - cu->cmap.index) 448 return (EINVAL); 449 for (i = 0; i < cu->cmap.count; i++) { 450 v = sc->sc_curcmap[i + cu->cmap.index + 0]; 451 if (subyte(&cu->cmap.red[i], v)) 452 return (EFAULT); 453 v = sc->sc_curcmap[i + cu->cmap.index + 2]; 454 if (subyte(&cu->cmap.green[i], v)) 455 return (EFAULT); 456 v = sc->sc_curcmap[i + cu->cmap.index + 4]; 457 if (subyte(&cu->cmap.blue[i], v)) 458 return (EFAULT); 459 } 460 } else { 461 cu->cmap.index = 0; 462 cu->cmap.count = 2; 463 } 464 break; 465 466 default: 467 #ifdef DEBUG 468 log(LOG_NOTICE, "zxioctl(0x%lx) (%s[%d])\n", cmd, 469 l->l_proc->p_comm, l->l_proc->p_pid); 470 #endif 471 return (ENOTTY); 472 } 473 474 return (0); 475 } 476 477 int 478 zx_intr(void *cookie) 479 { 480 481 return (1); 482 } 483 484 void 485 zx_reset(struct zx_softc *sc) 486 { 487 struct fbtype *fbt; 488 u_int i; 489 490 fbt = &sc->sc_fb.fb_type; 491 492 zx_cross_loadwid(sc, ZX_WID_DBL_8, 0, 0x2c0); 493 zx_cross_loadwid(sc, ZX_WID_DBL_8, 1, 0x30); 494 zx_cross_loadwid(sc, ZX_WID_DBL_8, 2, 0x20); 495 zx_cross_loadwid(sc, ZX_WID_DBL_24, 1, 0x30); 496 497 i = bus_space_read_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc); 498 i |= ZX_SS1_MISC_ENABLE; 499 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc, i); 500 501 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wid, 0xffffffff); 502 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_widclip, 0); 503 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wmask, 0xffff); 504 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmin, 0); 505 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmax, 506 (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 16)); 507 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, 0); 508 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_planemask, 0xff000000); 509 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP); 510 511 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, 512 (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 11)); 513 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_addrspace, 514 ZX_ADDRSPC_FONT_OBGR); 515 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 0); 516 517 for (i = 0; i < 256; i++) { 518 sc->sc_cmap[i] = rasops_cmap[i * 3]; 519 sc->sc_cmap[i + 256] = rasops_cmap[i * 3 + 1]; 520 sc->sc_cmap[i + 512] = rasops_cmap[i * 3 + 2]; 521 } 522 523 zx_cmap_put(sc); 524 } 525 526 int 527 zx_cross_wait(struct zx_softc *sc) 528 { 529 int i; 530 531 for (i = 300000; i != 0; i--) { 532 if ((bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) & 533 ZX_CROSS_CSR_PROGRESS) == 0) 534 break; 535 DELAY(1); 536 } 537 538 if (i == 0) 539 printf("zx_cross_wait: timed out\n"); 540 541 return (i); 542 } 543 544 int 545 zx_cross_loadwid(struct zx_softc *sc, u_int type, u_int index, u_int value) 546 { 547 u_int tmp = 0; 548 549 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID); 550 551 if (zx_cross_wait(sc)) 552 return (1); 553 554 if (type == ZX_WID_DBL_8) 555 tmp = (index & 0x0f) + 0x40; 556 else if (type == ZX_WID_DBL_24) 557 tmp = index & 0x3f; 558 559 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, 0x5800 + tmp); 560 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, value); 561 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID); 562 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, 563 ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2); 564 565 return (0); 566 } 567 568 int 569 zx_cmap_put(struct zx_softc *sc) 570 { 571 const u_char *b; 572 u_int i, t; 573 574 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0); 575 if (zx_cross_wait(sc)) 576 return (1); 577 578 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, 579 ZX_CROSS_TYPE_CLUTDATA); 580 581 for (i = 0, b = sc->sc_cmap; i < 256; i++) { 582 t = b[i]; 583 t |= b[i + 256] << 8; 584 t |= b[i + 512] << 16; 585 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, t); 586 } 587 588 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0); 589 i = bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr); 590 i = i | ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2; 591 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, i); 592 return (0); 593 } 594 595 void 596 zx_cursor_move(struct zx_softc *sc) 597 { 598 int sx, sy, x, y; 599 600 x = sc->sc_curpos.x - sc->sc_curhot.x; 601 y = sc->sc_curpos.y - sc->sc_curhot.y; 602 603 if (x < 0) { 604 sx = min(-x, 32); 605 x = 0; 606 } else 607 sx = 0; 608 609 if (y < 0) { 610 sy = min(-y, 32); 611 y = 0; 612 } else 613 sy = 0; 614 615 if (sx != sc->sc_shiftx || sy != sc->sc_shifty) { 616 sc->sc_shiftx = sx; 617 sc->sc_shifty = sy; 618 zx_cursor_set(sc); 619 } 620 621 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_sxy, 622 ((y & 0x7ff) << 11) | (x & 0x7ff)); 623 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 624 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x30); 625 626 /* XXX Necessary? */ 627 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 628 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80); 629 } 630 631 void 632 zx_cursor_set(struct zx_softc *sc) 633 { 634 int i, j, data; 635 636 if ((sc->sc_flags & ZX_CURSOR) != 0) 637 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 638 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) & 639 ~0x80); 640 641 for (j = 0; j < 2; j++) { 642 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x20 << j); 643 644 for (i = sc->sc_shifty; i < 32; i++) { 645 data = sc->sc_curbits[j][i]; 646 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, 647 data >> sc->sc_shiftx); 648 } 649 for (i = sc->sc_shifty; i != 0; i--) 650 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, 0); 651 } 652 653 if ((sc->sc_flags & ZX_CURSOR) != 0) 654 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 655 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80); 656 } 657 658 void 659 zx_cursor_blank(struct zx_softc *sc) 660 { 661 662 sc->sc_flags &= ~ZX_CURSOR; 663 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 664 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) & ~0x80); 665 } 666 667 void 668 zx_cursor_unblank(struct zx_softc *sc) 669 { 670 671 sc->sc_flags |= ZX_CURSOR; 672 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 673 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80); 674 } 675 676 void 677 zx_cursor_color(struct zx_softc *sc) 678 { 679 u_int8_t tmp; 680 681 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x50); 682 683 tmp = sc->sc_curcmap[0] | (sc->sc_curcmap[2] << 8) | 684 (sc->sc_curcmap[4] << 16); 685 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, tmp); 686 687 tmp = sc->sc_curcmap[1] | (sc->sc_curcmap[3] << 8) | 688 (sc->sc_curcmap[5] << 16); 689 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, sc->sc_curcmap[1]); 690 691 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 692 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x03); 693 } 694 695 void 696 zx_blank(struct device *dv) 697 { 698 struct zx_softc *sc; 699 700 sc = device_private(dv); 701 702 if ((sc->sc_flags & ZX_BLANKED) != 0) 703 return; 704 sc->sc_flags |= ZX_BLANKED; 705 706 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO); 707 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, 708 bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) & 709 ~ZX_CROSS_CSR_ENABLE); 710 } 711 712 void 713 zx_unblank(struct device *dv) 714 { 715 struct zx_softc *sc; 716 717 sc = device_private(dv); 718 719 if ((sc->sc_flags & ZX_BLANKED) == 0) 720 return; 721 sc->sc_flags &= ~ZX_BLANKED; 722 723 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO); 724 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, 725 bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) | 726 ZX_CROSS_CSR_ENABLE); 727 } 728 729 paddr_t 730 zxmmap(dev_t dev, off_t off, int prot) 731 { 732 struct zx_softc *sc; 733 const struct zx_mmo *mm, *mmmax; 734 735 sc = device_lookup_private(&zx_cd, minor(dev)); 736 off = trunc_page(off); 737 mm = zx_mmo; 738 mmmax = mm + sizeof(zx_mmo) / sizeof(zx_mmo[0]); 739 740 for (; mm < mmmax; mm++) 741 if (off >= mm->mo_va && off < mm->mo_va + mm->mo_size) { 742 off = off - mm->mo_va + mm->mo_pa; 743 return (bus_space_mmap(sc->sc_bt, sc->sc_paddr, 744 off, prot, BUS_SPACE_MAP_LINEAR)); 745 } 746 747 return (-1); 748 } 749 750 void 751 zx_fillrect(struct rasops_info *ri, int x, int y, int w, int h, long attr, 752 int rop) 753 { 754 struct zx_softc *sc; 755 int fg, bg; 756 757 sc = ri->ri_hw; 758 759 rasops_unpack_attr(attr, &fg, &bg, NULL); 760 x = x * sc->sc_fontw + ri->ri_xorigin; 761 y = y * sc->sc_fonth + ri->ri_yorigin; 762 w = sc->sc_fontw * w - 1; 763 h = sc->sc_fonth * h - 1; 764 765 while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) & 766 ZX_CSR_BLT_BUSY) != 0) 767 ; 768 769 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, rop); 770 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, 771 (bg & 7) ? 0x00000000 : 0xff000000); 772 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, w | (h << 11)); 773 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fill, 774 x | (y << 11) | 0x80000000); 775 } 776 777 void 778 zx_copyrect(struct rasops_info *ri, int sx, int sy, int dx, int dy, int w, 779 int h) 780 { 781 struct zx_softc *sc; 782 int dir; 783 784 sc = ri->ri_hw; 785 786 sx = sx * sc->sc_fontw + ri->ri_xorigin; 787 sy = sy * sc->sc_fonth + ri->ri_yorigin; 788 dx = dx * sc->sc_fontw + ri->ri_xorigin; 789 dy = dy * sc->sc_fonth + ri->ri_yorigin; 790 w = w * sc->sc_fontw - 1; 791 h = h * sc->sc_fonth - 1; 792 793 if (sy < dy || sx < dx) { 794 dir = 0x80000000; 795 sx += w; 796 sy += h; 797 dx += w; 798 dy += h; 799 } else 800 dir = 0; 801 802 while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) & 803 ZX_CSR_BLT_BUSY) != 0) 804 ; 805 806 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP); 807 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, 808 w | (h << 11) | dir); 809 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_src, sx | (sy << 11)); 810 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_copy, dx | (dy << 11)); 811 } 812 813 void 814 zx_do_cursor(struct rasops_info *ri) 815 { 816 817 zx_fillrect(ri, ri->ri_ccol, ri->ri_crow, 1, 1, 0, 818 ZX_ROP_NEW_XOR_OLD | ZX_ATTR_WE_ENABLE | ZX_ATTR_OE_ENABLE | 819 ZX_ATTR_FORCE_WID); 820 } 821 822 void 823 zx_erasecols(void *cookie, int row, int col, int num, long attr) 824 { 825 struct rasops_info *ri; 826 827 ri = (struct rasops_info *)cookie; 828 829 zx_fillrect(ri, col, row, num, 1, attr, ZX_STD_ROP); 830 } 831 832 void 833 zx_eraserows(void *cookie, int row, int num, long attr) 834 { 835 struct rasops_info *ri; 836 837 ri = (struct rasops_info *)cookie; 838 839 zx_fillrect(ri, 0, row, ri->ri_cols, num, attr, ZX_STD_ROP); 840 } 841 842 void 843 zx_copyrows(void *cookie, int src, int dst, int num) 844 { 845 struct rasops_info *ri; 846 847 ri = (struct rasops_info *)cookie; 848 849 zx_copyrect(ri, 0, src, 0, dst, ri->ri_cols, num); 850 } 851 852 void 853 zx_copycols(void *cookie, int row, int src, int dst, int num) 854 { 855 struct rasops_info *ri; 856 857 ri = (struct rasops_info *)cookie; 858 859 zx_copyrect(ri, src, row, dst, row, num, 1); 860 } 861 862 void 863 zx_putchar(void *cookie, int row, int col, u_int uc, long attr) 864 { 865 struct rasops_info *ri; 866 struct zx_softc *sc; 867 struct wsdisplay_font *font; 868 volatile u_int32_t *dp; 869 u_int8_t *fb; 870 int fs, i, fg, bg, ul; 871 872 ri = (struct rasops_info *)cookie; 873 874 if (uc == ' ') { 875 zx_fillrect(ri, col, row, 1, 1, attr, ZX_STD_ROP); 876 return; 877 } 878 879 sc = (struct zx_softc *)ri->ri_hw; 880 font = ri->ri_font; 881 882 dp = (volatile u_int32_t *)sc->sc_pixels + 883 ((row * sc->sc_fonth + ri->ri_yorigin) << 11) + 884 (col * sc->sc_fontw + ri->ri_xorigin); 885 fb = (u_int8_t *)font->data + (uc - font->firstchar) * 886 ri->ri_fontscale; 887 fs = font->stride; 888 rasops_unpack_attr(attr, &fg, &bg, &ul); 889 890 while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) & 891 ZX_CSR_BLT_BUSY) != 0) 892 ; 893 894 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP); 895 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, 896 (fg & 7) ? 0x00000000 : 0xff000000); 897 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_bg, 898 (bg & 7) ? 0x00000000 : 0xff000000); 899 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk, 900 0xffffffff << (32 - sc->sc_fontw)); 901 902 if (sc->sc_fontw <= 8) { 903 for (i = sc->sc_fonth; i != 0; i--, dp += 2048) { 904 *dp = *fb << 24; 905 fb += fs; 906 } 907 } else { 908 for (i = sc->sc_fonth; i != 0; i--, dp += 2048) { 909 *dp = *((u_int16_t *)fb) << 16; 910 fb += fs; 911 } 912 } 913 914 if (ul) { 915 dp -= 4096; 916 *dp = 0xffffffff; 917 } 918 } 919