1 /* $OpenBSD: cgsix.c,v 1.62 2022/07/15 17:57:27 kettenis 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 const 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->stride = sc->sc_sunfb.sf_linebytes; 274 wdf->offset = 0; 275 wdf->cmsize = 256; 276 break; 277 case WSDISPLAYIO_LINEBYTES: 278 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 279 break; 280 case WSDISPLAYIO_GETCMAP: 281 cm = (struct wsdisplay_cmap *)data; 282 error = cg6_bt_getcmap(&sc->sc_cmap, cm); 283 if (error) 284 return (error); 285 break; 286 case WSDISPLAYIO_PUTCMAP: 287 cm = (struct wsdisplay_cmap *)data; 288 error = cg6_bt_putcmap(&sc->sc_cmap, cm); 289 if (error) 290 return (error); 291 /* if we can handle interrupts, defer the update */ 292 if (sc->sc_ih != NULL) 293 cgsix_loadcmap_deferred(sc, cm->index, cm->count); 294 else 295 cgsix_loadcmap_immediate(sc, cm->index, cm->count); 296 break; 297 case WSDISPLAYIO_SCURSOR: 298 curs = (struct wsdisplay_cursor *)data; 299 return (cgsix_setcursor(sc, curs)); 300 case WSDISPLAYIO_GCURSOR: 301 curs = (struct wsdisplay_cursor *)data; 302 if (curs->which & WSDISPLAY_CURSOR_DOCUR) 303 curs->enable = sc->sc_curs_enabled; 304 if (curs->which & WSDISPLAY_CURSOR_DOPOS) { 305 curs->pos.x = sc->sc_curs_pos.x; 306 curs->pos.y = sc->sc_curs_pos.y; 307 } 308 if (curs->which & WSDISPLAY_CURSOR_DOHOT) { 309 curs->hot.x = sc->sc_curs_hot.x; 310 curs->hot.y = sc->sc_curs_hot.y; 311 } 312 if (curs->which & WSDISPLAY_CURSOR_DOCMAP) { 313 curs->cmap.index = 0; 314 curs->cmap.count = 2; 315 r[0] = sc->sc_curs_fg >> 16; 316 g[0] = sc->sc_curs_fg >> 8; 317 b[0] = sc->sc_curs_fg >> 0; 318 r[1] = sc->sc_curs_bg >> 16; 319 g[1] = sc->sc_curs_bg >> 8; 320 b[1] = sc->sc_curs_bg >> 0; 321 error = copyout(r, curs->cmap.red, sizeof(r)); 322 if (error) 323 return (error); 324 error = copyout(g, curs->cmap.green, sizeof(g)); 325 if (error) 326 return (error); 327 error = copyout(b, curs->cmap.blue, sizeof(b)); 328 if (error) 329 return (error); 330 } 331 if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) { 332 size_t l; 333 334 curs->size.x = sc->sc_curs_size.x; 335 curs->size.y = sc->sc_curs_size.y; 336 l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY; 337 error = copyout(sc->sc_curs_image, curs->image, l); 338 if (error) 339 return (error); 340 error = copyout(sc->sc_curs_mask, curs->mask, l); 341 if (error) 342 return (error); 343 } 344 break; 345 case WSDISPLAYIO_GCURPOS: 346 pos = (struct wsdisplay_curpos *)data; 347 pos->x = sc->sc_curs_pos.x; 348 pos->y = sc->sc_curs_pos.y; 349 break; 350 case WSDISPLAYIO_SCURPOS: 351 pos = (struct wsdisplay_curpos *)data; 352 s = spltty(); 353 sc->sc_curs_pos.x = pos->x; 354 sc->sc_curs_pos.y = pos->y; 355 cgsix_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS); 356 splx(s); 357 break; 358 case WSDISPLAYIO_GCURMAX: 359 pos = (struct wsdisplay_curpos *)data; 360 pos->x = pos->y = 32; 361 break; 362 case WSDISPLAYIO_SVIDEO: 363 case WSDISPLAYIO_GVIDEO: 364 break; 365 default: 366 return -1; /* not supported */ 367 } 368 369 return (0); 370 } 371 372 int 373 cgsix_setcursor(struct cgsix_softc *sc, struct wsdisplay_cursor *curs) 374 { 375 u_int8_t r[2], g[2], b[2], image[128], mask[128]; 376 int s, error; 377 size_t imcount; 378 379 /* 380 * Do stuff that can generate errors first, then we'll blast it 381 * all at once. 382 */ 383 if (curs->which & WSDISPLAY_CURSOR_DOCMAP) { 384 if (curs->cmap.count < 2) 385 return (EINVAL); 386 error = copyin(curs->cmap.red, r, sizeof(r)); 387 if (error) 388 return (error); 389 error = copyin(curs->cmap.green, g, sizeof(g)); 390 if (error) 391 return (error); 392 error = copyin(curs->cmap.blue, b, sizeof(b)); 393 if (error) 394 return (error); 395 } 396 397 if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) { 398 if (curs->size.x > CG6_MAX_CURSOR || 399 curs->size.y > CG6_MAX_CURSOR) 400 return (EINVAL); 401 imcount = (curs->size.x * curs->size.y) / NBBY; 402 error = copyin(curs->image, image, imcount); 403 if (error) 404 return (error); 405 error = copyin(curs->mask, mask, imcount); 406 if (error) 407 return (error); 408 } 409 410 /* 411 * Ok, everything is in kernel space and sane, update state. 412 */ 413 s = spltty(); 414 415 if (curs->which & WSDISPLAY_CURSOR_DOCUR) 416 sc->sc_curs_enabled = curs->enable; 417 if (curs->which & WSDISPLAY_CURSOR_DOPOS) { 418 sc->sc_curs_pos.x = curs->pos.x; 419 sc->sc_curs_pos.y = curs->pos.y; 420 } 421 if (curs->which & WSDISPLAY_CURSOR_DOHOT) { 422 sc->sc_curs_hot.x = curs->hot.x; 423 sc->sc_curs_hot.y = curs->hot.y; 424 } 425 if (curs->which & WSDISPLAY_CURSOR_DOCMAP) { 426 sc->sc_curs_fg = ((r[0] << 16) | (g[0] << 8) | (b[0] << 0)); 427 sc->sc_curs_bg = ((r[1] << 16) | (g[1] << 8) | (b[1] << 0)); 428 } 429 if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) { 430 sc->sc_curs_size.x = curs->size.x; 431 sc->sc_curs_size.y = curs->size.y; 432 bcopy(image, sc->sc_curs_image, imcount); 433 bcopy(mask, sc->sc_curs_mask, imcount); 434 } 435 436 cgsix_updatecursor(sc, curs->which); 437 splx(s); 438 439 return (0); 440 } 441 442 int 443 cgsix_updatecursor(struct cgsix_softc *sc, u_int which) 444 { 445 if (which & WSDISPLAY_CURSOR_DOCMAP) { 446 BT_WRITE(sc, BT_ADDR, BT_OV1 << 24); 447 BT_WRITE(sc, BT_OMAP, 448 ((sc->sc_curs_fg & 0x00ff0000) >> 16) << 24); 449 BT_WRITE(sc, BT_OMAP, 450 ((sc->sc_curs_fg & 0x0000ff00) >> 8) << 24); 451 BT_WRITE(sc, BT_OMAP, 452 ((sc->sc_curs_fg & 0x000000ff) >> 0) << 24); 453 454 BT_WRITE(sc, BT_ADDR, BT_OV3 << 24); 455 BT_WRITE(sc, BT_OMAP, 456 ((sc->sc_curs_bg & 0x00ff0000) >> 16) << 24); 457 BT_WRITE(sc, BT_OMAP, 458 ((sc->sc_curs_bg & 0x0000ff00) >> 8) << 24); 459 BT_WRITE(sc, BT_OMAP, 460 ((sc->sc_curs_bg & 0x000000ff) >> 0) << 24); 461 } 462 463 if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 464 u_int32_t x, y; 465 466 x = sc->sc_curs_pos.x + CG6_MAX_CURSOR - sc->sc_curs_hot.x; 467 y = sc->sc_curs_pos.y + CG6_MAX_CURSOR - sc->sc_curs_hot.y; 468 THC_WRITE(sc, CG6_THC_CURSXY, 469 ((x & 0xffff) << 16) | (y & 0xffff)); 470 } 471 472 if (which & WSDISPLAY_CURSOR_DOCUR) { 473 u_int32_t c; 474 475 /* Enable or disable the cursor overlay planes */ 476 if (sc->sc_curs_enabled) { 477 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 478 c = BT_READ(sc, BT_CTRL); 479 c |= (BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24; 480 BT_WRITE(sc, BT_CTRL, c); 481 } else { 482 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 483 c = BT_READ(sc, BT_CTRL); 484 c &= ~((BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24); 485 BT_WRITE(sc, BT_CTRL, c); 486 THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF); 487 } 488 } 489 490 return (0); 491 } 492 493 struct mmo { 494 off_t mo_uaddr; 495 bus_size_t mo_size; 496 bus_size_t mo_physoff; 497 }; 498 499 paddr_t 500 cgsix_mmap(void *v, off_t off, int prot) 501 { 502 struct cgsix_softc *sc = v; 503 struct mmo *mo; 504 bus_addr_t u; 505 bus_size_t sz; 506 507 static struct mmo mmo[] = { 508 { CG6_USER_RAM, 0, CGSIX_VID_OFFSET }, 509 510 /* do not actually know how big most of these are! */ 511 { CG6_USER_FBC, 1, CGSIX_FBC_OFFSET }, 512 { CG6_USER_TEC, 1, CGSIX_TEC_OFFSET }, 513 { CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET }, 514 { CG6_USER_FHC, 1, CGSIX_FHC_OFFSET }, 515 { CG6_USER_THC, CGSIX_THC_SIZE, CGSIX_THC_OFFSET }, 516 { CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET }, 517 { CG6_USER_DHC, 1, CGSIX_DHC_OFFSET }, 518 }; 519 #define NMMO (sizeof mmo / sizeof *mmo) 520 521 if (off & PGOFSET || off < 0) 522 return (-1); 523 524 switch (sc->sc_mode) { 525 case WSDISPLAYIO_MODE_MAPPED: 526 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 527 if (off < mo->mo_uaddr) 528 continue; 529 u = off - mo->mo_uaddr; 530 sz = mo->mo_size ? mo->mo_size : sc->sc_sunfb.sf_fbsize; 531 if (u < sz) { 532 return (bus_space_mmap(sc->sc_bustag, 533 sc->sc_paddr, u + mo->mo_physoff, 534 prot, BUS_SPACE_MAP_LINEAR)); 535 } 536 } 537 break; 538 539 case WSDISPLAYIO_MODE_DUMBFB: 540 /* Allow mapping as a dumb framebuffer from offset 0 */ 541 if (off >= 0 && off < sc->sc_sunfb.sf_fbsize) 542 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 543 off + CGSIX_VID_OFFSET, prot, 544 BUS_SPACE_MAP_LINEAR)); 545 break; 546 } 547 548 return (-1); 549 } 550 551 int 552 cgsix_is_console(int node) 553 { 554 extern int fbnode; 555 556 return (fbnode == node); 557 } 558 559 int 560 cg6_bt_getcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm) 561 { 562 u_int index = rcm->index, count = rcm->count, i; 563 int error; 564 565 if (index >= 256 || count > 256 - index) 566 return (EINVAL); 567 for (i = 0; i < count; i++) { 568 if ((error = copyout(&bcm->cm_map[index + i][0], 569 &rcm->red[i], 1)) != 0) 570 return (error); 571 if ((error = copyout(&bcm->cm_map[index + i][1], 572 &rcm->green[i], 1)) != 0) 573 return (error); 574 if ((error = copyout(&bcm->cm_map[index + i][2], 575 &rcm->blue[i], 1)) != 0) 576 return (error); 577 } 578 return (0); 579 } 580 581 int 582 cg6_bt_putcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm) 583 { 584 u_int index = rcm->index, count = rcm->count, i; 585 int error; 586 587 if (index >= 256 || count > 256 - index) 588 return (EINVAL); 589 for (i = 0; i < count; i++) { 590 if ((error = copyin(&rcm->red[i], 591 &bcm->cm_map[index + i][0], 1)) != 0) 592 return (error); 593 if ((error = copyin(&rcm->green[i], 594 &bcm->cm_map[index + i][1], 1)) != 0) 595 return (error); 596 if ((error = copyin(&rcm->blue[i], 597 &bcm->cm_map[index + i][2], 1)) != 0) 598 return (error); 599 } 600 return (0); 601 } 602 603 void 604 cgsix_loadcmap_deferred(struct cgsix_softc *sc, u_int start, u_int ncolors) 605 { 606 u_int32_t thcm; 607 608 thcm = THC_READ(sc, CG6_THC_MISC); 609 thcm &= ~THC_MISC_RESET; 610 thcm |= THC_MISC_INTEN; 611 THC_WRITE(sc, CG6_THC_MISC, thcm); 612 } 613 614 void 615 cgsix_loadcmap_immediate(struct cgsix_softc *sc, u_int start, u_int ncolors) 616 { 617 u_int cstart; 618 u_int32_t v; 619 int count; 620 621 cstart = BT_D4M3(start); 622 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 623 BT_WRITE(sc, BT_ADDR, BT_D4M4(start) << 24); 624 while (--count >= 0) { 625 v = sc->sc_cmap.cm_chip[cstart]; 626 BT_WRITE(sc, BT_CMAP, v << 0); 627 BT_WRITE(sc, BT_CMAP, v << 8); 628 BT_WRITE(sc, BT_CMAP, v << 16); 629 BT_WRITE(sc, BT_CMAP, v << 24); 630 cstart++; 631 } 632 } 633 634 void 635 cgsix_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 636 { 637 struct cgsix_softc *sc = v; 638 union bt_cmap *bcm = &sc->sc_cmap; 639 640 bcm->cm_map[index][0] = r; 641 bcm->cm_map[index][1] = g; 642 bcm->cm_map[index][2] = b; 643 cgsix_loadcmap_immediate(sc, index, 1); 644 } 645 646 void 647 cgsix_reset(struct cgsix_softc *sc, u_int32_t fhcrev) 648 { 649 u_int32_t fhc; 650 651 /* hide the cursor, just in case */ 652 THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF); 653 654 TEC_WRITE(sc, CG6_TEC_MV, 0); 655 TEC_WRITE(sc, CG6_TEC_CLIP, 0); 656 TEC_WRITE(sc, CG6_TEC_VDC, 0); 657 658 /* take core of hardware bugs in old revisions */ 659 if (fhcrev < 5) { 660 /* 661 * Keep current resolution; set cpu to 68020, set test 662 * window (size 1Kx1K), and for rev 1, disable dest cache. 663 */ 664 fhc = FHC_READ(sc); 665 fhc &= FHC_RES_MASK; 666 fhc |= FHC_CPU_68020 | FHC_TEST | 667 (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT); 668 if (fhcrev < 2) 669 fhc |= FHC_DST_DISABLE; 670 FHC_WRITE(sc, fhc); 671 } 672 673 /* enable cursor overlays in brooktree DAC */ 674 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 675 BT_WRITE(sc, BT_CTRL, BT_READ(sc, BT_CTRL) | 676 ((BTCR_DISPENA_OV1 | BTCR_DISPENA_OV0) << 24)); 677 } 678 679 void 680 cgsix_hardreset(struct cgsix_softc *sc) 681 { 682 u_int32_t fhc, rev; 683 684 /* enable all of the bit planes */ 685 BT_WRITE(sc, BT_ADDR, BT_RMR << 24); 686 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 687 BT_WRITE(sc, BT_CTRL, 0xff << 24); 688 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 689 690 /* no bit planes should blink */ 691 BT_WRITE(sc, BT_ADDR, BT_BMR << 24); 692 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 693 BT_WRITE(sc, BT_CTRL, 0x00 << 24); 694 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 695 696 /* 697 * enable the RAMDAC, disable blink, disable overlay 0 and 1, 698 * use 4:1 multiplexor. 699 */ 700 BT_WRITE(sc, BT_ADDR, BT_CR << 24); 701 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 702 BT_WRITE(sc, BT_CTRL, 703 (BTCR_MPLX_4 | BTCR_RAMENA | BTCR_BLINK_6464) << 24); 704 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 705 706 /* disable the D/A read pins */ 707 BT_WRITE(sc, BT_ADDR, BT_CTR << 24); 708 BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE); 709 BT_WRITE(sc, BT_CTRL, 0x00 << 24); 710 BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE); 711 712 /* configure thc */ 713 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR | 714 THC_MISC_CYCLS); 715 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS); 716 717 THC_WRITE(sc, CG6_THC_HSYNC1, 0x10009); 718 THC_WRITE(sc, CG6_THC_HSYNC2, 0x570000); 719 THC_WRITE(sc, CG6_THC_HSYNC3, 0x15005d); 720 THC_WRITE(sc, CG6_THC_VSYNC1, 0x10005); 721 THC_WRITE(sc, CG6_THC_VSYNC2, 0x2403a8); 722 THC_WRITE(sc, CG6_THC_REFRESH, 0x16b); 723 724 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR | 725 THC_MISC_CYCLS); 726 THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS); 727 728 /* configure fhc (1152x900) */ 729 fhc = FHC_READ(sc); 730 rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT; 731 732 fhc = FHC_RES_1152 | FHC_CPU_68020 | FHC_TEST; 733 if (rev < 1) 734 fhc |= FHC_FROP_DISABLE; 735 if (rev < 2) 736 fhc |= FHC_DST_DISABLE; 737 FHC_WRITE(sc, fhc); 738 } 739 740 void 741 cgsix_burner(void *vsc, u_int on, u_int flags) 742 { 743 struct cgsix_softc *sc = vsc; 744 int s; 745 u_int32_t thcm; 746 747 s = splhigh(); 748 thcm = THC_READ(sc, CG6_THC_MISC); 749 if (on) 750 thcm |= THC_MISC_VIDEN | THC_MISC_SYNCEN; 751 else { 752 thcm &= ~THC_MISC_VIDEN; 753 if (flags & WSDISPLAY_BURN_VBLANK) 754 thcm &= ~THC_MISC_SYNCEN; 755 } 756 THC_WRITE(sc, CG6_THC_MISC, thcm); 757 splx(s); 758 } 759 760 int 761 cgsix_intr(void *vsc) 762 { 763 struct cgsix_softc *sc = vsc; 764 u_int32_t thcm; 765 766 thcm = THC_READ(sc, CG6_THC_MISC); 767 if ((thcm & (THC_MISC_INTEN | THC_MISC_INTR)) != 768 (THC_MISC_INTEN | THC_MISC_INTR)) { 769 /* Not expecting an interrupt, it's not for us. */ 770 return (0); 771 } 772 773 /* Acknowledge the interrupt and disable it. */ 774 thcm &= ~(THC_MISC_RESET | THC_MISC_INTEN); 775 thcm |= THC_MISC_INTR; 776 THC_WRITE(sc, CG6_THC_MISC, thcm); 777 cgsix_loadcmap_immediate(sc, 0, 256); 778 return (1); 779 } 780 781 void 782 cgsix_ras_init(struct cgsix_softc *sc) 783 { 784 u_int32_t m; 785 786 CG6_DRAIN(sc); 787 m = FBC_READ(sc, CG6_FBC_MODE); 788 m &= ~FBC_MODE_MASK; 789 m |= FBC_MODE_VAL; 790 FBC_WRITE(sc, CG6_FBC_MODE, m); 791 } 792 793 int 794 cgsix_ras_copyrows(void *cookie, int src, int dst, int n) 795 { 796 struct rasops_info *ri = cookie; 797 struct cgsix_softc *sc = ri->ri_hw; 798 799 if (dst == src) 800 return 0; 801 if (src < 0) { 802 n += src; 803 src = 0; 804 } 805 if (src + n > ri->ri_rows) 806 n = ri->ri_rows - src; 807 if (dst < 0) { 808 n += dst; 809 dst = 0; 810 } 811 if (dst + n > ri->ri_rows) 812 n = ri->ri_rows - dst; 813 if (n <= 0) 814 return 0; 815 n *= ri->ri_font->fontheight; 816 src *= ri->ri_font->fontheight; 817 dst *= ri->ri_font->fontheight; 818 819 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 820 FBC_WRITE(sc, CG6_FBC_S, 0); 821 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 822 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 823 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 824 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 825 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 826 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 827 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY); 828 FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin); 829 FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + src); 830 FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + ri->ri_emuwidth - 1); 831 FBC_WRITE(sc, CG6_FBC_Y1, ri->ri_yorigin + src + n - 1); 832 FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin); 833 FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + dst); 834 FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + ri->ri_emuwidth - 1); 835 FBC_WRITE(sc, CG6_FBC_Y3, ri->ri_yorigin + dst + n - 1); 836 CG6_BLIT_WAIT(sc); 837 CG6_DRAIN(sc); 838 839 return 0; 840 } 841 842 int 843 cgsix_ras_copycols(void *cookie, int row, int src, int dst, int n) 844 { 845 struct rasops_info *ri = cookie; 846 struct cgsix_softc *sc = ri->ri_hw; 847 848 if (dst == src) 849 return 0; 850 if ((row < 0) || (row >= ri->ri_rows)) 851 return 0; 852 if (src < 0) { 853 n += src; 854 src = 0; 855 } 856 if (src + n > ri->ri_cols) 857 n = ri->ri_cols - src; 858 if (dst < 0) { 859 n += dst; 860 dst = 0; 861 } 862 if (dst + n > ri->ri_cols) 863 n = ri->ri_cols - dst; 864 if (n <= 0) 865 return 0; 866 n *= ri->ri_font->fontwidth; 867 src *= ri->ri_font->fontwidth; 868 dst *= ri->ri_font->fontwidth; 869 row *= ri->ri_font->fontheight; 870 871 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 872 FBC_WRITE(sc, CG6_FBC_S, 0); 873 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 874 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 875 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 876 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 877 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 878 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 879 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY); 880 FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin + src); 881 FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + row); 882 FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + src + n - 1); 883 FBC_WRITE(sc, CG6_FBC_Y1, 884 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 885 FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin + dst); 886 FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + row); 887 FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + dst + n - 1); 888 FBC_WRITE(sc, CG6_FBC_Y3, 889 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 890 CG6_BLIT_WAIT(sc); 891 CG6_DRAIN(sc); 892 893 return 0; 894 } 895 896 int 897 cgsix_ras_erasecols(void *cookie, int row, int col, int n, uint32_t attr) 898 { 899 struct rasops_info *ri = cookie; 900 struct cgsix_softc *sc = ri->ri_hw; 901 int fg, bg; 902 903 if ((row < 0) || (row >= ri->ri_rows)) 904 return 0; 905 if (col < 0) { 906 n += col; 907 col = 0; 908 } 909 if (col + n > ri->ri_cols) 910 n = ri->ri_cols - col; 911 if (n <= 0) 912 return 0; 913 n *= ri->ri_font->fontwidth; 914 col *= ri->ri_font->fontwidth; 915 row *= ri->ri_font->fontheight; 916 917 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 918 919 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 920 FBC_WRITE(sc, CG6_FBC_S, 0); 921 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 922 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 923 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 924 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 925 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 926 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 927 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL); 928 FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[bg]); 929 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row); 930 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col); 931 FBC_WRITE(sc, CG6_FBC_ARECTY, 932 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 933 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col + n - 1); 934 CG6_DRAW_WAIT(sc); 935 CG6_DRAIN(sc); 936 937 return 0; 938 } 939 940 int 941 cgsix_ras_eraserows(void *cookie, int row, int n, uint32_t attr) 942 { 943 struct rasops_info *ri = cookie; 944 struct cgsix_softc *sc = ri->ri_hw; 945 int fg, bg; 946 947 if (row < 0) { 948 n += row; 949 row = 0; 950 } 951 if (row + n > ri->ri_rows) 952 n = ri->ri_rows - row; 953 if (n <= 0) 954 return 0; 955 956 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 957 958 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 959 FBC_WRITE(sc, CG6_FBC_S, 0); 960 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 961 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 962 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 963 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 964 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 965 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 966 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL); 967 FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[bg]); 968 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 969 FBC_WRITE(sc, CG6_FBC_ARECTY, 0); 970 FBC_WRITE(sc, CG6_FBC_ARECTX, 0); 971 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_height - 1); 972 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_width - 1); 973 } else { 974 row *= ri->ri_font->fontheight; 975 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row); 976 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin); 977 FBC_WRITE(sc, CG6_FBC_ARECTY, 978 ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1); 979 FBC_WRITE(sc, CG6_FBC_ARECTX, 980 ri->ri_xorigin + ri->ri_emuwidth - 1); 981 } 982 CG6_DRAW_WAIT(sc); 983 CG6_DRAIN(sc); 984 985 return 0; 986 } 987 988 int 989 cgsix_ras_do_cursor(struct rasops_info *ri) 990 { 991 struct cgsix_softc *sc = ri->ri_hw; 992 int row, col; 993 994 row = ri->ri_crow * ri->ri_font->fontheight; 995 col = ri->ri_ccol * ri->ri_font->fontwidth; 996 FBC_WRITE(sc, CG6_FBC_CLIP, 0); 997 FBC_WRITE(sc, CG6_FBC_S, 0); 998 FBC_WRITE(sc, CG6_FBC_OFFX, 0); 999 FBC_WRITE(sc, CG6_FBC_OFFY, 0); 1000 FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0); 1001 FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0); 1002 FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1); 1003 FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1); 1004 FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FLIP); 1005 FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row); 1006 FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col); 1007 FBC_WRITE(sc, CG6_FBC_ARECTY, 1008 ri->ri_yorigin + row + ri->ri_font->fontheight - 1); 1009 FBC_WRITE(sc, CG6_FBC_ARECTX, 1010 ri->ri_xorigin + col + ri->ri_font->fontwidth - 1); 1011 CG6_DRAW_WAIT(sc); 1012 CG6_DRAIN(sc); 1013 1014 return 0; 1015 } 1016