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