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