1 /* $NetBSD: cgsix.c,v 1.7 2001/11/13 06:54:32 lukem 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. All advertising materials mentioning features or use of this software 61 * must display the following acknowledgement: 62 * This product includes software developed by the University of 63 * California, Berkeley and its contributors. 64 * 4. Neither the name of the University nor the names of its contributors 65 * may be used to endorse or promote products derived from this software 66 * without specific prior written permission. 67 * 68 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 69 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 70 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 71 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 72 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 73 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 74 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 75 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 76 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 77 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 78 * SUCH DAMAGE. 79 * 80 * @(#)cgsix.c 8.4 (Berkeley) 1/21/94 81 */ 82 83 /* 84 * color display (cgsix) driver. 85 * 86 * Does not handle interrupts, even though they can occur. 87 * 88 * XXX should defer colormap updates to vertical retrace interrupts 89 */ 90 91 #include <sys/cdefs.h> 92 __KERNEL_RCSID(0, "$NetBSD: cgsix.c,v 1.7 2001/11/13 06:54:32 lukem Exp $"); 93 94 #include <sys/param.h> 95 #include <sys/systm.h> 96 #include <sys/buf.h> 97 #include <sys/device.h> 98 #include <sys/ioctl.h> 99 #include <sys/malloc.h> 100 #include <sys/mman.h> 101 #include <sys/tty.h> 102 #include <sys/conf.h> 103 104 #ifdef DEBUG 105 #include <sys/proc.h> 106 #include <sys/syslog.h> 107 #endif 108 109 #include <uvm/uvm_extern.h> 110 111 #include <machine/bus.h> 112 113 #include <dev/sun/fbio.h> 114 #include <dev/sun/fbvar.h> 115 116 #include <dev/sun/btreg.h> 117 #include <dev/sun/btvar.h> 118 #include <dev/sun/cgsixreg.h> 119 #include <dev/sun/cgsixvar.h> 120 #include <dev/sun/pfourreg.h> 121 122 #ifdef RASTERCONSOLE 123 #include <dev/rasops/rasops.h> 124 #include <dev/wscons/wsconsio.h> 125 #endif 126 127 #include <machine/conf.h> 128 129 static void cg6_unblank(struct device *); 130 131 /* cdevsw prototypes */ 132 cdev_decl(cgsix); 133 134 extern struct cfdriver cgsix_cd; 135 136 /* frame buffer generic driver */ 137 static struct fbdriver cg6_fbdriver = { 138 cg6_unblank, cgsixopen, cgsixclose, cgsixioctl, cgsixpoll, cgsixmmap 139 }; 140 141 static void cg6_reset (struct cgsix_softc *); 142 static void cg6_loadcmap (struct cgsix_softc *, int, int); 143 static void cg6_loadomap (struct cgsix_softc *); 144 static void cg6_setcursor (struct cgsix_softc *);/* set position */ 145 static void cg6_loadcursor (struct cgsix_softc *);/* set shape */ 146 147 #ifdef RASTERCONSOLE 148 int cgsix_use_rasterconsole = 1; 149 150 /* 151 * cg6 accelerated console routines. 152 * 153 * Note that buried in this code in several places is the assumption 154 * that pixels are exactly one byte wide. Since this is cg6-specific 155 * code, this seems safe. This assumption resides in things like the 156 * use of ri_emuwidth without messing around with ri_pelbytes, or the 157 * assumption that ri_font->fontwidth is the right thing to multiply 158 * character-cell counts by to get byte counts. 159 */ 160 161 /* 162 * Magic values for blitter 163 */ 164 165 /* Values for the mode register */ 166 #define CG6_MODE ( \ 167 0x00200000 /* GX_BLIT_SRC */ \ 168 | 0x00020000 /* GX_MODE_COLOR8 */ \ 169 | 0x00008000 /* GX_DRAW_RENDER */ \ 170 | 0x00002000 /* GX_BWRITE0_ENABLE */ \ 171 | 0x00001000 /* GX_BWRITE1_DISABLE */ \ 172 | 0x00000200 /* GX_BREAD_0 */ \ 173 | 0x00000080 /* GX_BDISP_0 */ \ 174 ) 175 #define CG6_MODE_MASK ( \ 176 0x00300000 /* GX_BLIT_ALL */ \ 177 | 0x00060000 /* GX_MODE_ALL */ \ 178 | 0x00018000 /* GX_DRAW_ALL */ \ 179 | 0x00006000 /* GX_BWRITE0_ALL */ \ 180 | 0x00001800 /* GX_BWRITE1_ALL */ \ 181 | 0x00000600 /* GX_BREAD_ALL */ \ 182 | 0x00000180 /* GX_BDISP_ALL */ \ 183 ) 184 185 /* Value for the alu register for screen-to-screen copies */ 186 #define CG6_ALU_COPY ( \ 187 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ 188 | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ 189 | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ 190 | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ 191 | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ 192 | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ 193 | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ 194 | 0x0000cccc /* ALU = src */ \ 195 ) 196 197 /* Value for the alu register for region fills */ 198 #define CG6_ALU_FILL ( \ 199 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ 200 | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ 201 | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ 202 | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ 203 | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ 204 | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ 205 | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ 206 | 0x0000ff00 /* ALU = fg color */ \ 207 ) 208 209 /* Value for the alu register for toggling an area */ 210 #define CG6_ALU_FLIP ( \ 211 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ 212 | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ 213 | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ 214 | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ 215 | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ 216 | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ 217 | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ 218 | 0x00005555 /* ALU = ~dst */ \ 219 ) 220 221 /* 222 * Wait for a blit to finish. 223 * 0x8000000 bit: function unknown; 0x20000000 bit: GX_BLT_INPROGRESS 224 */ 225 #define CG6_BLIT_WAIT(fbc) do { \ 226 while (((fbc)->fbc_blit & 0xa0000000) == 0xa0000000) \ 227 /*EMPTY*/; \ 228 } while (0) 229 230 /* 231 * Wait for a drawing operation to finish, or at least get queued. 232 * 0x8000000 bit: function unknown; 0x20000000 bit: GX_FULL 233 */ 234 #define CG6_DRAW_WAIT(fbc) do { \ 235 while (((fbc)->fbc_draw & 0xa0000000) == 0xa0000000) \ 236 /*EMPTY*/; \ 237 } while (0) 238 239 /* 240 * Wait for the whole engine to go idle. This may not matter in our case; 241 * I'm not sure whether blits are actually queued or not. It more likely 242 * is intended for lines and such that do get queued. 243 * 0x10000000 bit: GX_INPROGRESS 244 */ 245 #define CG6_DRAIN(fbc) do { \ 246 while ((fbc)->fbc_s & 0x10000000) \ 247 /*EMPTY*/; \ 248 } while (0) 249 250 static void cg6_ras_init(struct cgsix_softc *); 251 static void cg6_ras_copyrows(void *, int, int, int); 252 static void cg6_ras_copycols(void *, int, int, int, int); 253 static void cg6_ras_erasecols(void *, int, int, int, long int); 254 static void cg6_ras_eraserows(void *, int, int, long int); 255 static void cg6_ras_do_cursor(struct rasops_info *); 256 257 static void 258 cg6_ras_init(struct cgsix_softc *sc) 259 { 260 volatile struct cg6_fbc *fbc = sc->sc_fbc; 261 262 CG6_DRAIN(fbc); 263 fbc->fbc_mode &= ~CG6_MODE_MASK; 264 fbc->fbc_mode |= CG6_MODE; 265 } 266 267 static void 268 cg6_ras_copyrows(void *cookie, int src, int dst, int n) 269 { 270 struct rasops_info *ri; 271 volatile struct cg6_fbc *fbc; 272 273 ri = cookie; 274 if (dst == src) 275 return; 276 if (src < 0) { 277 n += src; 278 src = 0; 279 } 280 if (src+n > ri->ri_rows) 281 n = ri->ri_rows - src; 282 if (dst < 0) { 283 n += dst; 284 dst = 0; 285 } 286 if (dst+n > ri->ri_rows) 287 n = ri->ri_rows - dst; 288 if (n <= 0) 289 return; 290 n *= ri->ri_font->fontheight; 291 src *= ri->ri_font->fontheight; 292 dst *= ri->ri_font->fontheight; 293 fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc; 294 fbc->fbc_clip = 0; 295 fbc->fbc_s = 0; 296 fbc->fbc_offx = 0; 297 fbc->fbc_offy = 0; 298 fbc->fbc_clipminx = 0; 299 fbc->fbc_clipminy = 0; 300 fbc->fbc_clipmaxx = ri->ri_width - 1; 301 fbc->fbc_clipmaxy = ri->ri_height - 1; 302 fbc->fbc_alu = CG6_ALU_COPY; 303 fbc->fbc_x0 = ri->ri_xorigin; 304 fbc->fbc_y0 = ri->ri_yorigin + src; 305 fbc->fbc_x1 = ri->ri_xorigin + ri->ri_emuwidth - 1; 306 fbc->fbc_y1 = ri->ri_yorigin + src + n - 1; 307 fbc->fbc_x2 = ri->ri_xorigin; 308 fbc->fbc_y2 = ri->ri_yorigin + dst; 309 fbc->fbc_x3 = ri->ri_xorigin + ri->ri_emuwidth - 1; 310 fbc->fbc_y3 = ri->ri_yorigin + dst + n - 1; 311 CG6_BLIT_WAIT(fbc); 312 CG6_DRAIN(fbc); 313 } 314 315 static void 316 cg6_ras_copycols(void *cookie, int row, int src, int dst, int n) 317 { 318 struct rasops_info *ri; 319 volatile struct cg6_fbc *fbc; 320 321 ri = cookie; 322 if (dst == src) 323 return; 324 if ((row < 0) || (row >= ri->ri_rows)) 325 return; 326 if (src < 0) { 327 n += src; 328 src = 0; 329 } 330 if (src+n > ri->ri_cols) 331 n = ri->ri_cols - src; 332 if (dst < 0) { 333 n += dst; 334 dst = 0; 335 } 336 if (dst+n > ri->ri_cols) 337 n = ri->ri_cols - dst; 338 if (n <= 0) 339 return; 340 n *= ri->ri_font->fontwidth; 341 src *= ri->ri_font->fontwidth; 342 dst *= ri->ri_font->fontwidth; 343 row *= ri->ri_font->fontheight; 344 fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc; 345 fbc->fbc_clip = 0; 346 fbc->fbc_s = 0; 347 fbc->fbc_offx = 0; 348 fbc->fbc_offy = 0; 349 fbc->fbc_clipminx = 0; 350 fbc->fbc_clipminy = 0; 351 fbc->fbc_clipmaxx = ri->ri_width - 1; 352 fbc->fbc_clipmaxy = ri->ri_height - 1; 353 fbc->fbc_alu = CG6_ALU_COPY; 354 fbc->fbc_x0 = ri->ri_xorigin + src; 355 fbc->fbc_y0 = ri->ri_yorigin + row; 356 fbc->fbc_x1 = ri->ri_xorigin + src + n - 1; 357 fbc->fbc_y1 = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; 358 fbc->fbc_x2 = ri->ri_xorigin + dst; 359 fbc->fbc_y2 = ri->ri_yorigin + row; 360 fbc->fbc_x3 = ri->ri_xorigin + dst + n - 1; 361 fbc->fbc_y3 = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; 362 CG6_BLIT_WAIT(fbc); 363 CG6_DRAIN(fbc); 364 } 365 366 static void 367 cg6_ras_erasecols(void *cookie, int row, int col, int n, long int attr) 368 { 369 struct rasops_info *ri; 370 volatile struct cg6_fbc *fbc; 371 372 ri = cookie; 373 if ((row < 0) || (row >= ri->ri_rows)) 374 return; 375 if (col < 0) { 376 n += col; 377 col = 0; 378 } 379 if (col+n > ri->ri_cols) 380 n = ri->ri_cols - col; 381 if (n <= 0) 382 return; 383 n *= ri->ri_font->fontwidth; 384 col *= ri->ri_font->fontwidth; 385 row *= ri->ri_font->fontheight; 386 fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc; 387 fbc->fbc_clip = 0; 388 fbc->fbc_s = 0; 389 fbc->fbc_offx = 0; 390 fbc->fbc_offy = 0; 391 fbc->fbc_clipminx = 0; 392 fbc->fbc_clipminy = 0; 393 fbc->fbc_clipmaxx = ri->ri_width - 1; 394 fbc->fbc_clipmaxy = ri->ri_height - 1; 395 fbc->fbc_alu = CG6_ALU_FILL; 396 fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xf]; 397 fbc->fbc_arecty = ri->ri_yorigin + row; 398 fbc->fbc_arectx = ri->ri_xorigin + col; 399 fbc->fbc_arecty = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; 400 fbc->fbc_arectx = ri->ri_xorigin + col + n - 1; 401 CG6_DRAW_WAIT(fbc); 402 CG6_DRAIN(fbc); 403 } 404 405 static void 406 cg6_ras_eraserows(void *cookie, int row, int n, long int attr) 407 { 408 struct rasops_info *ri; 409 volatile struct cg6_fbc *fbc; 410 411 ri = cookie; 412 if (row < 0) { 413 n += row; 414 row = 0; 415 } 416 if (row+n > ri->ri_rows) 417 n = ri->ri_rows - row; 418 if (n <= 0) 419 return; 420 fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc; 421 fbc->fbc_clip = 0; 422 fbc->fbc_s = 0; 423 fbc->fbc_offx = 0; 424 fbc->fbc_offy = 0; 425 fbc->fbc_clipminx = 0; 426 fbc->fbc_clipminy = 0; 427 fbc->fbc_clipmaxx = ri->ri_width - 1; 428 fbc->fbc_clipmaxy = ri->ri_height - 1; 429 fbc->fbc_alu = CG6_ALU_FILL; 430 fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xf]; 431 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 432 fbc->fbc_arecty = 0; 433 fbc->fbc_arectx = 0; 434 fbc->fbc_arecty = ri->ri_height - 1; 435 fbc->fbc_arectx = ri->ri_width - 1; 436 } else { 437 row *= ri->ri_font->fontheight; 438 fbc->fbc_arecty = ri->ri_yorigin + row; 439 fbc->fbc_arectx = ri->ri_xorigin; 440 fbc->fbc_arecty = ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1; 441 fbc->fbc_arectx = ri->ri_xorigin + ri->ri_emuwidth - 1; 442 } 443 CG6_DRAW_WAIT(fbc); 444 CG6_DRAIN(fbc); 445 } 446 447 /* 448 * Really want something more like fg^bg here, but that would be more 449 * or less impossible to migrate to colors. So we hope there's 450 * something not too inappropriate in the colormap...besides, it's what 451 * the non-accelerated code did. :-) 452 */ 453 static void 454 cg6_ras_do_cursor(struct rasops_info *ri) 455 { 456 volatile struct cg6_fbc *fbc; 457 int row; 458 int col; 459 460 row = ri->ri_crow * ri->ri_font->fontheight; 461 col = ri->ri_ccol * ri->ri_font->fontwidth; 462 fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc; 463 fbc->fbc_clip = 0; 464 fbc->fbc_s = 0; 465 fbc->fbc_offx = 0; 466 fbc->fbc_offy = 0; 467 fbc->fbc_clipminx = 0; 468 fbc->fbc_clipminy = 0; 469 fbc->fbc_clipmaxx = ri->ri_width - 1; 470 fbc->fbc_clipmaxy = ri->ri_height - 1; 471 fbc->fbc_alu = CG6_ALU_FLIP; 472 fbc->fbc_arecty = ri->ri_yorigin + row; 473 fbc->fbc_arectx = ri->ri_xorigin + col; 474 fbc->fbc_arecty = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; 475 fbc->fbc_arectx = ri->ri_xorigin + col + ri->ri_font->fontwidth - 1; 476 CG6_DRAW_WAIT(fbc); 477 CG6_DRAIN(fbc); 478 } 479 #endif /* RASTERCONSOLE */ 480 481 void 482 cg6attach(sc, name, isconsole) 483 struct cgsix_softc *sc; 484 char *name; 485 int isconsole; 486 { 487 struct fbdevice *fb = &sc->sc_fb; 488 489 fb->fb_driver = &cg6_fbdriver; 490 491 /* Don't have to map the pfour register on the cgsix. */ 492 fb->fb_pfour = NULL; 493 494 fb->fb_type.fb_cmsize = 256; 495 fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes; 496 printf(": %s, %d x %d", name, 497 fb->fb_type.fb_width, fb->fb_type.fb_height); 498 499 sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) & 500 (FHC_REV_MASK >> FHC_REV_SHIFT); 501 502 printf(", rev %d", sc->sc_fhcrev); 503 504 /* reset cursor & frame buffer controls */ 505 cg6_reset(sc); 506 507 /* enable video */ 508 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 509 510 if (isconsole) { 511 printf(" (console)"); 512 #ifdef RASTERCONSOLE 513 if (cgsix_use_rasterconsole) { 514 fbrcons_init(&sc->sc_fb); 515 sc->sc_fb.fb_rinfo.ri_hw = sc; 516 sc->sc_fb.fb_rinfo.ri_ops.copyrows = cg6_ras_copyrows; 517 sc->sc_fb.fb_rinfo.ri_ops.copycols = cg6_ras_copycols; 518 sc->sc_fb.fb_rinfo.ri_ops.erasecols = cg6_ras_erasecols; 519 sc->sc_fb.fb_rinfo.ri_ops.eraserows = cg6_ras_eraserows; 520 sc->sc_fb.fb_rinfo.ri_do_cursor = cg6_ras_do_cursor; 521 cg6_ras_init(sc); 522 } 523 #endif 524 } 525 526 printf("\n"); 527 fb_attach(&sc->sc_fb, isconsole); 528 } 529 530 531 int 532 cgsixopen(dev, flags, mode, p) 533 dev_t dev; 534 int flags, mode; 535 struct proc *p; 536 { 537 int unit = minor(dev); 538 539 if (unit >= cgsix_cd.cd_ndevs || cgsix_cd.cd_devs[unit] == NULL) 540 return (ENXIO); 541 return (0); 542 } 543 544 int 545 cgsixclose(dev, flags, mode, p) 546 dev_t dev; 547 int flags, mode; 548 struct proc *p; 549 { 550 struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; 551 552 cg6_reset(sc); 553 554 /* (re-)initialize the default color map */ 555 bt_initcmap(&sc->sc_cmap, 256); 556 cg6_loadcmap(sc, 0, 256); 557 558 return (0); 559 } 560 561 int 562 cgsixioctl(dev, cmd, data, flags, p) 563 dev_t dev; 564 u_long cmd; 565 caddr_t data; 566 int flags; 567 struct proc *p; 568 { 569 struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; 570 u_int count; 571 int v, error; 572 union cursor_cmap tcm; 573 574 switch (cmd) { 575 576 case FBIOGTYPE: 577 *(struct fbtype *)data = sc->sc_fb.fb_type; 578 break; 579 580 case FBIOGATTR: 581 #define fba ((struct fbgattr *)data) 582 fba->real_type = sc->sc_fb.fb_type.fb_type; 583 fba->owner = 0; /* XXX ??? */ 584 fba->fbtype = sc->sc_fb.fb_type; 585 fba->sattr.flags = 0; 586 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 587 fba->sattr.dev_specific[0] = -1; 588 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 589 fba->emu_types[1] = -1; 590 #undef fba 591 break; 592 593 case FBIOGETCMAP: 594 #define p ((struct fbcmap *)data) 595 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 596 597 case FBIOPUTCMAP: 598 /* copy to software map */ 599 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 600 if (error) 601 return (error); 602 /* now blast them into the chip */ 603 /* XXX should use retrace interrupt */ 604 cg6_loadcmap(sc, p->index, p->count); 605 #undef p 606 break; 607 608 case FBIOGVIDEO: 609 *(int *)data = sc->sc_blanked; 610 break; 611 612 case FBIOSVIDEO: 613 if (*(int *)data) 614 cg6_unblank(&sc->sc_dev); 615 else if (!sc->sc_blanked) { 616 sc->sc_blanked = 1; 617 sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN; 618 } 619 break; 620 621 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 622 #define p ((struct fbcursor *)data) 623 #define cc (&sc->sc_cursor) 624 625 case FBIOGCURSOR: 626 /* do not quite want everything here... */ 627 p->set = FB_CUR_SETALL; /* close enough, anyway */ 628 p->enable = cc->cc_enable; 629 p->pos = cc->cc_pos; 630 p->hot = cc->cc_hot; 631 p->size = cc->cc_size; 632 633 /* begin ugh ... can we lose some of this crap?? */ 634 if (p->image != NULL) { 635 count = cc->cc_size.y * 32 / NBBY; 636 error = copyout((caddr_t)cc->cc_bits[1], 637 (caddr_t)p->image, count); 638 if (error) 639 return (error); 640 error = copyout((caddr_t)cc->cc_bits[0], 641 (caddr_t)p->mask, count); 642 if (error) 643 return (error); 644 } 645 if (p->cmap.red != NULL) { 646 error = bt_getcmap(&p->cmap, 647 (union bt_cmap *)&cc->cc_color, 2, 1); 648 if (error) 649 return (error); 650 } else { 651 p->cmap.index = 0; 652 p->cmap.count = 2; 653 } 654 /* end ugh */ 655 break; 656 657 case FBIOSCURSOR: 658 /* 659 * For setcmap and setshape, verify parameters, so that 660 * we do not get halfway through an update and then crap 661 * out with the software state screwed up. 662 */ 663 v = p->set; 664 if (v & FB_CUR_SETCMAP) { 665 /* 666 * This use of a temporary copy of the cursor 667 * colormap is not terribly efficient, but these 668 * copies are small (8 bytes)... 669 */ 670 tcm = cc->cc_color; 671 error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2, 1); 672 if (error) 673 return (error); 674 } 675 if (v & FB_CUR_SETSHAPE) { 676 if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32) 677 return (EINVAL); 678 count = p->size.y * 32 / NBBY; 679 if (!uvm_useracc(p->image, count, B_READ) || 680 !uvm_useracc(p->mask, count, B_READ)) 681 return (EFAULT); 682 } 683 684 /* parameters are OK; do it */ 685 if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { 686 if (v & FB_CUR_SETCUR) 687 cc->cc_enable = p->enable; 688 if (v & FB_CUR_SETPOS) 689 cc->cc_pos = p->pos; 690 if (v & FB_CUR_SETHOT) 691 cc->cc_hot = p->hot; 692 cg6_setcursor(sc); 693 } 694 if (v & FB_CUR_SETCMAP) { 695 cc->cc_color = tcm; 696 cg6_loadomap(sc); /* XXX defer to vertical retrace */ 697 } 698 if (v & FB_CUR_SETSHAPE) { 699 cc->cc_size = p->size; 700 count = p->size.y * 32 / NBBY; 701 bzero((caddr_t)cc->cc_bits, sizeof cc->cc_bits); 702 copyin(p->mask, (caddr_t)cc->cc_bits[0], count); 703 copyin(p->image, (caddr_t)cc->cc_bits[1], count); 704 cg6_loadcursor(sc); 705 } 706 break; 707 708 #undef p 709 #undef cc 710 711 case FBIOGCURPOS: 712 *(struct fbcurpos *)data = sc->sc_cursor.cc_pos; 713 break; 714 715 case FBIOSCURPOS: 716 sc->sc_cursor.cc_pos = *(struct fbcurpos *)data; 717 cg6_setcursor(sc); 718 break; 719 720 case FBIOGCURMAX: 721 /* max cursor size is 32x32 */ 722 ((struct fbcurpos *)data)->x = 32; 723 ((struct fbcurpos *)data)->y = 32; 724 break; 725 726 default: 727 #ifdef DEBUG 728 log(LOG_NOTICE, "cgsixioctl(0x%lx) (%s[%d])\n", cmd, 729 p->p_comm, p->p_pid); 730 #endif 731 return (ENOTTY); 732 } 733 return (0); 734 } 735 736 int 737 cgsixpoll(dev, events, p) 738 dev_t dev; 739 int events; 740 struct proc *p; 741 { 742 743 return (seltrue(dev, events, p)); 744 } 745 746 /* 747 * Clean up hardware state (e.g., after bootup or after X crashes). 748 */ 749 static void 750 cg6_reset(sc) 751 struct cgsix_softc *sc; 752 { 753 volatile struct cg6_tec_xxx *tec; 754 int fhc; 755 volatile struct bt_regs *bt; 756 757 /* hide the cursor, just in case */ 758 sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF; 759 760 /* turn off frobs in transform engine (makes X11 work) */ 761 tec = sc->sc_tec; 762 tec->tec_mv = 0; 763 tec->tec_clip = 0; 764 tec->tec_vdc = 0; 765 766 /* take care of hardware bugs in old revisions */ 767 if (sc->sc_fhcrev < 5) { 768 /* 769 * Keep current resolution; set cpu to 68020, set test 770 * window (size 1Kx1K), and for rev 1, disable dest cache. 771 */ 772 fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 | 773 FHC_TEST | 774 (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT); 775 if (sc->sc_fhcrev < 2) 776 fhc |= FHC_DST_DISABLE; 777 *sc->sc_fhc = fhc; 778 } 779 780 /* Enable cursor in Brooktree DAC. */ 781 bt = sc->sc_bt; 782 bt->bt_addr = 0x06 << 24; 783 bt->bt_ctrl |= 0x03 << 24; 784 } 785 786 static void 787 cg6_setcursor(sc) 788 struct cgsix_softc *sc; 789 { 790 791 /* we need to subtract the hot-spot value here */ 792 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f) 793 sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ? 794 ((COORD(x) << 16) | (COORD(y) & 0xffff)) : 795 (THC_CURSOFF << 16) | THC_CURSOFF; 796 #undef COORD 797 } 798 799 static void 800 cg6_loadcursor(sc) 801 struct cgsix_softc *sc; 802 { 803 volatile struct cg6_thc *thc; 804 u_int edgemask, m; 805 int i; 806 807 /* 808 * Keep the top size.x bits. Here we *throw out* the top 809 * size.x bits from an all-one-bits word, introducing zeros in 810 * the top size.x bits, then invert all the bits to get what 811 * we really wanted as our mask. But this fails if size.x is 812 * 32---a sparc uses only the low 5 bits of the shift count--- 813 * so we have to special case that. 814 */ 815 edgemask = ~0; 816 if (sc->sc_cursor.cc_size.x < 32) 817 edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x); 818 thc = sc->sc_thc; 819 for (i = 0; i < 32; i++) { 820 m = sc->sc_cursor.cc_bits[0][i] & edgemask; 821 thc->thc_cursmask[i] = m; 822 thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i]; 823 } 824 } 825 826 /* 827 * Load a subset of the current (new) colormap into the color DAC. 828 */ 829 static void 830 cg6_loadcmap(sc, start, ncolors) 831 struct cgsix_softc *sc; 832 int start, ncolors; 833 { 834 volatile struct bt_regs *bt; 835 u_int *ip, i; 836 int count; 837 838 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 839 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 840 bt = sc->sc_bt; 841 bt->bt_addr = BT_D4M4(start) << 24; 842 while (--count >= 0) { 843 i = *ip++; 844 /* hardware that makes one want to pound boards with hammers */ 845 bt->bt_cmap = i; 846 bt->bt_cmap = i << 8; 847 bt->bt_cmap = i << 16; 848 bt->bt_cmap = i << 24; 849 } 850 } 851 852 /* 853 * Load the cursor (overlay `foreground' and `background') colors. 854 */ 855 static void 856 cg6_loadomap(sc) 857 struct cgsix_softc *sc; 858 { 859 volatile struct bt_regs *bt; 860 u_int i; 861 862 bt = sc->sc_bt; 863 bt->bt_addr = 0x01 << 24; /* set background color */ 864 i = sc->sc_cursor.cc_color.cm_chip[0]; 865 bt->bt_omap = i; /* R */ 866 bt->bt_omap = i << 8; /* G */ 867 bt->bt_omap = i << 16; /* B */ 868 869 bt->bt_addr = 0x03 << 24; /* set foreground color */ 870 bt->bt_omap = i << 24; /* R */ 871 i = sc->sc_cursor.cc_color.cm_chip[1]; 872 bt->bt_omap = i; /* G */ 873 bt->bt_omap = i << 8; /* B */ 874 } 875 876 static void 877 cg6_unblank(dev) 878 struct device *dev; 879 { 880 struct cgsix_softc *sc = (struct cgsix_softc *)dev; 881 882 if (sc->sc_blanked) { 883 sc->sc_blanked = 0; 884 sc->sc_thc->thc_misc |= THC_MISC_VIDEN; 885 } 886 } 887 888 /* XXX the following should be moved to a "user interface" header */ 889 /* 890 * Base addresses at which users can mmap() the various pieces of a cg6. 891 * Note that although the Brooktree color registers do not occupy 8K, 892 * the X server dies if we do not allow it to map 8K there (it just maps 893 * from 0x70000000 forwards, as a contiguous chunk). 894 */ 895 #define CG6_USER_FBC 0x70000000 896 #define CG6_USER_TEC 0x70001000 897 #define CG6_USER_BTREGS 0x70002000 898 #define CG6_USER_FHC 0x70004000 899 #define CG6_USER_THC 0x70005000 900 #define CG6_USER_ROM 0x70006000 901 #define CG6_USER_RAM 0x70016000 902 #define CG6_USER_DHC 0x80000000 903 904 struct mmo { 905 u_long mo_uaddr; /* user (virtual) address */ 906 u_long mo_size; /* size, or 0 for video ram size */ 907 u_long mo_physoff; /* offset from sc_physadr */ 908 }; 909 910 /* 911 * Return the address that would map the given device at the given 912 * offset, allowing for the given protection, or return -1 for error. 913 * 914 * XXX needs testing against `demanding' applications (e.g., aviator) 915 */ 916 paddr_t 917 cgsixmmap(dev, off, prot) 918 dev_t dev; 919 off_t off; 920 int prot; 921 { 922 struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; 923 struct mmo *mo; 924 u_int u, sz; 925 static struct mmo mmo[] = { 926 { CG6_USER_RAM, 0, CGSIX_RAM_OFFSET }, 927 928 /* do not actually know how big most of these are! */ 929 { CG6_USER_FBC, 1, CGSIX_FBC_OFFSET }, 930 { CG6_USER_TEC, 1, CGSIX_TEC_OFFSET }, 931 { CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET }, 932 { CG6_USER_FHC, 1, CGSIX_FHC_OFFSET }, 933 { CG6_USER_THC, sizeof(struct cg6_thc), CGSIX_THC_OFFSET }, 934 { CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET }, 935 { CG6_USER_DHC, 1, CGSIX_DHC_OFFSET }, 936 }; 937 #define NMMO (sizeof mmo / sizeof *mmo) 938 939 if (off & PGOFSET) 940 panic("cgsixmmap"); 941 942 /* 943 * Entries with size 0 map video RAM (i.e., the size in fb data). 944 * 945 * Since we work in pages, the fact that the map offset table's 946 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 947 * one byte is as good as one page. 948 */ 949 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 950 if ((u_long)off < mo->mo_uaddr) 951 continue; 952 u = off - mo->mo_uaddr; 953 sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; 954 if (u < sz) { 955 return (bus_space_mmap(sc->sc_bustag, 956 sc->sc_paddr, u+mo->mo_physoff, 957 prot, BUS_SPACE_MAP_LINEAR)); 958 } 959 } 960 961 #ifdef DEBUG 962 { 963 struct proc *p = curproc; /* XXX */ 964 log(LOG_NOTICE, "cgsixmmap(0x%llx) (%s[%d])\n", 965 (long long)off, p->p_comm, p->p_pid); 966 } 967 #endif 968 return (-1); /* not a user-map offset */ 969 } 970