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