1 /* $OpenBSD: cgsix.c,v 1.60 2020/05/25 09:55:49 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Jason L. Wright (jason@thought.net) 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Effort sponsored in part by the Defense Advanced Research Projects 29 * Agency (DARPA) and Air Force Research Laboratory, Air Force 30 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 31 * 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/errno.h> 38 #include <sys/device.h> 39 #include <sys/ioctl.h> 40 #include <sys/malloc.h> 41 42 #include <machine/bus.h> 43 #include <machine/intr.h> 44 #include <machine/autoconf.h> 45 #include <machine/openfirm.h> 46 47 #include <dev/sbus/sbusvar.h> 48 #include <dev/wscons/wsconsio.h> 49 #include <dev/wscons/wsdisplayvar.h> 50 #include <dev/rasops/rasops.h> 51 #include <machine/fbvar.h> 52 #include <dev/sbus/cgsixreg.h> 53 #include <dev/ic/bt458reg.h> 54 55 int cgsix_ioctl(void *, u_long, caddr_t, int, struct proc *); 56 paddr_t cgsix_mmap(void *, off_t, int); 57 int cgsix_is_console(int); 58 int cg6_bt_getcmap(union bt_cmap *, struct wsdisplay_cmap *); 59 int cg6_bt_putcmap(union bt_cmap *, struct wsdisplay_cmap *); 60 void cgsix_loadcmap_immediate(struct cgsix_softc *, u_int, u_int); 61 void cgsix_loadcmap_deferred(struct cgsix_softc *, u_int, u_int); 62 void cgsix_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 63 void cgsix_reset(struct cgsix_softc *, u_int32_t); 64 void cgsix_hardreset(struct cgsix_softc *); 65 void cgsix_burner(void *, u_int, u_int); 66 int cgsix_intr(void *); 67 void cgsix_ras_init(struct cgsix_softc *); 68 int cgsix_ras_copyrows(void *, int, int, int); 69 int cgsix_ras_copycols(void *, int, int, int, int); 70 int cgsix_ras_erasecols(void *, int, int, int, uint32_t); 71 int cgsix_ras_eraserows(void *, int, int, uint32_t); 72 int cgsix_ras_do_cursor(struct rasops_info *); 73 int cgsix_setcursor(struct cgsix_softc *, struct wsdisplay_cursor *); 74 int cgsix_updatecursor(struct cgsix_softc *, u_int); 75 76 struct wsdisplay_accessops cgsix_accessops = { 77 .ioctl = cgsix_ioctl, 78 .mmap = cgsix_mmap, 79 .burn_screen = cgsix_burner 80 }; 81 82 int cgsixmatch(struct device *, void *, void *); 83 void cgsixattach(struct device *, struct device *, void *); 84 85 struct cfattach cgsix_ca = { 86 sizeof (struct cgsix_softc), cgsixmatch, cgsixattach 87 }; 88 89 struct cfdriver cgsix_cd = { 90 NULL, "cgsix", DV_DULL 91 }; 92 93 int 94 cgsixmatch(struct device *parent, void *vcf, void *aux) 95 { 96 struct cfdata *cf = vcf; 97 struct sbus_attach_args *sa = aux; 98 99 return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0); 100 } 101 102 void 103 cgsixattach(struct device *parent, struct device *self, void *aux) 104 { 105 struct cgsix_softc *sc = (struct cgsix_softc *)self; 106 struct sbus_attach_args *sa = aux; 107 int node, console; 108 u_int32_t fhc, rev; 109 const char *nam; 110 111 node = sa->sa_node; 112 sc->sc_bustag = sa->sa_bustag; 113 sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, sa->sa_offset); 114 115 if (sa->sa_nreg != 1) { 116 printf(": expected %d registers, got %d\n", 1, sa->sa_nreg); 117 goto fail; 118 } 119 120 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 121 122 /* 123 * Map just BT, FHC, FBC, THC, and video RAM. 124 */ 125 if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, 126 sa->sa_reg[0].sbr_offset + CGSIX_BT_OFFSET, 127 CGSIX_BT_SIZE, 0, 0, &sc->sc_bt_regs) != 0) { 128 printf(": cannot map bt registers\n"); 129 goto fail_bt; 130 } 131 132 if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, 133 sa->sa_reg[0].sbr_offset + CGSIX_FHC_OFFSET, 134 CGSIX_FHC_SIZE, 0, 0, &sc->sc_fhc_regs) != 0) { 135 printf(": cannot map fhc registers\n"); 136 goto fail_fhc; 137 } 138 139 if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, 140 sa->sa_reg[0].sbr_offset + CGSIX_THC_OFFSET, 141 CGSIX_THC_SIZE, 0, 0, &sc->sc_thc_regs) != 0) { 142 printf(": cannot map thc registers\n"); 143 goto fail_thc; 144 } 145 146 if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, 147 sa->sa_reg[0].sbr_offset + CGSIX_VID_OFFSET, 148 sc->sc_sunfb.sf_fbsize, BUS_SPACE_MAP_LINEAR, 149 0, &sc->sc_vid_regs) != 0) { 150 printf(": cannot map vid registers\n"); 151 goto fail_vid; 152 } 153 154 if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, 155 sa->sa_reg[0].sbr_offset + CGSIX_TEC_OFFSET, 156 CGSIX_TEC_SIZE, 0, 0, &sc->sc_tec_regs) != 0) { 157 printf(": cannot map tec registers\n"); 158 goto fail_tec; 159 } 160 161 if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, 162 sa->sa_reg[0].sbr_offset + CGSIX_FBC_OFFSET, 163 CGSIX_FBC_SIZE, 0, 0, &sc->sc_fbc_regs) != 0) { 164 printf(": cannot map fbc registers\n"); 165 goto fail_fbc; 166 } 167 168 if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri, 169 IPL_TTY, 0, cgsix_intr, sc, self->dv_xname)) == NULL) { 170 printf(": couldn't establish interrupt, pri %d\n%s", 171 INTLEV(sa->sa_pri), self->dv_xname); 172 } 173 174 /* if prom didn't initialize us, do it the hard way */ 175 if (OF_getproplen(node, "width") != sizeof(u_int32_t)) 176 cgsix_hardreset(sc); 177 178 nam = getpropstring(node, "model"); 179 if (*nam == '\0') 180 nam = sa->sa_name; 181 printf(": %s", nam); 182 183 console = cgsix_is_console(node); 184 185 fhc = FHC_READ(sc); 186 rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT; 187 cgsix_reset(sc, rev); 188 189 cgsix_burner(sc, 1, 0); 190 191 sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bustag, 192 sc->sc_vid_regs); 193 sc->sc_sunfb.sf_ro.ri_hw = sc; 194 195 printf(", %dx%d, rev %d\n", sc->sc_sunfb.sf_width, 196 sc->sc_sunfb.sf_height, rev); 197 198 fbwscons_init(&sc->sc_sunfb, 0, console); 199 fbwscons_setcolormap(&sc->sc_sunfb, cgsix_setcolor); 200 201 /* 202 * Old rev. cg6 cards do not like the current acceleration code. 203 * 204 * Some hints from Sun point out at timing and cache problems, which 205 * will be investigated later. 206 */ 207 if (rev < 5) 208 sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags |= CG6_CFFLAG_NOACCEL; 209 210 if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CG6_CFFLAG_NOACCEL) 211 == 0) { 212 sc->sc_sunfb.sf_ro.ri_ops.copyrows = cgsix_ras_copyrows; 213 sc->sc_sunfb.sf_ro.ri_ops.copycols = cgsix_ras_copycols; 214 sc->sc_sunfb.sf_ro.ri_ops.eraserows = cgsix_ras_eraserows; 215 sc->sc_sunfb.sf_ro.ri_ops.erasecols = cgsix_ras_erasecols; 216 sc->sc_sunfb.sf_ro.ri_do_cursor = cgsix_ras_do_cursor; 217 cgsix_ras_init(sc); 218 } 219 220 if (console) 221 fbwscons_console_init(&sc->sc_sunfb, -1); 222 223 fbwscons_attach(&sc->sc_sunfb, &cgsix_accessops, console); 224 225 return; 226 227 fail_fbc: 228 bus_space_unmap(sa->sa_bustag, sc->sc_tec_regs, CGSIX_TEC_SIZE); 229 fail_tec: 230 bus_space_unmap(sa->sa_bustag, sc->sc_vid_regs, sc->sc_sunfb.sf_fbsize); 231 fail_vid: 232 bus_space_unmap(sa->sa_bustag, sc->sc_thc_regs, CGSIX_THC_SIZE); 233 fail_thc: 234 bus_space_unmap(sa->sa_bustag, sc->sc_fhc_regs, CGSIX_FHC_SIZE); 235 fail_fhc: 236 bus_space_unmap(sa->sa_bustag, sc->sc_bt_regs, CGSIX_BT_SIZE); 237 fail_bt: 238 fail: 239 return; 240 } 241 242 int 243 cgsix_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 244 { 245 struct cgsix_softc *sc = v; 246 struct wsdisplay_cmap *cm; 247 struct wsdisplay_fbinfo *wdf; 248 struct wsdisplay_cursor *curs; 249 struct wsdisplay_curpos *pos; 250 u_char r[2], g[2], b[2]; 251 int error, s; 252 u_int mode; 253 254 switch (cmd) { 255 case WSDISPLAYIO_GTYPE: 256 *(u_int *)data = WSDISPLAY_TYPE_SUNCG6; 257 break; 258 case WSDISPLAYIO_SMODE: 259 mode = *(u_int *)data; 260 if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & 261 CG6_CFFLAG_NOACCEL) == 0) { 262 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL && 263 mode == WSDISPLAYIO_MODE_EMUL) 264 cgsix_ras_init(sc); 265 } 266 sc->sc_mode = mode; 267 break; 268 case WSDISPLAYIO_GINFO: 269 wdf = (void *)data; 270 wdf->height = sc->sc_sunfb.sf_height; 271 wdf->width = sc->sc_sunfb.sf_width; 272 wdf->depth = sc->sc_sunfb.sf_depth; 273 wdf->cmsize = 256; 274 break; 275 case WSDISPLAYIO_LINEBYTES: 276 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 277 break; 278 case WSDISPLAYIO_GETCMAP: 279 cm = (struct wsdisplay_cmap *)data; 280 error = cg6_bt_getcmap(&sc->sc_cmap, cm); 281 if (error) 282 return (error); 283 break; 284 case WSDISPLAYIO_PUTCMAP: 285 cm = (struct wsdisplay_cmap *)data; 286 error = cg6_bt_putcmap(&sc->sc_cmap, cm); 287 if (error) 288 return (error); 289 /* if we can handle interrupts, defer the update */ 290 if (sc->sc_ih != NULL) 291 cgsix_loadcmap_deferred(sc, cm->index, cm->count); 292 else 293 cgsix_loadcmap_immediate(sc, cm->index, cm->count); 294 break; 295 case WSDISPLAYIO_SCURSOR: 296 curs = (struct wsdisplay_cursor *)data; 297 return (cgsix_setcursor(sc, curs)); 298 case WSDISPLAYIO_GCURSOR: 299 curs = (struct wsdisplay_cursor *)data; 300 if (curs->which & WSDISPLAY_CURSOR_DOCUR) 301 curs->enable = sc->sc_curs_enabled; 302 if (curs->which & WSDISPLAY_CURSOR_DOPOS) { 303 curs->pos.x = sc->sc_curs_pos.x; 304 curs->pos.y = sc->sc_curs_pos.y; 305 } 306 if (curs->which & WSDISPLAY_CURSOR_DOHOT) { 307 curs->hot.x = sc->sc_curs_hot.x; 308 curs->hot.y = sc->sc_curs_hot.y; 309 } 310 if (curs->which & WSDISPLAY_CURSOR_DOCMAP) { 311 curs->cmap.index = 0; 312 curs->cmap.count = 2; 313 r[0] = sc->sc_curs_fg >> 16; 314 g[0] = sc->sc_curs_fg >> 8; 315 b[0] = sc->sc_curs_fg >> 0; 316 r[1] = sc->sc_curs_bg >> 16; 317 g[1] = sc->sc_curs_bg >> 8; 318 b[1] = sc->sc_curs_bg >> 0; 319 error = copyout(r, curs->cmap.red, sizeof(r)); 320 if (error) 321 return (error); 322 error = copyout(g, curs->cmap.green, sizeof(g)); 323 if (error) 324 return (error); 325 error = copyout(b, curs->cmap.blue, sizeof(b)); 326 if (error) 327 return (error); 328 } 329 if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) { 330 size_t l; 331 332 curs->size.x = sc->sc_curs_size.x; 333 curs->size.y = sc->sc_curs_size.y; 334 l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY; 335 error = copyout(sc->sc_curs_image, curs->image, l); 336 if (error) 337 return (error); 338 error = copyout(sc->sc_curs_mask, curs->mask, l); 339 if (error) 340 return (error); 341 } 342 break; 343 case WSDISPLAYIO_GCURPOS: 344 pos = (struct wsdisplay_curpos *)data; 345 pos->x = sc->sc_curs_pos.x; 346 pos->y = sc->sc_curs_pos.y; 347 break; 348 case WSDISPLAYIO_SCURPOS: 349 pos = (struct wsdisplay_curpos *)data; 350 s = spltty(); 351 sc->sc_curs_pos.x = pos->x; 352 sc->sc_curs_pos.y = pos->y; 353 cgsix_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS); 354 splx(s); 355 break; 356 case WSDISPLAYIO_GCURMAX: 357 pos = (struct wsdisplay_curpos *)data; 358 pos->x = pos->y = 32; 359 break; 360 case WSDISPLAYIO_SVIDEO: 361 case WSDISPLAYIO_GVIDEO: 362 break; 363 default: 364 return -1; /* not supported */ 365 } 366 367 return (0); 368 } 369 370 int 371 cgsix_setcursor(struct cgsix_softc *sc, struct wsdisplay_cursor *curs) 372 { 373 u_int8_t r[2], g[2], b[2], image[128], mask[128]; 374 int s, error; 375 size_t imcount; 376 377 /* 378 * Do stuff that can generate errors first, then we'll blast it 379 * all at once. 380 */ 381 if (curs->which & WSDISPLAY_CURSOR_DOCMAP) { 382 if (curs->cmap.count < 2) 383 return (EINVAL); 384 error = copyin(curs->cmap.red, r, sizeof(r)); 385 if (error) 386 return (error); 387 error = copyin(curs->cmap.green, g, sizeof(g)); 388 if (error) 389 return (error); 390 error = copyin(curs->cmap.blue, b, sizeof(b)); 391 if (error) 392 return (error); 393 } 394 395 if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) { 396 if (curs->size.x > CG6_MAX_CURSOR || 397 curs->size.y > CG6_MAX_CURSOR) 398 return (EINVAL); 399 imcount = (curs->size.x * curs->size.y) / NBBY; 400 error = copyin(curs->image, image, imcount); 401 if (error) 402 return (error); 403 error = copyin(curs->mask, mask, imcount); 404 if (error) 405 return (error); 406 } 407 408 /* 409 * Ok, everything is in kernel space and sane, update state. 410 */ 411 s = spltty(); 412 413 if (curs->which & WSDISPLAY_CURSOR_DOCUR) 414 sc->sc_curs_enabled = curs->enable; 415 if (curs->which & WSDISPLAY_CURSOR_DOPOS) { 416 sc->sc_curs_pos.x = curs->pos.x; 417 sc->sc_curs_pos.y = curs->pos.y; 418 } 419 if (curs->which & WSDISPLAY_CURSOR_DOHOT) { 420 sc->sc_curs_hot.x = curs->hot.x; 421 sc->sc_curs_hot.y = curs->hot.y; 422 } 423 if (curs->which & WSDISPLAY_CURSOR_DOCMAP) { 424 sc->sc_curs_fg = ((r[0] << 16) | (g[0] << 8) | (b[0] << 0)); 425 sc->sc_curs_bg = ((r[1] << 16) | (g[1] << 8) | (b[1] << 0)); 426 } 427 if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) { 428 sc->sc_curs_size.x = curs->size.x; 429 sc->sc_curs_size.y = curs->size.y; 430 bcopy(image, sc->sc_curs_image, imcount); 431 bcopy(mask, sc->sc_curs_mask, imcount); 432 } 433 434 cgsix_updatecursor(sc, curs->which); 435 splx(s); 436 437 return (0); 438 } 439 440 int 441 cgsix_updatecursor(struct cgsix_softc *sc, u_int which) 442 { 443 if (which & WSDISPLAY_CURSOR_DOCMAP) { 444 BT_WRITE(sc, BT_ADDR, BT_OV1 << 24); 445 BT_WRITE(sc, BT_OMAP, 446 ((sc->sc_curs_fg & 0x00ff0000) >> 16) << 24); 447 BT_WRITE(sc, BT_OMAP, 448 ((sc->sc_curs_fg & 0x0000ff00) >> 8) << 24); 449 BT_WRITE(sc, BT_OMAP, 450 ((sc->sc_curs_fg & 0x000000ff) >> 0) << 24); 451 452 BT_WRITE(sc, BT_ADDR, BT_OV3 << 24); 453 BT_WRITE(sc, BT_OMAP, 454 ((sc->sc_curs_bg & 0x00ff0000) >> 16) << 24); 455 BT_WRITE(sc, BT_OMAP, 456 ((sc->sc_curs_bg & 0x0000ff00) >> 8) << 24); 457 BT_WRITE(sc, BT_OMAP, 458 ((sc->sc_curs_bg & 0x000000ff) >> 0) << 24); 459 } 460 461 if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 462 u_int32_t x, y; 463 464 x = sc->sc_curs_pos.x + CG6_MAX_CURSOR - sc->sc_curs_hot.x; 465 y = sc->sc_curs_pos.y + CG6_MAX_CURSOR - sc->sc_curs_hot.y; 466 THC_WRITE(sc, CG6_THC_CURSXY, 467 ((x & 0xffff) << 16) | (y & 0xffff)); 468 } 469 470 if (which & WSDISPLAY_CURSOR_DOCUR) { 471 u_int32_t c; 472 473 /* Enable or disable the cursor overlay planes */ 474 if (sc->sc_curs_enabled) { 475 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 476 c = BT_READ(sc, BT_CTRL); 477 c |= (BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24; 478 BT_WRITE(sc, BT_CTRL, c); 479 } else { 480 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 481 c = BT_READ(sc, BT_CTRL); 482 c &= ~((BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24); 483 BT_WRITE(sc, BT_CTRL, c); 484 THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF); 485 } 486 } 487 488 return (0); 489 } 490 491 struct mmo { 492 off_t mo_uaddr; 493 bus_size_t mo_size; 494 bus_size_t mo_physoff; 495 }; 496 497 paddr_t 498 cgsix_mmap(void *v, off_t off, int prot) 499 { 500 struct cgsix_softc *sc = v; 501 struct mmo *mo; 502 bus_addr_t u; 503 bus_size_t sz; 504 505 static struct mmo mmo[] = { 506 { CG6_USER_RAM, 0, CGSIX_VID_OFFSET }, 507 508 /* do not actually know how big most of these are! */ 509 { CG6_USER_FBC, 1, CGSIX_FBC_OFFSET }, 510 { CG6_USER_TEC, 1, CGSIX_TEC_OFFSET }, 511 { CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET }, 512 { CG6_USER_FHC, 1, CGSIX_FHC_OFFSET }, 513 { CG6_USER_THC, CGSIX_THC_SIZE, CGSIX_THC_OFFSET }, 514 { CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET }, 515 { CG6_USER_DHC, 1, CGSIX_DHC_OFFSET }, 516 }; 517 #define NMMO (sizeof mmo / sizeof *mmo) 518 519 if (off & PGOFSET || off < 0) 520 return (-1); 521 522 switch (sc->sc_mode) { 523 case WSDISPLAYIO_MODE_MAPPED: 524 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 525 if (off < mo->mo_uaddr) 526 continue; 527 u = off - mo->mo_uaddr; 528 sz = mo->mo_size ? mo->mo_size : sc->sc_sunfb.sf_fbsize; 529 if (u < sz) { 530 return (bus_space_mmap(sc->sc_bustag, 531 sc->sc_paddr, u + mo->mo_physoff, 532 prot, BUS_SPACE_MAP_LINEAR)); 533 } 534 } 535 break; 536 537 case WSDISPLAYIO_MODE_DUMBFB: 538 /* Allow mapping as a dumb framebuffer from offset 0 */ 539 if (off >= 0 && off < sc->sc_sunfb.sf_fbsize) 540 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 541 off + CGSIX_VID_OFFSET, prot, 542 BUS_SPACE_MAP_LINEAR)); 543 break; 544 } 545 546 return (-1); 547 } 548 549 int 550 cgsix_is_console(int node) 551 { 552 extern int fbnode; 553 554 return (fbnode == node); 555 } 556 557 int 558 cg6_bt_getcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm) 559 { 560 u_int index = rcm->index, count = rcm->count, i; 561 int error; 562 563 if (index >= 256 || count > 256 - index) 564 return (EINVAL); 565 for (i = 0; i < count; i++) { 566 if ((error = copyout(&bcm->cm_map[index + i][0], 567 &rcm->red[i], 1)) != 0) 568 return (error); 569 if ((error = copyout(&bcm->cm_map[index + i][1], 570 &rcm->green[i], 1)) != 0) 571 return (error); 572 if ((error = copyout(&bcm->cm_map[index + i][2], 573 &rcm->blue[i], 1)) != 0) 574 return (error); 575 } 576 return (0); 577 } 578 579 int 580 cg6_bt_putcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm) 581 { 582 u_int index = rcm->index, count = rcm->count, i; 583 int error; 584 585 if (index >= 256 || count > 256 - index) 586 return (EINVAL); 587 for (i = 0; i < count; i++) { 588 if ((error = copyin(&rcm->red[i], 589 &bcm->cm_map[index + i][0], 1)) != 0) 590 return (error); 591 if ((error = copyin(&rcm->green[i], 592 &bcm->cm_map[index + i][1], 1)) != 0) 593 return (error); 594 if ((error = copyin(&rcm->blue[i], 595 &bcm->cm_map[index + i][2], 1)) != 0) 596 return (error); 597 } 598 return (0); 599 } 600 601 void 602 cgsix_loadcmap_deferred(struct cgsix_softc *sc, u_int start, u_int ncolors) 603 { 604 u_int32_t thcm; 605 606 thcm = THC_READ(sc, CG6_THC_MISC); 607 thcm &= ~THC_MISC_RESET; 608 thcm |= THC_MISC_INTEN; 609 THC_WRITE(sc, CG6_THC_MISC, thcm); 610 } 611 612 void 613 cgsix_loadcmap_immediate(struct cgsix_softc *sc, u_int start, u_int ncolors) 614 { 615 u_int cstart; 616 u_int32_t v; 617 int count; 618 619 cstart = BT_D4M3(start); 620 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 621 BT_WRITE(sc, BT_ADDR, BT_D4M4(start) << 24); 622 while (--count >= 0) { 623 v = sc->sc_cmap.cm_chip[cstart]; 624 BT_WRITE(sc, BT_CMAP, v << 0); 625 BT_WRITE(sc, BT_CMAP, v << 8); 626 BT_WRITE(sc, BT_CMAP, v << 16); 627 BT_WRITE(sc, BT_CMAP, v << 24); 628 cstart++; 629 } 630 } 631 632 void 633 cgsix_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 634 { 635 struct cgsix_softc *sc = v; 636 union bt_cmap *bcm = &sc->sc_cmap; 637 638 bcm->cm_map[index][0] = r; 639 bcm->cm_map[index][1] = g; 640 bcm->cm_map[index][2] = b; 641 cgsix_loadcmap_immediate(sc, index, 1); 642 } 643 644 void 645 cgsix_reset(struct cgsix_softc *sc, u_int32_t fhcrev) 646 { 647 u_int32_t fhc; 648 649 /* hide the cursor, just in case */ 650 THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF); 651 652 TEC_WRITE(sc, CG6_TEC_MV, 0); 653 TEC_WRITE(sc, CG6_TEC_CLIP, 0); 654 TEC_WRITE(sc, CG6_TEC_VDC, 0); 655 656 /* take core of hardware bugs in old revisions */ 657 if (fhcrev < 5) { 658 /* 659 * Keep current resolution; set cpu to 68020, set test 660 * window (size 1Kx1K), and for rev 1, disable dest cache. 661 */ 662 fhc = FHC_READ(sc); 663 fhc &= FHC_RES_MASK; 664 fhc |= FHC_CPU_68020 | FHC_TEST | 665 (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT); 666 if (fhcrev < 2) 667 fhc |= FHC_DST_DISABLE; 668 FHC_WRITE(sc, fhc); 669 } 670 671 /* enable cursor overlays in brooktree DAC */ 672 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 673 BT_WRITE(sc, BT_CTRL, BT_READ(sc, BT_CTRL) | 674 ((BTCR_DISPENA_OV1 | BTCR_DISPENA_OV0) << 24)); 675 } 676 677 void 678 cgsix_hardreset(struct cgsix_softc *sc) 679 { 680 u_int32_t fhc, rev; 681 682 /* enable all of the bit planes */ 683 BT_WRITE(sc, BT_ADDR, BT_RMR << 24); 684 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 685 BT_WRITE(sc, BT_CTRL, 0xff << 24); 686 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 687 688 /* no bit planes should blink */ 689 BT_WRITE(sc, BT_ADDR, BT_BMR << 24); 690 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 691 BT_WRITE(sc, BT_CTRL, 0x00 << 24); 692 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 693 694 /* 695 * enable the RAMDAC, disable blink, disable overlay 0 and 1, 696 * use 4:1 multiplexor. 697 */ 698 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 699 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 700 BT_WRITE(sc, BT_CTRL, 701 (BTCR_MPLX_4 | BTCR_RAMENA | BTCR_BLINK_6464) << 24); 702 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 703 704 /* disable the D/A read pins */ 705 BT_WRITE(sc, BT_ADDR, BT_CTR << 24); 706 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 707 BT_WRITE(sc, BT_CTRL, 0x00 << 24); 708 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 709 710 /* configure thc */ 711 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR | 712 THC_MISC_CYCLS); 713 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS); 714 715 THC_WRITE(sc, CG6_THC_HSYNC1, 0x10009); 716 THC_WRITE(sc, CG6_THC_HSYNC2, 0x570000); 717 THC_WRITE(sc, CG6_THC_HSYNC3, 0x15005d); 718 THC_WRITE(sc, CG6_THC_VSYNC1, 0x10005); 719 THC_WRITE(sc, CG6_THC_VSYNC2, 0x2403a8); 720 THC_WRITE(sc, CG6_THC_REFRESH, 0x16b); 721 722 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR | 723 THC_MISC_CYCLS); 724 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS); 725 726 /* configure fhc (1152x900) */ 727 fhc = FHC_READ(sc); 728 rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT; 729 730 fhc = FHC_RES_1152 | FHC_CPU_68020 | FHC_TEST; 731 if (rev < 1) 732 fhc |= FHC_FROP_DISABLE; 733 if (rev < 2) 734 fhc |= FHC_DST_DISABLE; 735 FHC_WRITE(sc, fhc); 736 } 737 738 void 739 cgsix_burner(void *vsc, u_int on, u_int flags) 740 { 741 struct cgsix_softc *sc = vsc; 742 int s; 743 u_int32_t thcm; 744 745 s = splhigh(); 746 thcm = THC_READ(sc, CG6_THC_MISC); 747 if (on) 748 thcm |= THC_MISC_VIDEN | THC_MISC_SYNCEN; 749 else { 750 thcm &= ~THC_MISC_VIDEN; 751 if (flags & WSDISPLAY_BURN_VBLANK) 752 thcm &= ~THC_MISC_SYNCEN; 753 } 754 THC_WRITE(sc, CG6_THC_MISC, thcm); 755 splx(s); 756 } 757 758 int 759 cgsix_intr(void *vsc) 760 { 761 struct cgsix_softc *sc = vsc; 762 u_int32_t thcm; 763 764 thcm = THC_READ(sc, CG6_THC_MISC); 765 if ((thcm & (THC_MISC_INTEN | THC_MISC_INTR)) != 766 (THC_MISC_INTEN | THC_MISC_INTR)) { 767 /* Not expecting an interrupt, it's not for us. */ 768 return (0); 769 } 770 771 /* Acknowledge the interrupt and disable it. */ 772 thcm &= ~(THC_MISC_RESET | THC_MISC_INTEN); 773 thcm |= THC_MISC_INTR; 774 THC_WRITE(sc, CG6_THC_MISC, thcm); 775 cgsix_loadcmap_immediate(sc, 0, 256); 776 return (1); 777 } 778 779 void 780 cgsix_ras_init(struct cgsix_softc *sc) 781 { 782 u_int32_t m; 783 784 CG6_DRAIN(sc); 785 m = FBC_READ(sc, CG6_FBC_MODE); 786 m &= ~FBC_MODE_MASK; 787 m |= FBC_MODE_VAL; 788 FBC_WRITE(sc, CG6_FBC_MODE, m); 789 } 790 791 int 792 cgsix_ras_copyrows(void *cookie, int src, int dst, int n) 793 { 794 struct rasops_info *ri = cookie; 795 struct cgsix_softc *sc = ri->ri_hw; 796 797 if (dst == src) 798 return 0; 799 if (src < 0) { 800 n += src; 801 src = 0; 802 } 803 if (src + n > ri->ri_rows) 804 n = ri->ri_rows - src; 805 if (dst < 0) { 806 n += dst; 807 dst = 0; 808 } 809 if (dst + n > ri->ri_rows) 810 n = ri->ri_rows - dst; 811 if (n <= 0) 812 return 0; 813 n *= ri->ri_font->fontheight; 814 src *= ri->ri_font->fontheight; 815 dst *= ri->ri_font->fontheight; 816 817 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 818 FBC_WRITE(sc, CG6_FBC_S, 0); 819 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 820 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 821 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 822 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 823 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 824 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 825 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY); 826 FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin); 827 FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + src); 828 FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + ri->ri_emuwidth - 1); 829 FBC_WRITE(sc, CG6_FBC_Y1, ri->ri_yorigin + src + n - 1); 830 FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin); 831 FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + dst); 832 FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + ri->ri_emuwidth - 1); 833 FBC_WRITE(sc, CG6_FBC_Y3, ri->ri_yorigin + dst + n - 1); 834 CG6_BLIT_WAIT(sc); 835 CG6_DRAIN(sc); 836 837 return 0; 838 } 839 840 int 841 cgsix_ras_copycols(void *cookie, int row, int src, int dst, int n) 842 { 843 struct rasops_info *ri = cookie; 844 struct cgsix_softc *sc = ri->ri_hw; 845 846 if (dst == src) 847 return 0; 848 if ((row < 0) || (row >= ri->ri_rows)) 849 return 0; 850 if (src < 0) { 851 n += src; 852 src = 0; 853 } 854 if (src + n > ri->ri_cols) 855 n = ri->ri_cols - src; 856 if (dst < 0) { 857 n += dst; 858 dst = 0; 859 } 860 if (dst + n > ri->ri_cols) 861 n = ri->ri_cols - dst; 862 if (n <= 0) 863 return 0; 864 n *= ri->ri_font->fontwidth; 865 src *= ri->ri_font->fontwidth; 866 dst *= ri->ri_font->fontwidth; 867 row *= ri->ri_font->fontheight; 868 869 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 870 FBC_WRITE(sc, CG6_FBC_S, 0); 871 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 872 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 873 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 874 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 875 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 876 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 877 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY); 878 FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin + src); 879 FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + row); 880 FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + src + n - 1); 881 FBC_WRITE(sc, CG6_FBC_Y1, 882 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 883 FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin + dst); 884 FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + row); 885 FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + dst + n - 1); 886 FBC_WRITE(sc, CG6_FBC_Y3, 887 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 888 CG6_BLIT_WAIT(sc); 889 CG6_DRAIN(sc); 890 891 return 0; 892 } 893 894 int 895 cgsix_ras_erasecols(void *cookie, int row, int col, int n, uint32_t attr) 896 { 897 struct rasops_info *ri = cookie; 898 struct cgsix_softc *sc = ri->ri_hw; 899 int fg, bg; 900 901 if ((row < 0) || (row >= ri->ri_rows)) 902 return 0; 903 if (col < 0) { 904 n += col; 905 col = 0; 906 } 907 if (col + n > ri->ri_cols) 908 n = ri->ri_cols - col; 909 if (n <= 0) 910 return 0; 911 n *= ri->ri_font->fontwidth; 912 col *= ri->ri_font->fontwidth; 913 row *= ri->ri_font->fontheight; 914 915 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 916 917 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 918 FBC_WRITE(sc, CG6_FBC_S, 0); 919 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 920 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 921 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 922 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 923 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 924 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 925 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL); 926 FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[bg]); 927 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row); 928 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col); 929 FBC_WRITE(sc, CG6_FBC_ARECTY, 930 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 931 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col + n - 1); 932 CG6_DRAW_WAIT(sc); 933 CG6_DRAIN(sc); 934 935 return 0; 936 } 937 938 int 939 cgsix_ras_eraserows(void *cookie, int row, int n, uint32_t attr) 940 { 941 struct rasops_info *ri = cookie; 942 struct cgsix_softc *sc = ri->ri_hw; 943 int fg, bg; 944 945 if (row < 0) { 946 n += row; 947 row = 0; 948 } 949 if (row + n > ri->ri_rows) 950 n = ri->ri_rows - row; 951 if (n <= 0) 952 return 0; 953 954 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 955 956 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 957 FBC_WRITE(sc, CG6_FBC_S, 0); 958 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 959 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 960 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 961 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 962 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 963 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 964 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL); 965 FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[bg]); 966 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 967 FBC_WRITE(sc, CG6_FBC_ARECTY, 0); 968 FBC_WRITE(sc, CG6_FBC_ARECTX, 0); 969 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_height - 1); 970 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_width - 1); 971 } else { 972 row *= ri->ri_font->fontheight; 973 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row); 974 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin); 975 FBC_WRITE(sc, CG6_FBC_ARECTY, 976 ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1); 977 FBC_WRITE(sc, CG6_FBC_ARECTX, 978 ri->ri_xorigin + ri->ri_emuwidth - 1); 979 } 980 CG6_DRAW_WAIT(sc); 981 CG6_DRAIN(sc); 982 983 return 0; 984 } 985 986 int 987 cgsix_ras_do_cursor(struct rasops_info *ri) 988 { 989 struct cgsix_softc *sc = ri->ri_hw; 990 int row, col; 991 992 row = ri->ri_crow * ri->ri_font->fontheight; 993 col = ri->ri_ccol * ri->ri_font->fontwidth; 994 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 995 FBC_WRITE(sc, CG6_FBC_S, 0); 996 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 997 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 998 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 999 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 1000 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 1001 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 1002 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FLIP); 1003 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row); 1004 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col); 1005 FBC_WRITE(sc, CG6_FBC_ARECTY, 1006 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 1007 FBC_WRITE(sc, CG6_FBC_ARECTX, 1008 ri->ri_xorigin + col + ri->ri_font->fontwidth - 1); 1009 CG6_DRAW_WAIT(sc); 1010 CG6_DRAIN(sc); 1011 1012 return 0; 1013 } 1014