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