1 /* $NetBSD: cgsix.c,v 1.74 2025/04/14 10:05:26 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This software was developed by the Computer Systems Engineering group 37 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 38 * contributed to Berkeley. 39 * 40 * All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Lawrence Berkeley Laboratory. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 * 69 * @(#)cgsix.c 8.4 (Berkeley) 1/21/94 70 */ 71 72 /* 73 * color display (cgsix) driver. 74 * 75 * Does not handle interrupts, even though they can occur. 76 * 77 * XXX should defer colormap updates to vertical retrace interrupts 78 */ 79 80 #include <sys/cdefs.h> 81 __KERNEL_RCSID(0, "$NetBSD: cgsix.c,v 1.74 2025/04/14 10:05:26 macallan Exp $"); 82 83 #include <sys/param.h> 84 #include <sys/systm.h> 85 #include <sys/buf.h> 86 #include <sys/device.h> 87 #include <sys/ioctl.h> 88 #include <sys/mman.h> 89 #include <sys/tty.h> 90 #include <sys/conf.h> 91 92 #ifdef DEBUG 93 #include <sys/proc.h> 94 #include <sys/syslog.h> 95 #endif 96 97 #include <sys/bus.h> 98 99 #include <dev/sun/fbio.h> 100 #include <dev/sun/fbvar.h> 101 102 #include <dev/sun/btreg.h> 103 #include <dev/sun/btvar.h> 104 #include <dev/sun/pfourreg.h> 105 106 #include <dev/wscons/wsconsio.h> 107 #include <dev/wsfont/wsfont.h> 108 #include <dev/rasops/rasops.h> 109 110 #include "opt_wsemul.h" 111 #include "rasops_glue.h" 112 113 #include <dev/sun/cgsixreg.h> 114 #include <dev/sun/cgsixvar.h> 115 116 #include "ioconf.h" 117 118 static void cg6_unblank(device_t); 119 static void cg6_blank(struct cgsix_softc *, int); 120 121 dev_type_open(cgsixopen); 122 dev_type_close(cgsixclose); 123 dev_type_ioctl(cgsixioctl); 124 dev_type_mmap(cgsixmmap); 125 126 const struct cdevsw cgsix_cdevsw = { 127 .d_open = cgsixopen, 128 .d_close = cgsixclose, 129 .d_read = noread, 130 .d_write = nowrite, 131 .d_ioctl = cgsixioctl, 132 .d_stop = nostop, 133 .d_tty = notty, 134 .d_poll = nopoll, 135 .d_mmap = cgsixmmap, 136 .d_kqfilter = nokqfilter, 137 .d_discard = nodiscard, 138 .d_flag = D_OTHER 139 }; 140 141 /* frame buffer generic driver */ 142 static struct fbdriver cg6_fbdriver = { 143 cg6_unblank, cgsixopen, cgsixclose, cgsixioctl, nopoll, cgsixmmap, 144 nokqfilter 145 }; 146 147 static void cg6_reset (struct cgsix_softc *); 148 static void cg6_loadcmap (struct cgsix_softc *, int, int); 149 static void cg6_loadomap (struct cgsix_softc *); 150 static void cg6_setcursor (struct cgsix_softc *);/* set position */ 151 static void cg6_loadcursor (struct cgsix_softc *);/* set shape */ 152 153 static void cg6_setup_palette(struct cgsix_softc *); 154 155 struct wsscreen_descr cgsix_defaultscreen = { 156 "std", 157 0, 0, /* will be filled in -- XXX shouldn't, it's global */ 158 NULL, /* textops */ 159 8, 16, /* font width/height */ 160 WSSCREEN_WSCOLORS | WSSCREEN_RESIZE | WSSCREEN_UNDERLINE, 161 NULL /* modecookie */ 162 }; 163 164 static int cgsix_ioctl(void *, void *, u_long, void *, int, struct lwp *); 165 static paddr_t cgsix_mmap(void *, void *, off_t, int); 166 static void cgsix_init_screen(void *, struct vcons_screen *, int, long *); 167 168 static void cgsix_clearscreen(struct cgsix_softc *); 169 170 void cgsix_setup_mono(struct cgsix_softc *, int, int, int, int, uint32_t, 171 uint32_t); 172 void cgsix_feed_line(struct cgsix_softc *, int, uint8_t *); 173 void cgsix_rectfill(struct cgsix_softc *, int, int, int, int, uint32_t); 174 void cgsix_bitblt(void *, int, int, int, int, int, int, int); 175 176 int cgsix_putcmap(struct cgsix_softc *, struct wsdisplay_cmap *); 177 int cgsix_getcmap(struct cgsix_softc *, struct wsdisplay_cmap *); 178 void cgsix_putchar(void *, int, int, u_int, long); 179 void cgsix_putchar_aa(void *, int, int, u_int, long); 180 void cgsix_cursor(void *, int, int, int); 181 182 struct wsdisplay_accessops cgsix_accessops = { 183 cgsix_ioctl, 184 cgsix_mmap, 185 NULL, /* alloc_screen */ 186 NULL, /* free_screen */ 187 NULL, /* show_screen */ 188 NULL, /* load_font */ 189 NULL, /* pollc */ 190 NULL /* scroll */ 191 }; 192 193 const struct wsscreen_descr *_cgsix_scrlist[] = { 194 &cgsix_defaultscreen 195 }; 196 197 struct wsscreen_list cgsix_screenlist = { 198 sizeof(_cgsix_scrlist) / sizeof(struct wsscreen_descr *), 199 _cgsix_scrlist 200 }; 201 202 203 extern const u_char rasops_cmap[768]; 204 205 void cg6_invert(struct cgsix_softc *, int, int, int, int); 206 207 static struct vcons_screen cg6_console_screen; 208 209 /* 210 * cg6 accelerated console routines. 211 * 212 * Note that buried in this code in several places is the assumption 213 * that pixels are exactly one byte wide. Since this is cg6-specific 214 * code, this seems safe. This assumption resides in things like the 215 * use of ri_emuwidth without messing around with ri_pelbytes, or the 216 * assumption that ri_font->fontwidth is the right thing to multiply 217 * character-cell counts by to get byte counts. 218 */ 219 220 /* 221 * Magic values for blitter 222 */ 223 224 /* Values for the mode register */ 225 #define CG6_MODE ( \ 226 0x00200000 /* GX_BLIT_SRC */ \ 227 | 0x00020000 /* GX_MODE_COLOR8 */ \ 228 | 0x00008000 /* GX_DRAW_RENDER */ \ 229 | 0x00002000 /* GX_BWRITE0_ENABLE */ \ 230 | 0x00001000 /* GX_BWRITE1_DISABLE */ \ 231 | 0x00000200 /* GX_BREAD_0 */ \ 232 | 0x00000080 /* GX_BDISP_0 */ \ 233 ) 234 #define CG6_MODE_MASK ( \ 235 0x00300000 /* GX_BLIT_ALL */ \ 236 | 0x00060000 /* GX_MODE_ALL */ \ 237 | 0x00018000 /* GX_DRAW_ALL */ \ 238 | 0x00006000 /* GX_BWRITE0_ALL */ \ 239 | 0x00001800 /* GX_BWRITE1_ALL */ \ 240 | 0x00000600 /* GX_BREAD_ALL */ \ 241 | 0x00000180 /* GX_BDISP_ALL */ \ 242 ) 243 244 /* Value for the alu register for screen-to-screen copies */ 245 #define CG6_ALU_COPY ( \ 246 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ 247 | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ 248 | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ 249 | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ 250 | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ 251 | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ 252 | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ 253 | 0x0000cccc /* ALU = src */ \ 254 ) 255 256 /* Value for the alu register for region fills */ 257 #define CG6_ALU_FILL ( \ 258 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ 259 | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ 260 | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ 261 | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ 262 | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ 263 | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ 264 | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ 265 | 0x0000ff00 /* ALU = fg color */ \ 266 ) 267 268 /* Value for the alu register for toggling an area */ 269 #define CG6_ALU_FLIP ( \ 270 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ 271 | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ 272 | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ 273 | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ 274 | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ 275 | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ 276 | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ 277 | 0x00005555 /* ALU = ~dst */ \ 278 ) 279 280 /* 281 * Run a blitter command 282 */ 283 #define CG6_BLIT(f) { (void)f->fbc_blit; } 284 285 /* 286 * Run a drawing command 287 */ 288 #define CG6_DRAW(f) { (void)f->fbc_draw; } 289 290 /* 291 * Wait for the whole engine to go idle. This may not matter in our case; 292 * I'm not sure whether blits are actually queued or not. It more likely 293 * is intended for lines and such that do get queued. 294 * 0x10000000 bit: GX_INPROGRESS 295 */ 296 #define CG6_DRAIN(fbc) do { \ 297 while ((fbc)->fbc_s & GX_INPROGRESS) \ 298 /*EMPTY*/; \ 299 } while (0) 300 301 /* 302 * something is missing here 303 * Waiting for GX_FULL to clear should be enough to send another command 304 * but some CG6 ( LX onboard for example ) lock up if we do that while 305 * it works fine on others ( a 4MB TGX+ I've got here ) 306 * So, until I figure out what's going on we wait for the blitter to go 307 * fully idle. 308 */ 309 #define CG6_WAIT_READY(fbc) do { \ 310 while (((fbc)->fbc_s & GX_INPROGRESS/*GX_FULL*/) != 0) \ 311 /*EMPTY*/; \ 312 } while (0) 313 314 static void cg6_ras_init(struct cgsix_softc *); 315 static void cg6_ras_copyrows(void *, int, int, int); 316 static void cg6_ras_copycols(void *, int, int, int, int); 317 static void cg6_ras_erasecols(void *, int, int, int, long int); 318 static void cg6_ras_eraserows(void *, int, int, long int); 319 320 static void 321 cg6_ras_init(struct cgsix_softc *sc) 322 { 323 volatile struct cg6_fbc *fbc = sc->sc_fbc; 324 325 CG6_DRAIN(fbc); 326 fbc->fbc_mode &= ~CG6_MODE_MASK; 327 fbc->fbc_mode |= CG6_MODE; 328 329 /* set some common drawing engine parameters */ 330 fbc->fbc_clip = 0; 331 fbc->fbc_s = 0; 332 fbc->fbc_offx = 0; 333 fbc->fbc_offy = 0; 334 fbc->fbc_clipminx = 0; 335 fbc->fbc_clipminy = 0; 336 fbc->fbc_clipmaxx = 0x3fff; 337 fbc->fbc_clipmaxy = 0x3fff; 338 } 339 340 static void 341 cg6_ras_nuke_cursor(struct rasops_info *ri) 342 { 343 struct vcons_screen *scr = ri->ri_hw; 344 struct cgsix_softc *sc = scr->scr_cookie; 345 int wi, he, x, y; 346 347 if (ri->ri_flg & RI_CURSOR) { 348 wi = ri->ri_font->fontwidth; 349 he = ri->ri_font->fontheight; 350 x = ri->ri_ccol * wi + ri->ri_xorigin; 351 y = ri->ri_crow * he + ri->ri_yorigin; 352 cg6_invert(sc, x, y, wi, he); 353 ri->ri_flg &= ~RI_CURSOR; 354 } 355 } 356 357 static void 358 cg6_ras_copyrows(void *cookie, int src, int dst, int n) 359 { 360 struct rasops_info *ri = cookie; 361 struct vcons_screen *scr = ri->ri_hw; 362 struct cgsix_softc *sc = scr->scr_cookie; 363 volatile struct cg6_fbc *fbc = sc->sc_fbc; 364 365 if (dst == src) 366 return; 367 368 if ((ri->ri_crow >= src && ri->ri_crow < (src + n)) && 369 (ri->ri_flg & RI_CURSOR)) { 370 cg6_ras_nuke_cursor(ri); 371 } 372 373 if (ri->ri_crow >= dst && ri->ri_crow < (dst + n)) 374 ri->ri_flg &= ~RI_CURSOR; 375 376 n *= ri->ri_font->fontheight; 377 src *= ri->ri_font->fontheight; 378 dst *= ri->ri_font->fontheight; 379 380 CG6_WAIT_READY(fbc); 381 382 fbc->fbc_alu = CG6_ALU_COPY; 383 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 384 385 fbc->fbc_x0 = ri->ri_xorigin; 386 fbc->fbc_y0 = ri->ri_yorigin + src; 387 fbc->fbc_x1 = ri->ri_xorigin + ri->ri_emuwidth - 1; 388 fbc->fbc_y1 = ri->ri_yorigin + src + n - 1; 389 fbc->fbc_x2 = ri->ri_xorigin; 390 fbc->fbc_y2 = ri->ri_yorigin + dst; 391 fbc->fbc_x3 = ri->ri_xorigin + ri->ri_emuwidth - 1; 392 fbc->fbc_y3 = ri->ri_yorigin + dst + n - 1; 393 CG6_BLIT(fbc); 394 } 395 396 static void 397 cg6_ras_copycols(void *cookie, int row, int src, int dst, int n) 398 { 399 struct rasops_info *ri = cookie; 400 struct vcons_screen *scr = ri->ri_hw; 401 struct cgsix_softc *sc = scr->scr_cookie; 402 volatile struct cg6_fbc *fbc = sc->sc_fbc; 403 404 if (dst == src) 405 return; 406 407 if ((row < 0) || (row >= ri->ri_rows)) 408 return; 409 410 if (ri->ri_crow == row && 411 (ri->ri_ccol >= src && ri->ri_ccol < (src + n)) && 412 (ri->ri_flg & RI_CURSOR)) { 413 cg6_ras_nuke_cursor(ri); 414 } 415 416 if (ri->ri_crow == row && 417 (ri->ri_ccol >= dst && ri->ri_ccol < (dst + n))) 418 ri->ri_flg &= ~RI_CURSOR; 419 420 n *= ri->ri_font->fontwidth; 421 src *= ri->ri_font->fontwidth; 422 dst *= ri->ri_font->fontwidth; 423 row *= ri->ri_font->fontheight; 424 425 CG6_WAIT_READY(fbc); 426 427 fbc->fbc_alu = CG6_ALU_COPY; 428 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 429 430 fbc->fbc_x0 = ri->ri_xorigin + src; 431 fbc->fbc_y0 = ri->ri_yorigin + row; 432 fbc->fbc_x1 = ri->ri_xorigin + src + n - 1; 433 fbc->fbc_y1 = ri->ri_yorigin + row + 434 ri->ri_font->fontheight - 1; 435 fbc->fbc_x2 = ri->ri_xorigin + dst; 436 fbc->fbc_y2 = ri->ri_yorigin + row; 437 fbc->fbc_x3 = ri->ri_xorigin + dst + n - 1; 438 fbc->fbc_y3 = ri->ri_yorigin + row + 439 ri->ri_font->fontheight - 1; 440 CG6_BLIT(fbc); 441 } 442 443 static void 444 cg6_ras_erasecols(void *cookie, int row, int col, int n, long int attr) 445 { 446 struct rasops_info *ri = cookie; 447 struct vcons_screen *scr = ri->ri_hw; 448 struct cgsix_softc *sc = scr->scr_cookie; 449 volatile struct cg6_fbc *fbc = sc->sc_fbc; 450 451 if (ri->ri_crow == row && 452 (ri->ri_ccol >= col && ri->ri_ccol < (col + n))) 453 ri->ri_flg &= ~RI_CURSOR; 454 455 n *= ri->ri_font->fontwidth; 456 col *= ri->ri_font->fontwidth; 457 row *= ri->ri_font->fontheight; 458 459 CG6_WAIT_READY(fbc); 460 fbc->fbc_alu = CG6_ALU_FILL; 461 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 462 463 fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xff]; 464 fbc->fbc_arecty = ri->ri_yorigin + row; 465 fbc->fbc_arectx = ri->ri_xorigin + col; 466 fbc->fbc_arecty = ri->ri_yorigin + row + 467 ri->ri_font->fontheight - 1; 468 fbc->fbc_arectx = ri->ri_xorigin + col + n - 1; 469 CG6_DRAW(fbc); 470 } 471 472 static void 473 cg6_ras_eraserows(void *cookie, int row, int n, long int attr) 474 { 475 struct rasops_info *ri = cookie; 476 struct vcons_screen *scr = ri->ri_hw; 477 struct cgsix_softc *sc = scr->scr_cookie; 478 volatile struct cg6_fbc *fbc = sc->sc_fbc; 479 480 if (ri->ri_crow >= row && ri->ri_crow < (row + n)) 481 ri->ri_flg &= ~RI_CURSOR; 482 483 CG6_WAIT_READY(fbc); 484 fbc->fbc_alu = CG6_ALU_FILL; 485 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 486 487 fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xff]; 488 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 489 fbc->fbc_arecty = 0; 490 fbc->fbc_arectx = 0; 491 fbc->fbc_arecty = ri->ri_height - 1; 492 fbc->fbc_arectx = ri->ri_width - 1; 493 } else { 494 row *= ri->ri_font->fontheight; 495 fbc->fbc_arecty = ri->ri_yorigin + row; 496 fbc->fbc_arectx = ri->ri_xorigin; 497 fbc->fbc_arecty = ri->ri_yorigin + row + 498 (n * ri->ri_font->fontheight) - 1; 499 fbc->fbc_arectx = ri->ri_xorigin + ri->ri_emuwidth - 1; 500 } 501 CG6_DRAW(fbc); 502 } 503 504 void 505 cg6attach(struct cgsix_softc *sc, const char *name, int isconsole) 506 { 507 struct fbdevice *fb = &sc->sc_fb; 508 struct wsemuldisplaydev_attach_args aa; 509 struct rasops_info *ri = &cg6_console_screen.scr_ri; 510 unsigned long defattr; 511 512 fb->fb_driver = &cg6_fbdriver; 513 514 /* Don't have to map the pfour register on the cgsix. */ 515 fb->fb_pfour = NULL; 516 517 fb->fb_type.fb_cmsize = 256; 518 fb->fb_type.fb_size = sc->sc_ramsize; 519 520 printf(": %s, %d x %d", name, 521 fb->fb_type.fb_width, fb->fb_type.fb_height); 522 if(sc->sc_fhc) { 523 sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) & 524 (FHC_REV_MASK >> FHC_REV_SHIFT); 525 } else 526 sc->sc_fhcrev=-1; 527 printf(", rev %d", sc->sc_fhcrev); 528 529 /* reset cursor & frame buffer controls */ 530 cg6_reset(sc); 531 532 /* enable video */ 533 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 534 535 if (isconsole) { 536 printf(" (console)"); 537 } 538 printf("\n"); 539 540 fb_attach(&sc->sc_fb, isconsole); 541 sc->sc_width = fb->fb_type.fb_width; 542 sc->sc_stride = fb->fb_type.fb_width; 543 sc->sc_height = fb->fb_type.fb_height; 544 545 printf("%s: framebuffer size: %d MB\n", device_xname(sc->sc_dev), 546 sc->sc_ramsize >> 20); 547 548 /* setup rasops and so on for wsdisplay */ 549 memcpy(sc->sc_default_cmap, rasops_cmap, 768); 550 wsfont_init(); 551 cg6_ras_init(sc); 552 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 553 sc->sc_bg = WS_DEFAULT_BG; 554 sc->sc_fb_is_open = FALSE; 555 556 vcons_init(&sc->vd, sc, &cgsix_defaultscreen, &cgsix_accessops); 557 sc->vd.init_screen = cgsix_init_screen; 558 559 sc->sc_gc.gc_bitblt = cgsix_bitblt; 560 sc->sc_gc.gc_blitcookie = sc; 561 sc->sc_gc.gc_rop = CG6_ALU_COPY; 562 sc->vd.show_screen_cookie = &sc->sc_gc; 563 sc->vd.show_screen_cb = glyphcache_adapt; 564 565 if(isconsole) { 566 /* we mess with cg6_console_screen only once */ 567 vcons_init_screen(&sc->vd, &cg6_console_screen, 1, 568 &defattr); 569 sc->sc_bg = (defattr >> 16) & 0xf; /* yes, this is an index into devcmap */ 570 571 /* 572 * XXX 573 * Is this actually necessary? We're going to use the blitter later on anyway. 574 */ 575 /* We need unaccelerated initial screen clear on old revisions */ 576 if (sc->sc_fhcrev < 2) { 577 memset(sc->sc_fb.fb_pixels, ri->ri_devcmap[sc->sc_bg], 578 sc->sc_stride * sc->sc_height); 579 } else 580 cgsix_clearscreen(sc); 581 582 cg6_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 583 584 cgsix_defaultscreen.textops = &ri->ri_ops; 585 cgsix_defaultscreen.capabilities = ri->ri_caps; 586 cgsix_defaultscreen.nrows = ri->ri_rows; 587 cgsix_defaultscreen.ncols = ri->ri_cols; 588 SCREEN_VISIBLE(&cg6_console_screen); 589 sc->vd.active = &cg6_console_screen; 590 wsdisplay_cnattach(&cgsix_defaultscreen, ri, 0, 0, defattr); 591 if (ri->ri_flg & RI_ENABLE_ALPHA) { 592 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 593 (sc->sc_ramsize / sc->sc_stride) - 594 sc->sc_height - 5, 595 sc->sc_width, 596 ri->ri_font->fontwidth, 597 ri->ri_font->fontheight, 598 defattr); 599 } 600 vcons_replay_msgbuf(&cg6_console_screen); 601 } else { 602 /* 603 * since we're not the console we can postpone the rest 604 * until someone actually allocates a screen for us 605 */ 606 if (cg6_console_screen.scr_ri.ri_rows == 0) { 607 /* do some minimal setup to avoid weirdnesses later */ 608 vcons_init_screen(&sc->vd, &cg6_console_screen, 1, 609 &defattr); 610 } else 611 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 612 sc->sc_bg = (defattr >> 16) & 0xf; 613 if (ri->ri_flg & RI_ENABLE_ALPHA) { 614 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 615 (sc->sc_ramsize / sc->sc_stride) - 616 sc->sc_height - 5, 617 sc->sc_width, 618 ri->ri_font->fontwidth, 619 ri->ri_font->fontheight, 620 defattr); 621 } 622 } 623 cg6_setup_palette(sc); 624 625 aa.scrdata = &cgsix_screenlist; 626 aa.console = isconsole; 627 aa.accessops = &cgsix_accessops; 628 aa.accesscookie = &sc->vd; 629 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 630 } 631 632 633 int 634 cgsixopen(dev_t dev, int flags, int mode, struct lwp *l) 635 { 636 device_t dv = device_lookup(&cgsix_cd, minor(dev)); 637 struct cgsix_softc *sc = device_private(dv); 638 639 if (dv == NULL) 640 return ENXIO; 641 sc->sc_fb_is_open = TRUE; 642 643 return 0; 644 } 645 646 int 647 cgsixclose(dev_t dev, int flags, int mode, struct lwp *l) 648 { 649 device_t dv = device_lookup(&cgsix_cd, minor(dev)); 650 struct cgsix_softc *sc = device_private(dv); 651 652 cg6_reset(sc); 653 sc->sc_fb_is_open = FALSE; 654 655 if (IS_IN_EMUL_MODE(sc)) { 656 struct vcons_screen *ms = sc->vd.active; 657 658 cg6_ras_init(sc); 659 cg6_setup_palette(sc); 660 glyphcache_wipe(&sc->sc_gc); 661 662 /* we don't know if the screen exists */ 663 if (ms != NULL) 664 vcons_redraw_screen(ms); 665 } 666 return 0; 667 } 668 669 int 670 cgsixioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 671 { 672 struct cgsix_softc *sc = device_lookup_private(&cgsix_cd, minor(dev)); 673 union cursor_cmap tcm; 674 uint32_t image[32], mask[32]; 675 u_int count; 676 int v, error; 677 678 #ifdef CGSIX_DEBUG 679 printf("cgsixioctl(%lx)\n",cmd); 680 #endif 681 682 switch (cmd) { 683 684 case FBIOGTYPE: 685 *(struct fbtype *)data = sc->sc_fb.fb_type; 686 break; 687 688 case FBIOGATTR: 689 #define fba ((struct fbgattr *)data) 690 fba->real_type = sc->sc_fb.fb_type.fb_type; 691 fba->owner = 0; /* XXX ??? */ 692 fba->fbtype = sc->sc_fb.fb_type; 693 fba->sattr.flags = 0; 694 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 695 fba->sattr.dev_specific[0] = -1; 696 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 697 fba->emu_types[1] = -1; 698 #undef fba 699 break; 700 701 case FBIOGETCMAP: 702 #define p ((struct fbcmap *)data) 703 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 704 705 case FBIOPUTCMAP: 706 /* copy to software map */ 707 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 708 if (error) 709 return error; 710 /* now blast them into the chip */ 711 /* XXX should use retrace interrupt */ 712 cg6_loadcmap(sc, p->index, p->count); 713 #undef p 714 break; 715 716 case FBIOGVIDEO: 717 *(int *)data = sc->sc_blanked; 718 break; 719 720 case FBIOSVIDEO: 721 cg6_blank(sc, !(*(int *)data)); 722 break; 723 724 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 725 #define p ((struct fbcursor *)data) 726 #define cc (&sc->sc_cursor) 727 728 case FBIOGCURSOR: 729 /* do not quite want everything here... */ 730 p->set = FB_CUR_SETALL; /* close enough, anyway */ 731 p->enable = cc->cc_enable; 732 p->pos = cc->cc_pos; 733 p->hot = cc->cc_hot; 734 p->size = cc->cc_size; 735 736 /* begin ugh ... can we lose some of this crap?? */ 737 if (p->image != NULL) { 738 count = cc->cc_size.y * 32 / NBBY; 739 error = copyout(cc->cc_bits[1], p->image, count); 740 if (error) 741 return error; 742 error = copyout(cc->cc_bits[0], p->mask, count); 743 if (error) 744 return error; 745 } 746 if (p->cmap.red != NULL) { 747 error = bt_getcmap(&p->cmap, 748 (union bt_cmap *)&cc->cc_color, 2, 1); 749 if (error) 750 return error; 751 } else { 752 p->cmap.index = 0; 753 p->cmap.count = 2; 754 } 755 /* end ugh */ 756 break; 757 758 case FBIOSCURSOR: 759 /* 760 * For setcmap and setshape, verify parameters, so that 761 * we do not get halfway through an update and then crap 762 * out with the software state screwed up. 763 */ 764 v = p->set; 765 if (v & FB_CUR_SETCMAP) { 766 /* 767 * This use of a temporary copy of the cursor 768 * colormap is not terribly efficient, but these 769 * copies are small (8 bytes)... 770 */ 771 tcm = cc->cc_color; 772 error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2, 773 1); 774 if (error) 775 return error; 776 } 777 if (v & FB_CUR_SETSHAPE) { 778 if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32) 779 return EINVAL; 780 count = p->size.y * 32 / NBBY; 781 error = copyin(p->image, image, count); 782 if (error) 783 return error; 784 error = copyin(p->mask, mask, count); 785 if (error) 786 return error; 787 } 788 789 /* parameters are OK; do it */ 790 if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { 791 if (v & FB_CUR_SETCUR) 792 cc->cc_enable = p->enable; 793 if (v & FB_CUR_SETPOS) 794 cc->cc_pos = p->pos; 795 if (v & FB_CUR_SETHOT) 796 cc->cc_hot = p->hot; 797 cg6_setcursor(sc); 798 } 799 if (v & FB_CUR_SETCMAP) { 800 cc->cc_color = tcm; 801 cg6_loadomap(sc); /* XXX defer to vertical retrace */ 802 } 803 if (v & FB_CUR_SETSHAPE) { 804 cc->cc_size = p->size; 805 count = p->size.y * 32 / NBBY; 806 memset(cc->cc_bits, 0, sizeof cc->cc_bits); 807 memcpy(cc->cc_bits[1], image, count); 808 memcpy(cc->cc_bits[0], mask, count); 809 cg6_loadcursor(sc); 810 } 811 break; 812 813 #undef p 814 #undef cc 815 816 case FBIOGCURPOS: 817 *(struct fbcurpos *)data = sc->sc_cursor.cc_pos; 818 break; 819 820 case FBIOSCURPOS: 821 sc->sc_cursor.cc_pos = *(struct fbcurpos *)data; 822 cg6_setcursor(sc); 823 break; 824 825 case FBIOGCURMAX: 826 /* max cursor size is 32x32 */ 827 ((struct fbcurpos *)data)->x = 32; 828 ((struct fbcurpos *)data)->y = 32; 829 break; 830 831 default: 832 #ifdef DEBUG 833 log(LOG_NOTICE, "cgsixioctl(0x%lx) (%s[%d])\n", cmd, 834 l->l_proc->p_comm, l->l_proc->p_pid); 835 #endif 836 return ENOTTY; 837 } 838 return 0; 839 } 840 841 /* 842 * Clean up hardware state (e.g., after bootup or after X crashes). 843 */ 844 static void 845 cg6_reset(struct cgsix_softc *sc) 846 { 847 volatile struct cg6_tec_xxx *tec; 848 int fhc; 849 volatile struct bt_regs *bt; 850 851 /* hide the cursor, just in case */ 852 sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF; 853 854 /* turn off frobs in transform engine (makes X11 work) */ 855 tec = sc->sc_tec; 856 tec->tec_mv = 0; 857 tec->tec_clip = 0; 858 tec->tec_vdc = 0; 859 860 /* take care of hardware bugs in old revisions */ 861 if (sc->sc_fhcrev < 5) { 862 /* 863 * Keep current resolution; set CPU to 68020, set test 864 * window (size 1Kx1K), and for rev 1, disable dest cache. 865 */ 866 fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 | 867 FHC_TEST | 868 (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT); 869 if (sc->sc_fhcrev < 2) 870 fhc |= FHC_DST_DISABLE; 871 *sc->sc_fhc = fhc; 872 } 873 874 /* Enable cursor in Brooktree DAC. */ 875 bt = sc->sc_bt; 876 bt->bt_addr = 0x06 << 24; 877 bt->bt_ctrl |= 0x03 << 24; 878 } 879 880 static void 881 cg6_setcursor(struct cgsix_softc *sc) 882 { 883 884 /* we need to subtract the hot-spot value here */ 885 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f) 886 sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ? 887 ((COORD(x) << 16) | (COORD(y) & 0xffff)) : 888 (THC_CURSOFF << 16) | THC_CURSOFF; 889 #undef COORD 890 } 891 892 static void 893 cg6_loadcursor(struct cgsix_softc *sc) 894 { 895 volatile struct cg6_thc *thc; 896 u_int edgemask, m; 897 int i; 898 899 /* 900 * Keep the top size.x bits. Here we *throw out* the top 901 * size.x bits from an all-one-bits word, introducing zeros in 902 * the top size.x bits, then invert all the bits to get what 903 * we really wanted as our mask. But this fails if size.x is 904 * 32---a sparc uses only the low 5 bits of the shift count--- 905 * so we have to special case that. 906 */ 907 edgemask = ~0; 908 if (sc->sc_cursor.cc_size.x < 32) 909 edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x); 910 thc = sc->sc_thc; 911 for (i = 0; i < 32; i++) { 912 m = sc->sc_cursor.cc_bits[0][i] & edgemask; 913 thc->thc_cursmask[i] = m; 914 thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i]; 915 } 916 } 917 918 /* 919 * Load a subset of the current (new) colormap into the color DAC. 920 */ 921 static void 922 cg6_loadcmap(struct cgsix_softc *sc, int start, int ncolors) 923 { 924 volatile struct bt_regs *bt; 925 u_int *ip, i; 926 int count; 927 928 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 929 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 930 bt = sc->sc_bt; 931 bt->bt_addr = BT_D4M4(start) << 24; 932 while (--count >= 0) { 933 i = *ip++; 934 /* hardware that makes one want to pound boards with hammers */ 935 bt->bt_cmap = i; 936 bt->bt_cmap = i << 8; 937 bt->bt_cmap = i << 16; 938 bt->bt_cmap = i << 24; 939 } 940 } 941 942 /* 943 * Load the cursor (overlay `foreground' and `background') colors. 944 */ 945 static void 946 cg6_loadomap(struct cgsix_softc *sc) 947 { 948 volatile struct bt_regs *bt; 949 u_int i; 950 951 bt = sc->sc_bt; 952 bt->bt_addr = 0x01 << 24; /* set background color */ 953 i = sc->sc_cursor.cc_color.cm_chip[0]; 954 bt->bt_omap = i; /* R */ 955 bt->bt_omap = i << 8; /* G */ 956 bt->bt_omap = i << 16; /* B */ 957 958 bt->bt_addr = 0x03 << 24; /* set foreground color */ 959 bt->bt_omap = i << 24; /* R */ 960 i = sc->sc_cursor.cc_color.cm_chip[1]; 961 bt->bt_omap = i; /* G */ 962 bt->bt_omap = i << 8; /* B */ 963 } 964 965 /* blank or unblank the screen */ 966 static void 967 cg6_blank(struct cgsix_softc *sc, int flag) 968 { 969 970 if (sc->sc_blanked != flag) { 971 sc->sc_blanked = flag; 972 if (flag) { 973 sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN; 974 } else { 975 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 976 } 977 } 978 } 979 980 /* 981 * this is called on panic or ddb entry - force the console to the front, reset 982 * the colour map and enable drawing so we actually see the message even when X 983 * is running 984 */ 985 static void 986 cg6_unblank(device_t dev) 987 { 988 struct cgsix_softc *sc = device_private(dev); 989 990 cg6_blank(sc, 0); 991 } 992 993 /* XXX the following should be moved to a "user interface" header */ 994 /* 995 * Base addresses at which users can mmap() the various pieces of a cg6. 996 * Note that although the Brooktree color registers do not occupy 8K, 997 * the X server dies if we do not allow it to map 8K there (it just maps 998 * from 0x70000000 forwards, as a contiguous chunk). 999 */ 1000 #define CG6_USER_FBC 0x70000000 1001 #define CG6_USER_TEC 0x70001000 1002 #define CG6_USER_BTREGS 0x70002000 1003 #define CG6_USER_FHC 0x70004000 1004 #define CG6_USER_THC 0x70005000 1005 #define CG6_USER_ROM 0x70006000 1006 #define CG6_USER_RAM 0x70016000 1007 #define CG6_USER_DHC 0x80000000 1008 1009 struct mmo { 1010 u_long mo_uaddr; /* user (virtual) address */ 1011 u_long mo_size; /* size, or 0 for video ram size */ 1012 u_long mo_physoff; /* offset from sc_physadr */ 1013 }; 1014 1015 /* 1016 * Return the address that would map the given device at the given 1017 * offset, allowing for the given protection, or return -1 for error. 1018 * 1019 * XXX needs testing against `demanding' applications (e.g., aviator) 1020 */ 1021 paddr_t 1022 cgsixmmap(dev_t dev, off_t off, int prot) 1023 { 1024 struct cgsix_softc *sc = device_lookup_private(&cgsix_cd, minor(dev)); 1025 struct mmo *mo; 1026 u_int u, sz, flags; 1027 static struct mmo mmo[] = { 1028 { CG6_USER_RAM, 0, CGSIX_RAM_OFFSET }, 1029 1030 /* do not actually know how big most of these are! */ 1031 { CG6_USER_FBC, 1, CGSIX_FBC_OFFSET }, 1032 { CG6_USER_TEC, 1, CGSIX_TEC_OFFSET }, 1033 { CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET }, 1034 { CG6_USER_FHC, 1, CGSIX_FHC_OFFSET }, 1035 { CG6_USER_THC, sizeof(struct cg6_thc), CGSIX_THC_OFFSET }, 1036 { CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET }, 1037 { CG6_USER_DHC, 1, CGSIX_DHC_OFFSET }, 1038 }; 1039 #define NMMO (sizeof mmo / sizeof *mmo) 1040 1041 if (off & PGOFSET) 1042 panic("cgsixmmap"); 1043 1044 /* 1045 * Entries with size 0 map video RAM (i.e., the size in fb data). 1046 * 1047 * Since we work in pages, the fact that the map offset table's 1048 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 1049 * one byte is as good as one page. 1050 */ 1051 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 1052 if ((u_long)off < mo->mo_uaddr) 1053 continue; 1054 u = off - mo->mo_uaddr; 1055 if (mo->mo_size == 0) { 1056 flags = BUS_SPACE_MAP_LINEAR; 1057 sz = sc->sc_ramsize; 1058 } else { 1059 flags = BUS_SPACE_MAP_LINEAR; 1060 sz = mo->mo_size; 1061 } 1062 if (u < sz) { 1063 return (bus_space_mmap(sc->sc_bustag, 1064 sc->sc_paddr, u+mo->mo_physoff, 1065 prot, flags)); 1066 } 1067 } 1068 1069 #ifdef DEBUG 1070 { 1071 struct proc *p = curlwp->l_proc; /* XXX */ 1072 log(LOG_NOTICE, "cgsixmmap(0x%llx) (%s[%d])\n", 1073 (long long)off, p->p_comm, p->p_pid); 1074 } 1075 #endif 1076 return -1; /* not a user-map offset */ 1077 } 1078 1079 static void 1080 cg6_setup_palette(struct cgsix_softc *sc) 1081 { 1082 int i, j; 1083 1084 rasops_get_cmap(&cg6_console_screen.scr_ri, sc->sc_default_cmap, 1085 sizeof(sc->sc_default_cmap)); 1086 j = 0; 1087 for (i = 0; i < 256; i++) { 1088 sc->sc_cmap.cm_map[i][0] = sc->sc_default_cmap[j]; 1089 j++; 1090 sc->sc_cmap.cm_map[i][1] = sc->sc_default_cmap[j]; 1091 j++; 1092 sc->sc_cmap.cm_map[i][2] = sc->sc_default_cmap[j]; 1093 j++; 1094 } 1095 cg6_loadcmap(sc, 0, 256); 1096 } 1097 1098 int 1099 cgsix_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 1100 struct lwp *l) 1101 { 1102 /* we'll probably need to add more stuff here */ 1103 struct vcons_data *vd = v; 1104 struct cgsix_softc *sc = vd->cookie; 1105 struct wsdisplay_fbinfo *wdf; 1106 struct vcons_screen *ms = sc->vd.active; 1107 1108 #ifdef CGSIX_DEBUG 1109 printf("cgsix_ioctl(%lx)\n",cmd); 1110 #endif 1111 switch (cmd) { 1112 case WSDISPLAYIO_GTYPE: 1113 *(u_int *)data = WSDISPLAY_TYPE_SUNTCX; 1114 return 0; 1115 case WSDISPLAYIO_GINFO: 1116 wdf = (void *)data; 1117 wdf->height = sc->sc_height; 1118 wdf->width = sc->sc_width; 1119 wdf->depth = 8; 1120 wdf->cmsize = 256; 1121 return 0; 1122 1123 case WSDISPLAYIO_GETCMAP: 1124 return cgsix_getcmap(sc, 1125 (struct wsdisplay_cmap *)data); 1126 case WSDISPLAYIO_PUTCMAP: 1127 return cgsix_putcmap(sc, 1128 (struct wsdisplay_cmap *)data); 1129 1130 case WSDISPLAYIO_LINEBYTES: 1131 *(u_int *)data = sc->sc_stride; 1132 return 0; 1133 1134 case WSDISPLAYIO_SMODE: 1135 { 1136 int new_mode = *(int*)data; 1137 1138 if (new_mode != sc->sc_mode) { 1139 sc->sc_mode = new_mode; 1140 if (IS_IN_EMUL_MODE(sc)) { 1141 cg6_reset(sc); 1142 cg6_ras_init(sc); 1143 cg6_setup_palette(sc); 1144 glyphcache_wipe(&sc->sc_gc); 1145 vcons_redraw_screen(ms); 1146 } 1147 } 1148 } 1149 return 0; 1150 case WSDISPLAYIO_GET_FBINFO: 1151 { 1152 struct wsdisplayio_fbinfo *fbi = data; 1153 1154 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 1155 } 1156 } 1157 return EPASSTHROUGH; 1158 } 1159 1160 paddr_t 1161 cgsix_mmap(void *v, void *vs, off_t offset, int prot) 1162 { 1163 struct vcons_data *vd = v; 1164 struct cgsix_softc *sc = vd->cookie; 1165 1166 if (offset < sc->sc_ramsize) { 1167 return bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 1168 CGSIX_RAM_OFFSET + offset, prot, 1169 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 1170 } 1171 return -1; 1172 } 1173 1174 int 1175 cgsix_putcmap(struct cgsix_softc *sc, struct wsdisplay_cmap *cm) 1176 { 1177 u_int index = cm->index; 1178 u_int count = cm->count; 1179 int error, i; 1180 1181 if (index >= 256 || count > 256 || index + count > 256) 1182 return EINVAL; 1183 1184 for (i = 0; i < count; i++) 1185 { 1186 error = copyin(&cm->red[i], 1187 &sc->sc_cmap.cm_map[index + i][0], 1); 1188 if (error) 1189 return error; 1190 error = copyin(&cm->green[i], 1191 &sc->sc_cmap.cm_map[index + i][1], 1192 1); 1193 if (error) 1194 return error; 1195 error = copyin(&cm->blue[i], 1196 &sc->sc_cmap.cm_map[index + i][2], 1); 1197 if (error) 1198 return error; 1199 } 1200 cg6_loadcmap(sc, index, count); 1201 1202 return 0; 1203 } 1204 1205 int 1206 cgsix_getcmap(struct cgsix_softc *sc, struct wsdisplay_cmap *cm) 1207 { 1208 u_int index = cm->index; 1209 u_int count = cm->count; 1210 int error,i; 1211 1212 if (index >= 256 || count > 256 || index + count > 256) 1213 return EINVAL; 1214 1215 for (i = 0; i < count; i++) 1216 { 1217 error = copyout(&sc->sc_cmap.cm_map[index + i][0], 1218 &cm->red[i], 1); 1219 if (error) 1220 return error; 1221 error = copyout(&sc->sc_cmap.cm_map[index + i][1], 1222 &cm->green[i], 1); 1223 if (error) 1224 return error; 1225 error = copyout(&sc->sc_cmap.cm_map[index + i][2], 1226 &cm->blue[i], 1); 1227 if (error) 1228 return error; 1229 } 1230 1231 return 0; 1232 } 1233 1234 void 1235 cgsix_init_screen(void *cookie, struct vcons_screen *scr, 1236 int existing, long *defattr) 1237 { 1238 struct cgsix_softc *sc = cookie; 1239 struct rasops_info *ri = &scr->scr_ri; 1240 int av; 1241 1242 ri->ri_depth = 8; 1243 ri->ri_width = sc->sc_width; 1244 ri->ri_height = sc->sc_height; 1245 ri->ri_stride = sc->sc_stride; 1246 av = sc->sc_ramsize - (sc->sc_height * sc->sc_stride); 1247 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB; 1248 if (av > (128 * 1024)) { 1249 ri->ri_flg |= RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 1250 } 1251 ri->ri_bits = sc->sc_fb.fb_pixels; 1252 scr->scr_flags |= VCONS_LOADFONT; 1253 1254 rasops_init(ri, 0, 0); 1255 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_REVERSE | 1256 WSSCREEN_UNDERLINE | WSSCREEN_RESIZE; 1257 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 1258 sc->sc_width / ri->ri_font->fontwidth); 1259 1260 /* enable acceleration */ 1261 ri->ri_hw = scr; 1262 ri->ri_ops.copyrows = cg6_ras_copyrows; 1263 ri->ri_ops.copycols = cg6_ras_copycols; 1264 ri->ri_ops.eraserows = cg6_ras_eraserows; 1265 ri->ri_ops.erasecols = cg6_ras_erasecols; 1266 ri->ri_ops.cursor = cgsix_cursor; 1267 if (FONT_IS_ALPHA(ri->ri_font)) { 1268 ri->ri_ops.putchar = cgsix_putchar_aa; 1269 } else 1270 ri->ri_ops.putchar = cgsix_putchar; 1271 } 1272 1273 void 1274 cgsix_rectfill(struct cgsix_softc *sc, int xs, int ys, int wi, int he, 1275 uint32_t col) 1276 { 1277 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1278 1279 CG6_WAIT_READY(fbc); 1280 1281 fbc->fbc_alu = CG6_ALU_FILL; 1282 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 1283 1284 fbc->fbc_fg = col; 1285 fbc->fbc_arecty = ys; 1286 fbc->fbc_arectx = xs; 1287 fbc->fbc_arecty = ys + he - 1; 1288 fbc->fbc_arectx = xs + wi - 1; 1289 CG6_DRAW(fbc); 1290 } 1291 1292 void 1293 cgsix_bitblt(void *cookie, int xs, int ys, int xd, int yd, 1294 int wi, int he, int rop) 1295 { 1296 struct cgsix_softc *sc = cookie; 1297 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1298 CG6_WAIT_READY(fbc); 1299 1300 fbc->fbc_alu = rop; 1301 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 1302 1303 fbc->fbc_x0 = xs; 1304 fbc->fbc_y0 = ys; 1305 fbc->fbc_x1 = xs + wi - 1; 1306 fbc->fbc_y1 = ys + he - 1; 1307 fbc->fbc_x2 = xd; 1308 fbc->fbc_y2 = yd; 1309 fbc->fbc_x3 = xd + wi - 1; 1310 fbc->fbc_y3 = yd + he - 1; 1311 CG6_BLIT(fbc); 1312 } 1313 1314 void 1315 cgsix_setup_mono(struct cgsix_softc *sc, int x, int y, int wi, int he, 1316 uint32_t fg, uint32_t bg) 1317 { 1318 volatile struct cg6_fbc *fbc=sc->sc_fbc; 1319 1320 CG6_WAIT_READY(fbc); 1321 1322 fbc->fbc_x0 = x; 1323 fbc->fbc_x1 = x + wi - 1; 1324 fbc->fbc_y0 = y; 1325 fbc->fbc_incx = 0; 1326 fbc->fbc_incy = 1; 1327 fbc->fbc_fg = fg; 1328 fbc->fbc_bg = bg; 1329 fbc->fbc_mode = GX_BLIT_NOSRC | GX_MODE_COLOR1; 1330 fbc->fbc_alu = GX_PATTERN_ONES | ROP_OSTP(GX_ROP_CLEAR, GX_ROP_SET); 1331 sc->sc_mono_width = wi; 1332 /* now feed the data into the chip */ 1333 } 1334 1335 void 1336 cgsix_feed_line(struct cgsix_softc *sc, int count, uint8_t *data) 1337 { 1338 int i; 1339 uint32_t latch, res = 0, shift; 1340 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1341 1342 if (sc->sc_mono_width > 32) { 1343 /* ARGH! */ 1344 } else 1345 { 1346 shift = 24; 1347 for (i = 0; i < count; i++) { 1348 latch = data[i]; 1349 res |= latch << shift; 1350 shift -= 8; 1351 } 1352 fbc->fbc_font = res; 1353 } 1354 } 1355 1356 void 1357 cgsix_putchar(void *cookie, int row, int col, u_int c, long attr) 1358 { 1359 struct rasops_info *ri = cookie; 1360 struct wsdisplay_font *font = PICK_FONT(ri, c); 1361 struct vcons_screen *scr = ri->ri_hw; 1362 struct cgsix_softc *sc = scr->scr_cookie; 1363 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1364 int fg, bg, uc, i; 1365 uint8_t *data; 1366 int x, y, wi, he; 1367 int inv; 1368 1369 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1370 return; 1371 1372 if (!CHAR_IN_FONT(c, font)) 1373 return; 1374 1375 if (row == ri->ri_crow && col == ri->ri_ccol) { 1376 ri->ri_flg &= ~RI_CURSOR; 1377 } 1378 1379 wi = font->fontwidth; 1380 he = font->fontheight; 1381 1382 inv = ((attr >> 8) & WSATTR_REVERSE); 1383 if (inv) { 1384 fg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff]; 1385 bg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff]; 1386 } else { 1387 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff]; 1388 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff]; 1389 } 1390 1391 x = ri->ri_xorigin + col * wi; 1392 y = ri->ri_yorigin + row * he; 1393 1394 if (c == 0x20) { 1395 cgsix_rectfill(sc, x, y, wi, he, bg); 1396 } else { 1397 uc = c - font->firstchar; 1398 data = (uint8_t *)font->data + uc * ri->ri_fontscale; 1399 1400 cgsix_setup_mono(sc, x, y, wi, 1, fg, bg); 1401 for (i = 0; i < he; i++) { 1402 cgsix_feed_line(sc, font->stride, data); 1403 data += font->stride; 1404 } 1405 /* put the chip back to normal */ 1406 fbc->fbc_incy = 0; 1407 } 1408 } 1409 1410 void 1411 cgsix_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1412 { 1413 struct rasops_info *ri = cookie; 1414 struct wsdisplay_font *font = PICK_FONT(ri, c); 1415 struct vcons_screen *scr = ri->ri_hw; 1416 struct cgsix_softc *sc = scr->scr_cookie; 1417 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1418 1419 uint32_t bg, latch = 0, bg8, fg8, pixel; 1420 int i, j, shift, x, y, wi, he, r, g, b, aval; 1421 int r1, g1, b1, r0, g0, b0, fgo, bgo; 1422 uint8_t *data8; 1423 int rv; 1424 1425 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1426 return; 1427 1428 if (!CHAR_IN_FONT(c, font)) 1429 return; 1430 1431 if (row == ri->ri_crow && col == ri->ri_ccol) { 1432 ri->ri_flg &= ~RI_CURSOR; 1433 } 1434 1435 wi = font->fontwidth; 1436 he = font->fontheight; 1437 1438 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1439 x = ri->ri_xorigin + col * wi; 1440 y = ri->ri_yorigin + row * he; 1441 if (c == 0x20) { 1442 cgsix_rectfill(sc, x, y, wi, he, bg); 1443 return; 1444 } 1445 1446 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1447 if (rv == GC_OK) 1448 return; 1449 1450 data8 = WSFONT_GLYPH(c, font); 1451 1452 CG6_WAIT_READY(sc->sc_fbc); 1453 fbc->fbc_incx = 4; 1454 fbc->fbc_incy = 0; 1455 fbc->fbc_mode = GX_BLIT_NOSRC | GX_MODE_COLOR8; 1456 fbc->fbc_alu = CG6_ALU_COPY; 1457 fbc->fbc_clipmaxx = x + wi - 1; 1458 1459 /* 1460 * we need the RGB colours here, so get offsets into rasops_cmap 1461 */ 1462 fgo = ((attr >> 24) & 0xf) * 3; 1463 bgo = ((attr >> 16) & 0xf) * 3; 1464 1465 r0 = rasops_cmap[bgo]; 1466 r1 = rasops_cmap[fgo]; 1467 g0 = rasops_cmap[bgo + 1]; 1468 g1 = rasops_cmap[fgo + 1]; 1469 b0 = rasops_cmap[bgo + 2]; 1470 b1 = rasops_cmap[fgo + 2]; 1471 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1472 bg8 = R3G3B2(r0, g0, b0); 1473 fg8 = R3G3B2(r1, g1, b1); 1474 1475 for (i = 0; i < he; i++) { 1476 1477 CG6_WAIT_READY(fbc); 1478 fbc->fbc_x0 = x; 1479 fbc->fbc_x1 = x + 3; 1480 fbc->fbc_y0 = y + i; 1481 1482 shift = 24; 1483 for (j = 0; j < wi; j++) { 1484 aval = *data8; 1485 if (aval == 0) { 1486 pixel = bg8; 1487 } else if (aval == 255) { 1488 pixel = fg8; 1489 } else { 1490 r = aval * r1 + (255 - aval) * r0; 1491 g = aval * g1 + (255 - aval) * g0; 1492 b = aval * b1 + (255 - aval) * b0; 1493 pixel = ((r & 0xe000) >> 8) | 1494 ((g & 0xe000) >> 11) | 1495 ((b & 0xc000) >> 14); 1496 } 1497 data8++; 1498 1499 latch |= pixel << shift; 1500 if (shift == 0) { 1501 fbc->fbc_font = latch; 1502 latch = 0; 1503 shift = 24; 1504 } else 1505 shift -= 8; 1506 } 1507 if (shift != 24) 1508 fbc->fbc_font = latch; 1509 } 1510 fbc->fbc_clipmaxx = 0x3fff; 1511 1512 if (rv == GC_ADD) { 1513 glyphcache_add(&sc->sc_gc, c, x, y); 1514 } 1515 } 1516 1517 void 1518 cgsix_cursor(void *cookie, int on, int row, int col) 1519 { 1520 struct rasops_info *ri = cookie; 1521 struct vcons_screen *scr = ri->ri_hw; 1522 struct cgsix_softc *sc = scr->scr_cookie; 1523 int x, y, wi, he; 1524 1525 wi = ri->ri_font->fontwidth; 1526 he = ri->ri_font->fontheight; 1527 1528 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1529 if (on) { 1530 if (ri->ri_flg & RI_CURSOR) { 1531 cg6_ras_nuke_cursor(ri); 1532 } 1533 x = col * wi + ri->ri_xorigin; 1534 y = row * he + ri->ri_yorigin; 1535 cg6_invert(sc, x, y, wi, he); 1536 ri->ri_flg |= RI_CURSOR; 1537 } 1538 ri->ri_crow = row; 1539 ri->ri_ccol = col; 1540 } else 1541 { 1542 ri->ri_crow = row; 1543 ri->ri_ccol = col; 1544 ri->ri_flg &= ~RI_CURSOR; 1545 } 1546 } 1547 1548 void 1549 cgsix_clearscreen(struct cgsix_softc *sc) 1550 { 1551 struct rasops_info *ri = &cg6_console_screen.scr_ri; 1552 1553 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1554 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1555 1556 CG6_WAIT_READY(fbc); 1557 1558 fbc->fbc_alu = CG6_ALU_FILL; 1559 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 1560 1561 fbc->fbc_fg = ri->ri_devcmap[sc->sc_bg]; 1562 fbc->fbc_arectx = 0; 1563 fbc->fbc_arecty = 0; 1564 fbc->fbc_arectx = ri->ri_width - 1; 1565 fbc->fbc_arecty = ri->ri_height - 1; 1566 CG6_DRAW(fbc); 1567 ri->ri_flg &= ~RI_CURSOR; 1568 } 1569 } 1570 1571 void 1572 cg6_invert(struct cgsix_softc *sc, int x, int y, int wi, int he) 1573 { 1574 volatile struct cg6_fbc *fbc = sc->sc_fbc; 1575 1576 CG6_WAIT_READY(fbc); 1577 1578 fbc->fbc_alu = CG6_ALU_FLIP; 1579 fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8; 1580 fbc->fbc_arecty = y; 1581 fbc->fbc_arectx = x; 1582 fbc->fbc_arecty = y + he - 1; 1583 fbc->fbc_arectx = x + wi - 1; 1584 CG6_DRAW(fbc); 1585 } 1586 1587