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