1/* $NetBSD: zx.c,v 1.47 2021/08/07 16:19:15 thorpej 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 44#include <sys/cdefs.h> 45__KERNEL_RCSID(0, "$NetBSD: zx.c,v 1.47 2021/08/07 16:19:15 thorpej Exp $"); 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/device.h> 50#include <sys/ioctl.h> 51#include <sys/malloc.h> 52#include <sys/mman.h> 53#include <sys/tty.h> 54#include <sys/conf.h> 55#include <sys/syslog.h> 56#include <sys/buf.h> 57#ifdef DEBUG 58/* for log(9) in zxioctl() */ 59#include <sys/lwp.h> 60#include <sys/proc.h> 61#endif 62 63#include <sys/bus.h> 64#include <machine/autoconf.h> 65 66#include <dev/sun/fbio.h> 67#include <dev/sun/fbvar.h> 68 69#include "wsdisplay.h" 70#include <dev/wscons/wsconsio.h> 71#include <dev/wsfont/wsfont.h> 72#include <dev/rasops/rasops.h> 73#include <dev/wscons/wsdisplay_vconsvar.h> 74 75#include "opt_wsemul.h" 76 77#include <dev/sbus/zxreg.h> 78#include <dev/sbus/zxvar.h> 79#include <dev/sbus/sbusvar.h> 80 81#include <dev/wscons/wsconsio.h> 82 83#include "ioconf.h" 84 85#define ZX_STD_ROP (ZX_ROP_NEW | ZX_ATTR_WE_ENABLE | \ 86 ZX_ATTR_OE_ENABLE | ZX_ATTR_FORCE_WID) 87 88static void zx_attach(device_t, device_t, void *); 89static int zx_match(device_t, cfdata_t, void *); 90 91static void zx_blank(device_t); 92static int zx_cmap_put(struct zx_softc *); 93static void zx_copyrect(struct zx_softc *, int, int, int, int, int, int); 94static int zx_cross_loadwid(struct zx_softc *, u_int, u_int, u_int); 95static int zx_cross_wait(struct zx_softc *); 96static void zx_fillrect(struct zx_softc *, int, int, int, int, uint32_t, int); 97static int zx_intr(void *); 98static void zx_reset(struct zx_softc *); 99static void zx_unblank(device_t); 100 101static void zx_cursor_blank(struct zx_softc *); 102static void zx_cursor_color(struct zx_softc *); 103static void zx_cursor_move(struct zx_softc *); 104static void zx_cursor_set(struct zx_softc *); 105static void zx_cursor_unblank(struct zx_softc *); 106 107static void zx_copycols(void *, int, int, int, int); 108static void zx_copyrows(void *, int, int, int); 109static void zx_do_cursor(void *, int, int, int); 110static void zx_erasecols(void *, int, int, int, long); 111static void zx_eraserows(void *, int, int, long); 112static void zx_putchar(void *, int, int, u_int, long); 113 114struct zx_mmo { 115 off_t mo_va; 116 off_t mo_pa; 117 off_t mo_size; 118} static const zx_mmo[] = { 119 { ZX_FB0_VOFF, ZX_OFF_SS0, 0x00800000 }, 120 { ZX_LC0_VOFF, ZX_OFF_LC_SS0_USR, 0x00001000 }, 121 { ZX_LD0_VOFF, ZX_OFF_LD_SS0, 0x00001000 }, 122 { ZX_LX0_CURSOR_VOFF, ZX_OFF_LX_CURSOR, 0x00001000 }, 123 { ZX_FB1_VOFF, ZX_OFF_SS1, 0x00800000 }, 124 { ZX_LC1_VOFF, ZX_OFF_LC_SS1_USR, 0x00001000 }, 125 { ZX_LD1_VOFF, ZX_OFF_LD_SS1, 0x00001000 }, 126 { ZX_LX_KRN_VOFF, ZX_OFF_LX_CROSS, 0x00001000 }, 127 { ZX_LC0_KRN_VOFF, ZX_OFF_LC_SS0_KRN, 0x00001000 }, 128 { ZX_LC1_KRN_VOFF, ZX_OFF_LC_SS1_KRN, 0x00001000 }, 129 { ZX_LD_GBL_VOFF, ZX_OFF_LD_GBL, 0x00001000 }, 130}; 131 132CFATTACH_DECL_NEW(zx, sizeof(struct zx_softc), 133 zx_match, zx_attach, NULL, NULL); 134 135static dev_type_open(zxopen); 136static dev_type_close(zxclose); 137static dev_type_ioctl(zxioctl); 138static dev_type_mmap(zxmmap); 139 140static struct fbdriver zx_fbdriver = { 141 zx_unblank, zxopen, zxclose, zxioctl, nopoll, zxmmap 142}; 143 144struct wsscreen_descr zx_defaultscreen = { 145 "std", 146 0, 0, /* will be filled in -- XXX shouldn't, it's global */ 147 /* doesn't matter - you can't really have more than one leo */ 148 NULL, /* textops */ 149 8, 16, /* font width/height */ 150 WSSCREEN_WSCOLORS, /* capabilities */ 151 NULL /* modecookie */ 152}; 153 154static int zx_ioctl(void *, void *, u_long, void *, int, struct lwp *); 155static paddr_t zx_mmap(void *, void *, off_t, int); 156static void zx_init_screen(void *, struct vcons_screen *, int, long *); 157 158static int zx_putcmap(struct zx_softc *, struct wsdisplay_cmap *); 159static int zx_getcmap(struct zx_softc *, struct wsdisplay_cmap *); 160 161struct wsdisplay_accessops zx_accessops = { 162 zx_ioctl, 163 zx_mmap, 164 NULL, /* alloc_screen */ 165 NULL, /* free_screen */ 166 NULL, /* show_screen */ 167 NULL, /* load_font */ 168 NULL, /* pollc */ 169 NULL /* scroll */ 170}; 171 172const struct wsscreen_descr *_zx_scrlist[] = { 173 &zx_defaultscreen 174}; 175 176struct wsscreen_list zx_screenlist = { 177 sizeof(_zx_scrlist) / sizeof(struct wsscreen_descr *), 178 _zx_scrlist 179}; 180 181 182extern const u_char rasops_cmap[768]; 183 184static struct vcons_screen zx_console_screen; 185 186static int 187zx_match(device_t parent, cfdata_t cf, void *aux) 188{ 189 struct sbus_attach_args *sa; 190 191 sa = (struct sbus_attach_args *)aux; 192 193 return (strcmp(sa->sa_name, "SUNW,leo") == 0); 194} 195 196static void 197zx_attach(device_t parent, device_t self, void *args) 198{ 199 struct zx_softc *sc; 200 struct sbus_attach_args *sa; 201 bus_space_handle_t bh; 202 bus_space_tag_t bt; 203 struct fbdevice *fb; 204 struct wsemuldisplaydev_attach_args aa; 205 struct rasops_info *ri = &zx_console_screen.scr_ri; 206 unsigned long defattr; 207 int isconsole, width, height; 208 209 sc = device_private(self); 210 sc->sc_dv = self; 211 212 sa = args; 213 fb = &sc->sc_fb; 214 bt = sa->sa_bustag; 215 sc->sc_bt = bt; 216 sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset); 217 218 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_SS0, 219 0x800000, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, &bh) != 0) { 220 aprint_error_dev(self, "can't map bits\n"); 221 return; 222 } 223 fb->fb_pixels = (void *)bus_space_vaddr(bt, bh); 224 sc->sc_pixels = (uint32_t *)fb->fb_pixels; 225 226 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LC_SS0_USR, 227 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 228 aprint_error_dev(self, "can't map zc\n"); 229 return; 230 } 231 232 sc->sc_bhzc = bh; 233 234 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS0, 235 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 236 aprint_error_dev(self, "can't map ld/ss0\n"); 237 return; 238 } 239 sc->sc_bhzdss0 = bh; 240 241 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS1, 242 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 243 aprint_error_dev(self, "can't map ld/ss1\n"); 244 return; 245 } 246 sc->sc_bhzdss1 = bh; 247 248 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CROSS, 249 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 250 aprint_error_dev(self, "can't map zx\n"); 251 return; 252 } 253 sc->sc_bhzx = bh; 254 255 if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CURSOR, 256 PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) { 257 aprint_error_dev(self, "can't map zcu\n"); 258 return; 259 } 260 sc->sc_bhzcu = bh; 261 262 fb->fb_driver = &zx_fbdriver; 263 fb->fb_device = sc->sc_dv; 264 fb->fb_flags = device_cfdata(sc->sc_dv)->cf_flags & FB_USERMASK; 265 fb->fb_pfour = NULL; 266 fb->fb_linebytes = prom_getpropint(sa->sa_node, "linebytes", 8192); 267 268 width = prom_getpropint(sa->sa_node, "width", 1280); 269 height = prom_getpropint(sa->sa_node, "height", 1024); 270 fb_setsize_obp(fb, 32, width, height, sa->sa_node); 271 272 fb->fb_type.fb_cmsize = 256; 273 fb->fb_type.fb_depth = 32; 274 fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes; 275 fb->fb_type.fb_type = FBTYPE_SUNLEO; 276 277 printf(": %d x %d", fb->fb_type.fb_width, fb->fb_type.fb_height); 278 isconsole = fb_is_console(sa->sa_node); 279 if (isconsole) 280 printf(" (console)"); 281 printf("\n"); 282 283 if (sa->sa_nintr != 0) 284 bus_intr_establish(bt, sa->sa_pri, IPL_NONE, zx_intr, sc); 285 286 sc->sc_cmap = malloc(768, M_DEVBUF, M_WAITOK); 287 zx_reset(sc); 288 289 sc->sc_width = fb->fb_type.fb_width; 290 sc->sc_stride = 8192; /* 32 bit */ 291 sc->sc_height = fb->fb_type.fb_height; 292 293 /* setup rasops and so on for wsdisplay */ 294 wsfont_init(); 295 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 296 sc->sc_bg = WS_DEFAULT_BG; 297 298 vcons_init(&sc->vd, sc, &zx_defaultscreen, &zx_accessops); 299 sc->vd.init_screen = zx_init_screen; 300 301 if (isconsole) { 302 /* we mess with zx_console_screen only once */ 303 vcons_init_screen(&sc->vd, &zx_console_screen, 1, 304 &defattr); 305 zx_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 306 307 zx_defaultscreen.textops = &ri->ri_ops; 308 zx_defaultscreen.capabilities = WSSCREEN_WSCOLORS; 309 zx_defaultscreen.nrows = ri->ri_rows; 310 zx_defaultscreen.ncols = ri->ri_cols; 311 zx_fillrect(sc, 0, 0, width, height, 312 ri->ri_devcmap[defattr >> 16], ZX_STD_ROP); 313 wsdisplay_cnattach(&zx_defaultscreen, ri, 0, 0, defattr); 314 vcons_replay_msgbuf(&zx_console_screen); 315 } else { 316 /* 317 * we're not the console so we just clear the screen and don't 318 * set up any sort of text display 319 */ 320 if (zx_defaultscreen.textops == NULL) { 321 /* 322 * ugly, but... 323 * we want the console settings to win, so we only 324 * touch anything when we find an untouched screen 325 * definition. In this case we fill it from fb to 326 * avoid problems in case no zx is the console 327 */ 328 zx_defaultscreen.textops = &ri->ri_ops; 329 zx_defaultscreen.capabilities = ri->ri_caps; 330 zx_defaultscreen.nrows = ri->ri_rows; 331 zx_defaultscreen.ncols = ri->ri_cols; 332 } 333 } 334 335 aa.scrdata = &zx_screenlist; 336 aa.console = isconsole; 337 aa.accessops = &zx_accessops; 338 aa.accesscookie = &sc->vd; 339 config_found(sc->sc_dv, &aa, wsemuldisplaydevprint, CFARGS_NONE); 340 fb_attach(&sc->sc_fb, isconsole); 341} 342 343static int 344zxopen(dev_t dev, int flags, int mode, struct lwp *l) 345{ 346 347 if (device_lookup(&zx_cd, minor(dev)) == NULL) 348 return (ENXIO); 349 return (0); 350} 351 352static int 353zxclose(dev_t dev, int flags, int mode, struct lwp *l) 354{ 355 struct zx_softc *sc; 356 357 sc = device_lookup_private(&zx_cd, minor(dev)); 358 359 zx_reset(sc); 360 zx_cursor_blank(sc); 361 return (0); 362} 363 364static int 365zxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 366{ 367 struct zx_softc *sc; 368 struct fbcmap *cm; 369 struct fbcursor *cu; 370 uint32_t curbits[2][32]; 371 int rv, v, count, i, error; 372 373 sc = device_lookup_private(&zx_cd, minor(dev)); 374 375 switch (cmd) { 376 case FBIOGTYPE: 377 *(struct fbtype *)data = sc->sc_fb.fb_type; 378 break; 379 380 case FBIOGATTR: 381#define fba ((struct fbgattr *)data) 382 fba->real_type = sc->sc_fb.fb_type.fb_type; 383 fba->owner = 0; /* XXX ??? */ 384 fba->fbtype = sc->sc_fb.fb_type; 385 fba->sattr.flags = 0; 386 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 387 fba->sattr.dev_specific[0] = -1; 388 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 389 fba->emu_types[1] = -1; 390 fba->emu_types[2] = -1; 391#undef fba 392 break; 393 394 case FBIOGVIDEO: 395 *(int *)data = ((sc->sc_flags & ZX_BLANKED) != 0); 396 break; 397 398 case FBIOSVIDEO: 399 if (*(int *)data) 400 zx_unblank(sc->sc_dv); 401 else 402 zx_blank(sc->sc_dv); 403 break; 404 405 case FBIOGETCMAP: 406 cm = (struct fbcmap *)data; 407 if (cm->index > 256 || cm->count > 256 - cm->index) 408 return (EINVAL); 409 rv = copyout(sc->sc_cmap + cm->index, cm->red, cm->count); 410 if (rv == 0) 411 rv = copyout(sc->sc_cmap + 256 + cm->index, cm->green, 412 cm->count); 413 if (rv == 0) 414 rv = copyout(sc->sc_cmap + 512 + cm->index, cm->blue, 415 cm->count); 416 return (rv); 417 418 case FBIOPUTCMAP: 419 cm = (struct fbcmap *)data; 420 if (cm->index > 256 || cm->count > 256 - cm->index) 421 return (EINVAL); 422 rv = copyin(cm->red, sc->sc_cmap + cm->index, cm->count); 423 if (rv == 0) 424 rv = copyin(cm->green, sc->sc_cmap + 256 + cm->index, 425 cm->count); 426 if (rv == 0) 427 rv = copyin(cm->blue, sc->sc_cmap + 512 + cm->index, 428 cm->count); 429 zx_cmap_put(sc); 430 return (rv); 431 432 case FBIOGCURPOS: 433 *(struct fbcurpos *)data = sc->sc_curpos; 434 break; 435 436 case FBIOSCURPOS: 437 sc->sc_curpos = *(struct fbcurpos *)data; 438 zx_cursor_move(sc); 439 break; 440 441 case FBIOGCURMAX: 442 ((struct fbcurpos *)data)->x = 32; 443 ((struct fbcurpos *)data)->y = 32; 444 break; 445 446 case FBIOSCURSOR: 447 cu = (struct fbcursor *)data; 448 v = cu->set; 449 450 if ((v & FB_CUR_SETSHAPE) != 0) { 451 if ((u_int)cu->size.x > 32 || (u_int)cu->size.y > 32) 452 return (EINVAL); 453 count = cu->size.y * 4; 454 rv = copyin(cu->mask, curbits[0], count); 455 if (rv) 456 return rv; 457 rv = copyin(cu->image, curbits[1], count); 458 if (rv) 459 return rv; 460 } 461 if ((v & FB_CUR_SETCUR) != 0) { 462 if (cu->enable) 463 zx_cursor_unblank(sc); 464 else 465 zx_cursor_blank(sc); 466 } 467 if ((v & (FB_CUR_SETPOS | FB_CUR_SETHOT)) != 0) { 468 if ((v & FB_CUR_SETPOS) != 0) 469 sc->sc_curpos = cu->pos; 470 if ((v & FB_CUR_SETHOT) != 0) 471 sc->sc_curhot = cu->hot; 472 zx_cursor_move(sc); 473 } 474 if ((v & FB_CUR_SETCMAP) != 0) { 475 if (cu->cmap.index > 2 || 476 cu->cmap.count > 2 - cu->cmap.index) 477 return (EINVAL); 478 479 uint8_t red[2], green[2], blue[2]; 480 const u_int cnt = cu->cmap.count; 481 482 if (cnt && 483 ((error = copyin(cu->cmap.red, red, cnt)) || 484 (error = copyin(cu->cmap.green, green, cnt)) || 485 (error = copyin(cu->cmap.blue, blue, cnt)))) { 486 return error; 487 } 488 489 for (i = 0; i < cnt; i++) { 490 sc->sc_curcmap[i + cu->cmap.index + 0] = 491 red[i]; 492 sc->sc_curcmap[i + cu->cmap.index + 2] = 493 green[i]; 494 sc->sc_curcmap[i + cu->cmap.index + 4] = 495 blue[i]; 496 } 497 zx_cursor_color(sc); 498 } 499 if ((v & FB_CUR_SETSHAPE) != 0) { 500 sc->sc_cursize = cu->size; 501 count = cu->size.y * 4; 502 memset(sc->sc_curbits, 0, sizeof(sc->sc_curbits)); 503 memcpy(sc->sc_curbits[0], curbits[0], count); 504 memcpy(sc->sc_curbits[1], curbits[1], count); 505 zx_cursor_set(sc); 506 } 507 break; 508 509 case FBIOGCURSOR: 510 cu = (struct fbcursor *)data; 511 512 cu->set = FB_CUR_SETALL; 513 cu->enable = ((sc->sc_flags & ZX_CURSOR) != 0); 514 cu->pos = sc->sc_curpos; 515 cu->hot = sc->sc_curhot; 516 cu->size = sc->sc_cursize; 517 518 if (cu->image != NULL) { 519 count = sc->sc_cursize.y * 4; 520 rv = copyout(sc->sc_curbits[1], cu->image, count); 521 if (rv) 522 return (rv); 523 rv = copyout(sc->sc_curbits[0], cu->mask, count); 524 if (rv) 525 return (rv); 526 } 527 if (cu->cmap.red != NULL) { 528 uint8_t red[2], green[2], blue[2]; 529 const uint8_t *ccm = sc->sc_curcmap; 530 cm = &cu->cmap; 531 532 if (cm->index > 2 || cm->count > 2 - cm->index) 533 return EINVAL; 534 535 for (i = 0; i < cm->count; i++) { 536 red[i] = ccm[i + cm->index + 0]; 537 green[i] = ccm[i + cm->index + 2]; 538 blue[i] = ccm[i + cm->index + 4]; 539 } 540 541 if ((error = copyout(red, cm->red, cm->count)) || 542 (error = copyout(green, cm->green, cm->count)) || 543 (error = copyout(blue, cm->blue, cm->count))) 544 return error; 545 } else { 546 cu->cmap.index = 0; 547 cu->cmap.count = 2; 548 } 549 break; 550 551 default: 552#ifdef DEBUG 553 log(LOG_NOTICE, "zxioctl(0x%lx) (%s[%d])\n", cmd, 554 l->l_proc->p_comm, l->l_proc->p_pid); 555#endif 556 return (ENOTTY); 557 } 558 559 return (0); 560} 561 562static int 563zx_intr(void *cookie) 564{ 565 566 return (1); 567} 568 569static void 570zx_reset(struct zx_softc *sc) 571{ 572 struct fbtype *fbt; 573 u_int i; 574 575 fbt = &sc->sc_fb.fb_type; 576 577 zx_cross_loadwid(sc, ZX_WID_DBL_8, 0, 0x2c0); 578 zx_cross_loadwid(sc, ZX_WID_DBL_8, 1, 0x30); 579 zx_cross_loadwid(sc, ZX_WID_DBL_8, 2, 0x20); 580 zx_cross_loadwid(sc, ZX_WID_DBL_24, 1, 0x30); 581 582 i = bus_space_read_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc); 583 i |= ZX_SS1_MISC_ENABLE; 584 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc, i); 585 586 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wid, 1); 587 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_widclip, 0); 588 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wmask, 0xffff); 589 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmin, 0); 590 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmax, 591 (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 16)); 592 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, 0); 593 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_planemask, 0xffffffff); 594 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP); 595 596 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, 597 (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 11)); 598 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_addrspace, 599 ZX_ADDRSPC_FONT_OBGR); 600 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 0); 601 602 for (i = 0; i < 256; i++) { 603 sc->sc_cmap[i] = rasops_cmap[i * 3]; 604 sc->sc_cmap[i + 256] = rasops_cmap[i * 3 + 1]; 605 sc->sc_cmap[i + 512] = rasops_cmap[i * 3 + 2]; 606 } 607 608 zx_cmap_put(sc); 609} 610 611static int 612zx_cross_wait(struct zx_softc *sc) 613{ 614 int i; 615 616 for (i = 300000; i != 0; i--) { 617 if ((bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) & 618 ZX_CROSS_CSR_PROGRESS) == 0) 619 break; 620 DELAY(1); 621 } 622 623 if (i == 0) 624 printf("zx_cross_wait: timed out\n"); 625 626 return (i); 627} 628 629static int 630zx_cross_loadwid(struct zx_softc *sc, u_int type, u_int index, u_int value) 631{ 632 u_int tmp = 0; 633 634 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID); 635 636 if (zx_cross_wait(sc)) 637 return (1); 638 639 if (type == ZX_WID_DBL_8) 640 tmp = (index & 0x0f) + 0x40; 641 else if (type == ZX_WID_DBL_24) 642 tmp = index & 0x3f; 643 644 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, 0x5800 + tmp); 645 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, value); 646 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID); 647 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, 648 ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2); 649 650 return (0); 651} 652 653static int 654zx_cmap_put(struct zx_softc *sc) 655{ 656 const u_char *b; 657 u_int i, t; 658 659 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0); 660 661 zx_cross_wait(sc); 662 663 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, 664 ZX_CROSS_TYPE_CLUTDATA); 665 666 for (i = 0, b = sc->sc_cmap; i < 256; i++) { 667 t = b[i]; 668 t |= b[i + 256] << 8; 669 t |= b[i + 512] << 16; 670 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, t); 671 } 672 673 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0); 674 i = bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr); 675 i = i | ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2; 676 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, i); 677 return (0); 678} 679 680static void 681zx_cursor_move(struct zx_softc *sc) 682{ 683 int sx, sy, x, y; 684 685 x = sc->sc_curpos.x - sc->sc_curhot.x; 686 y = sc->sc_curpos.y - sc->sc_curhot.y; 687 688 if (x < 0) { 689 sx = uimin(-x, 32); 690 x = 0; 691 } else 692 sx = 0; 693 694 if (y < 0) { 695 sy = uimin(-y, 32); 696 y = 0; 697 } else 698 sy = 0; 699 700 if (sx != sc->sc_shiftx || sy != sc->sc_shifty) { 701 sc->sc_shiftx = sx; 702 sc->sc_shifty = sy; 703 zx_cursor_set(sc); 704 } 705 706 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_sxy, 707 ((y & 0x7ff) << 11) | (x & 0x7ff)); 708 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 709 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x30); 710 711 /* XXX Necessary? */ 712 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 713 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80); 714} 715 716static void 717zx_cursor_set(struct zx_softc *sc) 718{ 719 int i, j, data; 720 721 if ((sc->sc_flags & ZX_CURSOR) != 0) 722 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 723 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) & 724 ~0x80); 725 726 for (j = 0; j < 2; j++) { 727 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x20 << j); 728 729 for (i = sc->sc_shifty; i < 32; i++) { 730 data = sc->sc_curbits[j][i]; 731 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, 732 data >> sc->sc_shiftx); 733 } 734 for (i = sc->sc_shifty; i != 0; i--) 735 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, 0); 736 } 737 738 if ((sc->sc_flags & ZX_CURSOR) != 0) 739 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 740 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80); 741} 742 743static void 744zx_cursor_blank(struct zx_softc *sc) 745{ 746 747 sc->sc_flags &= ~ZX_CURSOR; 748 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 749 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) & ~0x80); 750} 751 752static void 753zx_cursor_unblank(struct zx_softc *sc) 754{ 755 756 sc->sc_flags |= ZX_CURSOR; 757 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 758 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80); 759} 760 761static void 762zx_cursor_color(struct zx_softc *sc) 763{ 764 uint8_t tmp; 765 766 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x50); 767 768 tmp = sc->sc_curcmap[0] | (sc->sc_curcmap[2] << 8) | 769 (sc->sc_curcmap[4] << 16); 770 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, tmp); 771 772 tmp = sc->sc_curcmap[1] | (sc->sc_curcmap[3] << 8) | 773 (sc->sc_curcmap[5] << 16); 774 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, tmp); 775 776 bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc, 777 bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x03); 778} 779 780static void 781zx_blank(device_t dv) 782{ 783 struct zx_softc *sc; 784 785 sc = device_private(dv); 786 787 if ((sc->sc_flags & ZX_BLANKED) != 0) 788 return; 789 sc->sc_flags |= ZX_BLANKED; 790 791 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO); 792 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, 793 bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) & 794 ~ZX_CROSS_CSR_ENABLE); 795} 796 797static void 798zx_unblank(device_t dv) 799{ 800 struct zx_softc *sc; 801 802 sc = device_private(dv); 803 804 if ((sc->sc_flags & ZX_BLANKED) == 0) 805 return; 806 sc->sc_flags &= ~ZX_BLANKED; 807 808 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO); 809 bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, 810 bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) | 811 ZX_CROSS_CSR_ENABLE); 812} 813 814static paddr_t 815zxmmap(dev_t dev, off_t off, int prot) 816{ 817 struct zx_softc *sc; 818 const struct zx_mmo *mm, *mmmax; 819 820 sc = device_lookup_private(&zx_cd, minor(dev)); 821 off = trunc_page(off); 822 mm = zx_mmo; 823 mmmax = mm + sizeof(zx_mmo) / sizeof(zx_mmo[0]); 824 825 for (; mm < mmmax; mm++) 826 if (off >= mm->mo_va && off < mm->mo_va + mm->mo_size) { 827 off = off - mm->mo_va + mm->mo_pa; 828 return (bus_space_mmap(sc->sc_bt, sc->sc_paddr, 829 off, prot, BUS_SPACE_MAP_LINEAR)); 830 } 831 832 return (-1); 833} 834 835static void 836zx_fillrect(struct zx_softc *sc, int x, int y, int w, int h, uint32_t bg, 837 int rop) 838{ 839 840 841 while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) & 842 ZX_CSR_BLT_BUSY) != 0) 843 ; 844 845 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, rop); 846 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, bg); 847 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, 848 (w - 1) | ((h - 1) << 11)); 849 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fill, 850 x | (y << 11) | 0x80000000); 851} 852 853static void 854zx_copyrect(struct zx_softc *sc, int sx, int sy, int dx, int dy, int w, 855 int h) 856{ 857 uint32_t dir; 858 859 w -= 1; 860 h -= 1; 861 862 if (sy < dy || sx < dx) { 863 dir = 0x80000000; 864 sx += w; 865 sy += h; 866 dx += w; 867 dy += h; 868 } else 869 dir = 0; 870 871 while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) & 872 ZX_CSR_BLT_BUSY) != 0) 873 ; 874 875 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP); 876 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, 877 w | (h << 11) | dir); 878 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_src, sx | (sy << 11)); 879 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_copy, dx | (dy << 11)); 880} 881 882static void 883zx_do_cursor(void *cookie, int on, int row, int col) 884{ 885 struct rasops_info *ri = cookie; 886 struct vcons_screen *scr = ri->ri_hw; 887 struct zx_softc *sc = scr->scr_cookie; 888 int x, y, wi, he; 889 890 wi = ri->ri_font->fontwidth; 891 he = ri->ri_font->fontheight; 892 893 if (ri->ri_flg & RI_CURSOR) { 894 x = ri->ri_ccol * wi + ri->ri_xorigin; 895 y = ri->ri_crow * he + ri->ri_yorigin; 896 zx_fillrect(sc, x, y, wi, he, 0xff000000, 897 ZX_ROP_NEW_XOR_OLD | ZX_ATTR_WE_ENABLE | ZX_ATTR_OE_ENABLE | 898 ZX_ATTR_FORCE_WID); 899 ri->ri_flg &= ~RI_CURSOR; 900 } 901 902 ri->ri_crow = row; 903 ri->ri_ccol = col; 904 905 if (on) 906 { 907 x = ri->ri_ccol * wi + ri->ri_xorigin; 908 y = ri->ri_crow * he + ri->ri_yorigin; 909 zx_fillrect(sc, x, y, wi, he, 0xff000000, 910 ZX_ROP_NEW_XOR_OLD | ZX_ATTR_WE_ENABLE | ZX_ATTR_OE_ENABLE | 911 ZX_ATTR_FORCE_WID); 912 ri->ri_flg |= RI_CURSOR; 913 } 914} 915 916static void 917zx_erasecols(void *cookie, int row, int startcol, int ncols, long attr) 918{ 919 struct rasops_info *ri = cookie; 920 struct vcons_screen *scr = ri->ri_hw; 921 struct zx_softc *sc = scr->scr_cookie; 922 int32_t x, y, width, height, bg; 923 924 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 925 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 926 width = ri->ri_font->fontwidth * ncols; 927 height = ri->ri_font->fontheight; 928 bg = ((uint32_t)ri->ri_devcmap[(attr >> 16) & 0xff]) << 24; 929 zx_fillrect(sc, x, y, width, height, bg, ZX_STD_ROP); 930} 931 932static void 933zx_eraserows(void *cookie, int row, int nrows, long attr) 934{ 935 struct rasops_info *ri = cookie; 936 struct vcons_screen *scr = ri->ri_hw; 937 struct zx_softc *sc = scr->scr_cookie; 938 int32_t x, y, width, height, bg; 939 940 if ((row == 0) && (nrows == ri->ri_rows)) { 941 x = y = 0; 942 width = ri->ri_width; 943 height = ri->ri_height; 944 } else { 945 x = ri->ri_xorigin; 946 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 947 width = ri->ri_emuwidth; 948 height = ri->ri_font->fontheight * nrows; 949 } 950 bg = ((uint32_t)ri->ri_devcmap[(attr >> 16) & 0xff]) << 24; 951 zx_fillrect(sc, x, y, width, height, bg, ZX_STD_ROP); 952} 953 954static void 955zx_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 956{ 957 struct rasops_info *ri = cookie; 958 struct vcons_screen *scr = ri->ri_hw; 959 struct zx_softc *sc = scr->scr_cookie; 960 int32_t x, ys, yd, width, height; 961 962 x = ri->ri_xorigin; 963 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 964 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 965 width = ri->ri_emuwidth; 966 height = ri->ri_font->fontheight * nrows; 967 zx_copyrect(sc, x, ys, x, yd, width, height); 968} 969 970static void 971zx_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 972{ 973 struct rasops_info *ri = cookie; 974 struct vcons_screen *scr = ri->ri_hw; 975 struct zx_softc *sc = scr->scr_cookie; 976 int32_t xs, xd, y, width, height; 977 978 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 979 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 980 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 981 width = ri->ri_font->fontwidth * ncols; 982 height = ri->ri_font->fontheight; 983 zx_copyrect(sc, xs, y, xd, y, width, height); 984} 985 986static void 987zx_putchar(void *cookie, int row, int col, u_int uc, long attr) 988{ 989 struct rasops_info *ri = cookie; 990 struct wsdisplay_font *font = PICK_FONT(ri, uc); 991 struct vcons_screen *scr = ri->ri_hw; 992 struct zx_softc *sc = scr->scr_cookie; 993 volatile uint32_t *dp; 994 uint8_t *fb; 995 int fs, i, ul; 996 uint32_t fg, bg; 997 998 rasops_unpack_attr(attr, &fg, &bg, &ul); 999 bg = ((uint32_t)ri->ri_devcmap[bg]) << 24; 1000 fg = ((uint32_t)ri->ri_devcmap[fg]) << 24; 1001 if (uc == ' ') { 1002 int x, y; 1003 1004 x = ri->ri_xorigin + font->fontwidth * col; 1005 y = ri->ri_yorigin + font->fontheight * row; 1006 zx_fillrect(sc, x, y, font->fontwidth, 1007 font->fontheight, bg, ZX_STD_ROP); 1008 return; 1009 } 1010 1011 dp = (volatile uint32_t *)sc->sc_pixels + 1012 ((row * font->fontheight + ri->ri_yorigin) << 11) + 1013 (col * font->fontwidth + ri->ri_xorigin); 1014 fb = (uint8_t *)font->data + (uc - font->firstchar) * 1015 ri->ri_fontscale; 1016 fs = font->stride; 1017 1018 while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) & 1019 ZX_CSR_BLT_BUSY) != 0) 1020 ; 1021 1022 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP); 1023 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, fg); 1024 bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_bg, bg); 1025 bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk, 1026 0xffffffff << (32 - font->fontwidth)); 1027 1028 if (font->fontwidth <= 8) { 1029 for (i = font->fontheight; i != 0; i--, dp += 2048) { 1030 *dp = *fb << 24; 1031 fb += fs; 1032 } 1033 } else { 1034 for (i = font->fontheight; i != 0; i--, dp += 2048) { 1035 *dp = *((uint16_t *)fb) << 16; 1036 fb += fs; 1037 } 1038 } 1039 1040 if (ul) { 1041 dp -= 4096; 1042 *dp = 0xffffffff; 1043 } 1044} 1045 1046static int 1047zx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 1048 struct lwp *l) 1049{ 1050 /* we'll probably need to add more stuff here */ 1051 struct vcons_data *vd = v; 1052 struct zx_softc *sc = vd->cookie; 1053 struct wsdisplay_fbinfo *wdf; 1054 struct vcons_screen *ms = sc->vd.active; 1055 struct rasops_info *ri = &ms->scr_ri; 1056 switch (cmd) { 1057 case WSDISPLAYIO_GTYPE: 1058 *(u_int *)data = WSDISPLAY_TYPE_SUNTCX; 1059 return 0; 1060 case WSDISPLAYIO_GINFO: 1061 wdf = (void *)data; 1062 wdf->height = ri->ri_height; 1063 wdf->width = ri->ri_width; 1064 wdf->depth = ri->ri_depth; 1065 wdf->cmsize = 256; 1066 return 0; 1067 1068 case WSDISPLAYIO_GETCMAP: 1069 return zx_getcmap(sc, 1070 (struct wsdisplay_cmap *)data); 1071 case WSDISPLAYIO_PUTCMAP: 1072 return zx_putcmap(sc, 1073 (struct wsdisplay_cmap *)data); 1074 1075 case WSDISPLAYIO_SMODE: 1076 { 1077 int new_mode = *(int*)data; 1078 if (new_mode != sc->sc_mode) 1079 { 1080 sc->sc_mode = new_mode; 1081 if(new_mode == WSDISPLAYIO_MODE_EMUL) 1082 { 1083 zx_reset(sc); 1084 vcons_redraw_screen(ms); 1085 } 1086 } 1087 } 1088 return 0; 1089 } 1090 return EPASSTHROUGH; 1091} 1092 1093static paddr_t 1094zx_mmap(void *v, void *vs, off_t offset, int prot) 1095{ 1096 /* I'm not at all sure this is the right thing to do */ 1097 return zxmmap(0, offset, prot); /* assume minor dev 0 for now */ 1098} 1099 1100static int 1101zx_putcmap(struct zx_softc *sc, struct wsdisplay_cmap *cm) 1102{ 1103 u_int index = cm->index; 1104 u_int count = cm->count; 1105 int error,i; 1106 if (index >= 256 || count > 256 || index + count > 256) 1107 return EINVAL; 1108 1109 for (i = 0; i < count; i++) 1110 { 1111 error = copyin(&cm->red[i], 1112 &sc->sc_cmap[index + i], 1); 1113 if (error) 1114 return error; 1115 error = copyin(&cm->green[i], 1116 &sc->sc_cmap[index + i + 256], 1); 1117 if (error) 1118 return error; 1119 error = copyin(&cm->blue[i], 1120 &sc->sc_cmap[index + i + 512], 1); 1121 if (error) 1122 return error; 1123 } 1124 zx_cmap_put(sc); 1125 1126 return 0; 1127} 1128 1129static int 1130zx_getcmap(struct zx_softc *sc, struct wsdisplay_cmap *cm) 1131{ 1132 u_int index = cm->index; 1133 u_int count = cm->count; 1134 int error,i; 1135 1136 if (index >= 256 || count > 256 || index + count > 256) 1137 return EINVAL; 1138 1139 for (i = 0; i < count; i++) 1140 { 1141 error = copyout(&sc->sc_cmap[index + i], 1142 &cm->red[i], 1); 1143 if (error) 1144 return error; 1145 error = copyout(&sc->sc_cmap[index + i + 256], 1146 &cm->green[i], 1); 1147 if (error) 1148 return error; 1149 error = copyout(&sc->sc_cmap[index + i + 256], 1150 &cm->blue[i], 1); 1151 if (error) 1152 return error; 1153 } 1154 1155 return 0; 1156} 1157 1158static void 1159zx_init_screen(void *cookie, struct vcons_screen *scr, 1160 int existing, long *defattr) 1161{ 1162 struct zx_softc *sc = cookie; 1163 struct rasops_info *ri = &scr->scr_ri; 1164 1165 ri->ri_depth = 8; /*sc->sc_fb.fb_type.fb_depth = 32;*/ 1166 ri->ri_width = sc->sc_width; 1167 ri->ri_height = sc->sc_height; 1168 ri->ri_stride = sc->sc_stride; 1169 ri->ri_flg = RI_CENTER; 1170 1171 ri->ri_bits = (void *)sc->sc_pixels; 1172 1173 rasops_init(ri, 0, 0); 1174 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; 1175 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 1176 sc->sc_width / ri->ri_font->fontwidth); 1177 1178 ri->ri_hw = scr; 1179 1180 ri->ri_ops.cursor = zx_do_cursor; 1181 ri->ri_ops.copycols = zx_copycols; 1182 ri->ri_ops.copyrows = zx_copyrows; 1183 ri->ri_ops.erasecols = zx_erasecols; 1184 ri->ri_ops.eraserows = zx_eraserows; 1185 ri->ri_ops.putchar = zx_putchar; 1186} 1187