1 /* $NetBSD: mfb.c,v 1.22 2000/03/16 05:50:57 nisimura Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Tohru Nishimura 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35 __KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.22 2000/03/16 05:50:57 nisimura Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/malloc.h> 42 #include <sys/buf.h> 43 #include <sys/ioctl.h> 44 #include <vm/vm.h> 45 46 #include <machine/bus.h> 47 #include <machine/intr.h> 48 49 #include <dev/wscons/wsconsio.h> 50 #include <dev/wscons/wsdisplayvar.h> 51 52 #include <dev/rasops/rasops.h> 53 #include <dev/wsfont/wsfont.h> 54 55 #include <dev/tc/tcvar.h> 56 #include <dev/ic/bt431reg.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #define machine_btop(x) mips_btop(x) 61 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x) 62 63 #define BYTE(base, index) *((u_int8_t *)(base) + ((index)<<2)) 64 #define HALF(base, index) *((u_int16_t *)(base) + ((index)<<1)) 65 66 /* Bt455 hardware registers */ 67 #define bt_reg 0 68 #define bt_cmap 1 69 #define bt_clr 2 70 #define bt_ovly 3 71 72 /* Bt431 hardware registers */ 73 #define bt_lo 0 74 #define bt_hi 1 75 #define bt_ram 2 76 #define bt_ctl 3 77 78 #define SELECT455(vdac, regno) do { \ 79 BYTE(vdac, bt_reg) = (regno); \ 80 BYTE(vdac, bt_clr) = 0; \ 81 tc_wmb(); \ 82 } while (0) 83 84 #define TWIN(x) ((x)|((x) << 8)) 85 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin) 86 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8) 87 88 #define SELECT431(curs, regno) do { \ 89 HALF(curs, bt_lo) = TWIN(regno);\ 90 HALF(curs, bt_hi) = 0; \ 91 tc_wmb(); \ 92 } while (0) 93 94 95 struct fb_devconfig { 96 vaddr_t dc_vaddr; /* memory space virtual base address */ 97 paddr_t dc_paddr; /* memory space physical base address */ 98 vsize_t dc_size; /* size of slot memory */ 99 int dc_wid; /* width of frame buffer */ 100 int dc_ht; /* height of frame buffer */ 101 int dc_depth; /* depth, bits per pixel */ 102 int dc_rowbytes; /* bytes in a FB scan line */ 103 vaddr_t dc_videobase; /* base of flat frame buffer */ 104 int dc_blanked; /* currently has video disabled */ 105 106 struct rasops_info rinfo; 107 }; 108 109 struct hwcursor64 { 110 struct wsdisplay_curpos cc_pos; 111 struct wsdisplay_curpos cc_hot; 112 struct wsdisplay_curpos cc_size; 113 struct wsdisplay_curpos cc_magic; 114 #define CURSOR_MAX_SIZE 64 115 u_int8_t cc_color[6]; 116 u_int64_t cc_image[64 + 64]; 117 }; 118 119 struct mfb_softc { 120 struct device sc_dev; 121 struct fb_devconfig *sc_dc; /* device configuration */ 122 struct hwcursor64 sc_cursor; /* software copy of cursor */ 123 int sc_curenb; /* cursor sprite enabled */ 124 int sc_changed; /* need update of colormap */ 125 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 126 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 127 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 128 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 129 #define DATA_ALL_CHANGED 0x0f 130 int nscreens; 131 }; 132 133 #define MX_MAGIC_X 360 134 #define MX_MAGIC_Y 36 135 136 #define MX_FB_OFFSET 0x200000 137 #define MX_FB_SIZE 0x200000 138 #define MX_BT455_OFFSET 0x100000 139 #define MX_BT431_OFFSET 0x180000 140 #define MX_IREQ_OFFSET 0x080000 /* Interrupt req. control */ 141 142 static int mfbmatch __P((struct device *, struct cfdata *, void *)); 143 static void mfbattach __P((struct device *, struct device *, void *)); 144 145 const struct cfattach mfb_ca = { 146 sizeof(struct mfb_softc), mfbmatch, mfbattach, 147 }; 148 149 static void mfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 150 static struct fb_devconfig mfb_console_dc; 151 static tc_addr_t mfb_consaddr; 152 153 static struct wsscreen_descr mfb_stdscreen = { 154 "std", 0, 0, 155 0, /* textops */ 156 0, 0, 157 WSSCREEN_REVERSE 158 }; 159 160 static const struct wsscreen_descr *_mfb_scrlist[] = { 161 &mfb_stdscreen, 162 }; 163 164 static const struct wsscreen_list mfb_screenlist = { 165 sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist 166 }; 167 168 static int mfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 169 static int mfbmmap __P((void *, off_t, int)); 170 171 static int mfb_alloc_screen __P((void *, const struct wsscreen_descr *, 172 void **, int *, int *, long *)); 173 static void mfb_free_screen __P((void *, void *)); 174 static int mfb_show_screen __P((void *, void *, int, 175 void (*) (void *, int, int), void *)); 176 177 static const struct wsdisplay_accessops mfb_accessops = { 178 mfbioctl, 179 mfbmmap, 180 mfb_alloc_screen, 181 mfb_free_screen, 182 mfb_show_screen, 183 0 /* load_font */ 184 }; 185 186 int mfb_cnattach __P((tc_addr_t)); 187 static int mfbintr __P((void *)); 188 static void mfbinit __P((struct fb_devconfig *)); 189 190 static int set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *)); 191 static int get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *)); 192 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *)); 193 static void bt431_set_curpos __P((struct mfb_softc *)); 194 195 /* bit order reverse */ 196 static const u_int8_t flip[256] = { 197 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 198 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 199 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 200 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 201 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 202 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 203 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 204 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 205 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 206 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 207 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 208 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 209 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 210 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 211 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 212 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 213 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 214 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 215 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 216 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 217 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 218 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 219 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 220 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 221 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 222 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 223 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 224 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 225 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 226 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 227 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 228 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 229 }; 230 231 static int 232 mfbmatch(parent, match, aux) 233 struct device *parent; 234 struct cfdata *match; 235 void *aux; 236 { 237 struct tc_attach_args *ta = aux; 238 239 if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0) 240 return (0); 241 242 return (1); 243 } 244 245 static void 246 mfb_getdevconfig(dense_addr, dc) 247 tc_addr_t dense_addr; 248 struct fb_devconfig *dc; 249 { 250 int i, cookie; 251 252 dc->dc_vaddr = dense_addr; 253 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET); 254 255 dc->dc_wid = 1280; 256 dc->dc_ht = 1024; 257 dc->dc_depth = 8; 258 dc->dc_rowbytes = 2048; 259 dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET; 260 dc->dc_blanked = 0; 261 262 /* initialize colormap and cursor resource */ 263 mfbinit(dc); 264 265 /* clear the screen */ 266 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 267 *(u_int32_t *)(dc->dc_videobase + i) = 0; 268 269 dc->rinfo.ri_flg = RI_CENTER; 270 dc->rinfo.ri_depth = dc->dc_depth; 271 dc->rinfo.ri_bits = (void *)dc->dc_videobase; 272 dc->rinfo.ri_width = dc->dc_wid; 273 dc->rinfo.ri_height = dc->dc_ht; 274 dc->rinfo.ri_stride = dc->dc_rowbytes; 275 276 wsfont_init(); 277 /* prefer 8 pixel wide font */ 278 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0) 279 cookie = wsfont_find(NULL, 0, 0, 0); 280 if (cookie <= 0) { 281 printf("mfb: font table is empty\n"); 282 return; 283 } 284 285 if (wsfont_lock(cookie, &dc->rinfo.ri_font, 286 WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) { 287 printf("mfb: couldn't lock font\n"); 288 return; 289 } 290 dc->rinfo.ri_wsfcookie = cookie; 291 292 rasops_init(&dc->rinfo, 34, 80); 293 294 /* XXX shouldn't be global */ 295 mfb_stdscreen.nrows = dc->rinfo.ri_rows; 296 mfb_stdscreen.ncols = dc->rinfo.ri_cols; 297 mfb_stdscreen.textops = &dc->rinfo.ri_ops; 298 mfb_stdscreen.capabilities = dc->rinfo.ri_caps; 299 } 300 301 static void 302 mfbattach(parent, self, aux) 303 struct device *parent, *self; 304 void *aux; 305 { 306 struct mfb_softc *sc = (struct mfb_softc *)self; 307 struct tc_attach_args *ta = aux; 308 struct wsemuldisplaydev_attach_args waa; 309 caddr_t mfbbase; 310 int console; 311 volatile register int junk; 312 313 console = (ta->ta_addr == mfb_consaddr); 314 if (console) { 315 sc->sc_dc = &mfb_console_dc; 316 sc->nscreens = 1; 317 } 318 else { 319 sc->sc_dc = (struct fb_devconfig *) 320 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 321 mfb_getdevconfig(ta->ta_addr, sc->sc_dc); 322 } 323 printf(": %d x %d, 1bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht); 324 325 sc->sc_cursor.cc_magic.x = MX_MAGIC_X; 326 sc->sc_cursor.cc_magic.y = MX_MAGIC_Y; 327 328 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc); 329 330 mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 331 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0; 332 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET); 333 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 1; 334 335 waa.console = console; 336 waa.scrdata = &mfb_screenlist; 337 waa.accessops = &mfb_accessops; 338 waa.accesscookie = sc; 339 340 config_found(self, &waa, wsemuldisplaydevprint); 341 } 342 343 static int 344 mfbioctl(v, cmd, data, flag, p) 345 void *v; 346 u_long cmd; 347 caddr_t data; 348 int flag; 349 struct proc *p; 350 { 351 struct mfb_softc *sc = v; 352 struct fb_devconfig *dc = sc->sc_dc; 353 int turnoff; 354 355 switch (cmd) { 356 case WSDISPLAYIO_GTYPE: 357 *(u_int *)data = WSDISPLAY_TYPE_MFB; 358 return (0); 359 360 case WSDISPLAYIO_GINFO: 361 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 362 wsd_fbip->height = sc->sc_dc->dc_ht; 363 wsd_fbip->width = sc->sc_dc->dc_wid; 364 wsd_fbip->depth = sc->sc_dc->dc_depth; 365 wsd_fbip->cmsize = 0; 366 #undef fbt 367 return (0); 368 369 case WSDISPLAYIO_GETCMAP: 370 case WSDISPLAYIO_PUTCMAP: 371 return (ENOTTY); 372 373 case WSDISPLAYIO_SVIDEO: 374 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 375 if ((dc->dc_blanked == 0) ^ turnoff) { 376 dc->dc_blanked = turnoff; 377 #if 0 /* XXX later XXX */ 378 To turn off, 379 - assign Bt455 cmap[1].green with value 0 (black), 380 - assign Bt431 register #0 with value 0x04 to hide sprite cursor. 381 #endif /* XXX XXX XXX */ 382 } 383 return (0); 384 385 case WSDISPLAYIO_GVIDEO: 386 *(u_int *)data = dc->dc_blanked ? 387 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 388 return (0); 389 390 case WSDISPLAYIO_GCURPOS: 391 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 392 return (0); 393 394 case WSDISPLAYIO_SCURPOS: 395 set_curpos(sc, (struct wsdisplay_curpos *)data); 396 bt431_set_curpos(sc); 397 return (0); 398 399 case WSDISPLAYIO_GCURMAX: 400 ((struct wsdisplay_curpos *)data)->x = 401 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 402 return (0); 403 404 case WSDISPLAYIO_GCURSOR: 405 return get_cursor(sc, (struct wsdisplay_cursor *)data); 406 407 case WSDISPLAYIO_SCURSOR: 408 return set_cursor(sc, (struct wsdisplay_cursor *)data); 409 } 410 return (ENOTTY); 411 } 412 413 static int 414 mfbmmap(v, offset, prot) 415 void *v; 416 off_t offset; 417 int prot; 418 { 419 struct mfb_softc *sc = v; 420 421 if (offset >= MX_FB_SIZE || offset < 0) 422 return (-1); 423 return machine_btop(sc->sc_dc->dc_paddr + offset); 424 } 425 426 static int 427 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 428 void *v; 429 const struct wsscreen_descr *type; 430 void **cookiep; 431 int *curxp, *curyp; 432 long *attrp; 433 { 434 struct mfb_softc *sc = v; 435 long defattr; 436 437 if (sc->nscreens > 0) 438 return (ENOMEM); 439 440 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */ 441 *curxp = 0; 442 *curyp = 0; 443 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 444 *attrp = defattr; 445 sc->nscreens++; 446 return (0); 447 } 448 449 static void 450 mfb_free_screen(v, cookie) 451 void *v; 452 void *cookie; 453 { 454 struct mfb_softc *sc = v; 455 456 if (sc->sc_dc == &mfb_console_dc) 457 panic("mfb_free_screen: console"); 458 459 sc->nscreens--; 460 } 461 462 static int 463 mfb_show_screen(v, cookie, waitok, cb, cbarg) 464 void *v; 465 void *cookie; 466 int waitok; 467 void (*cb) __P((void *, int, int)); 468 void *cbarg; 469 { 470 471 return (0); 472 } 473 474 /* EXPORT */ int 475 mfb_cnattach(addr) 476 tc_addr_t addr; 477 { 478 struct fb_devconfig *dcp = &mfb_console_dc; 479 long defattr; 480 481 mfb_getdevconfig(addr, dcp); 482 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 483 wsdisplay_cnattach(&mfb_stdscreen, &dcp->rinfo, 0, 0, defattr); 484 mfb_consaddr = addr; 485 return (0); 486 } 487 488 static int 489 mfbintr(arg) 490 void *arg; 491 { 492 struct mfb_softc *sc = arg; 493 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 494 void *vdac, *curs; 495 int v; 496 volatile register int junk; 497 498 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET); 499 #if 0 500 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0; 501 #endif 502 if (sc->sc_changed == 0) 503 return (1); 504 505 vdac = (void *)(mfbbase + MX_BT455_OFFSET); 506 curs = (void *)(mfbbase + MX_BT431_OFFSET); 507 v = sc->sc_changed; 508 sc->sc_changed = 0; 509 if (v & DATA_ENB_CHANGED) { 510 SELECT431(curs, BT431_REG_COMMAND); 511 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404; 512 } 513 if (v & DATA_CURCMAP_CHANGED) { 514 u_int8_t *cp = sc->sc_cursor.cc_color; 515 516 SELECT455(vdac, 8); 517 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 518 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb(); 519 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 520 521 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 522 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb(); 523 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 524 525 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 526 BYTE(vdac, bt_ovly) = cp[0]; tc_wmb(); 527 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 528 } 529 if (v & DATA_CURSHAPE_CHANGED) { 530 u_int8_t *ip, *mp, img, msk; 531 int bcnt; 532 533 ip = (u_int8_t *)sc->sc_cursor.cc_image; 534 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 535 bcnt = 0; 536 SELECT431(curs, BT431_REG_CRAM_BASE); 537 538 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 539 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 540 /* pad right half 32 pixel when smaller than 33 */ 541 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 542 HALF(curs, bt_ram) = 0; 543 tc_wmb(); 544 } 545 else { 546 img = *ip++; 547 msk = *mp++; 548 img &= msk; /* cookie off image */ 549 HALF(curs, bt_ram) 550 = (flip[msk] << 8) | flip[img]; 551 tc_wmb(); 552 } 553 bcnt += 2; 554 } 555 /* pad unoccupied scan lines */ 556 while (bcnt < CURSOR_MAX_SIZE * 16) { 557 HALF(curs, bt_ram) = 0; 558 tc_wmb(); 559 bcnt += 2; 560 } 561 } 562 return (1); 563 } 564 565 static void 566 mfbinit(dc) 567 struct fb_devconfig *dc; 568 { 569 caddr_t mfbbase = (caddr_t)dc->dc_vaddr; 570 void *vdac = (void *)(mfbbase + MX_BT455_OFFSET); 571 void *curs = (void *)(mfbbase + MX_BT431_OFFSET); 572 int i; 573 574 SELECT431(curs, BT431_REG_COMMAND); 575 HALF(curs, bt_ctl) = 0x0404; tc_wmb(); 576 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb(); 577 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb(); 578 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb(); 579 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb(); 580 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb(); 581 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb(); 582 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 583 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 584 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb(); 585 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb(); 586 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb(); 587 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb(); 588 589 /* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */ 590 SELECT455(vdac, 0); 591 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 592 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 593 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 594 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 595 BYTE(vdac, bt_cmap) = 0xff; tc_wmb(); 596 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 597 for (i = 2; i < 16; i++) { 598 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 599 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 600 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 601 } 602 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 603 BYTE(vdac, bt_ovly) = 0xff; tc_wmb(); 604 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 605 606 SELECT431(curs, BT431_REG_CRAM_BASE); 607 for (i = 0; i < 512; i++) { 608 HALF(curs, bt_ram) = 0; tc_wmb(); 609 } 610 } 611 612 static int 613 set_cursor(sc, p) 614 struct mfb_softc *sc; 615 struct wsdisplay_cursor *p; 616 { 617 #define cc (&sc->sc_cursor) 618 int v, count, index; 619 620 v = p->which; 621 if (v & WSDISPLAY_CURSOR_DOCMAP) { 622 index = p->cmap.index; 623 count = p->cmap.count; 624 if (index >= 2 || (index + count) > 2) 625 return (EINVAL); 626 if (!uvm_useracc(p->cmap.red, count, B_READ)) 627 return (EFAULT); 628 } 629 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 630 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 631 return (EINVAL); 632 count = ((p->size.x < 33) ? 4 : 8) * p->size.y; 633 if (!uvm_useracc(p->image, count, B_READ) || 634 !uvm_useracc(p->mask, count, B_READ)) 635 return (EFAULT); 636 } 637 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 638 if (v & WSDISPLAY_CURSOR_DOCUR) 639 cc->cc_hot = p->hot; 640 if (v & WSDISPLAY_CURSOR_DOPOS) 641 set_curpos(sc, &p->pos); 642 bt431_set_curpos(sc); 643 } 644 645 sc->sc_changed = 0; 646 if (v & WSDISPLAY_CURSOR_DOCUR) { 647 sc->sc_curenb = p->enable; 648 sc->sc_changed |= DATA_ENB_CHANGED; 649 } 650 if (v & WSDISPLAY_CURSOR_DOCMAP) { 651 copyin(p->cmap.red, &cc->cc_color[index], count); 652 sc->sc_changed |= DATA_CURCMAP_CHANGED; 653 } 654 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 655 cc->cc_size = p->size; 656 memset(cc->cc_image, 0, sizeof cc->cc_image); 657 copyin(p->image, cc->cc_image, count); 658 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count); 659 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 660 } 661 662 return (0); 663 #undef cc 664 } 665 666 static int 667 get_cursor(sc, p) 668 struct mfb_softc *sc; 669 struct wsdisplay_cursor *p; 670 { 671 return (ENOTTY); /* XXX */ 672 } 673 674 static void 675 set_curpos(sc, curpos) 676 struct mfb_softc *sc; 677 struct wsdisplay_curpos *curpos; 678 { 679 struct fb_devconfig *dc = sc->sc_dc; 680 int x = curpos->x, y = curpos->y; 681 682 if (y < 0) 683 y = 0; 684 else if (y > dc->dc_ht) 685 y = dc->dc_ht; 686 if (x < 0) 687 x = 0; 688 else if (x > dc->dc_wid) 689 x = dc->dc_wid; 690 sc->sc_cursor.cc_pos.x = x; 691 sc->sc_cursor.cc_pos.y = y; 692 } 693 694 static void 695 bt431_set_curpos(sc) 696 struct mfb_softc *sc; 697 { 698 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 699 void *curs = (void *)(mfbbase + MX_BT431_OFFSET); 700 u_int16_t twin; 701 int x, y, s; 702 703 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 704 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 705 706 x += sc->sc_cursor.cc_magic.x; 707 y += sc->sc_cursor.cc_magic.y; 708 709 s = spltty(); 710 711 SELECT431(curs, BT431_REG_CURSOR_X_LOW); 712 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb(); 713 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb(); 714 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb(); 715 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb(); 716 717 splx(s); 718 } 719