1 /* $NetBSD: mfb.c,v 1.20 1999/12/06 19:26:00 drochner 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.20 1999/12/06 19:26:00 drochner 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/rcons/raster.h> 50 #include <dev/wscons/wsconsio.h> 51 #include <dev/wscons/wscons_raster.h> 52 #include <dev/wscons/wsdisplayvar.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 struct raster dc_raster; /* raster description */ 104 struct rcons dc_rcons; /* raster blitter control info */ 105 int dc_blanked; /* currently has video disabled */ 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 const struct wsdisplay_emulops mfb_emulops = { 153 rcons_cursor, /* could use hardware cursor; punt */ 154 rcons_mapchar, 155 rcons_putchar, 156 rcons_copycols, 157 rcons_erasecols, 158 rcons_copyrows, 159 rcons_eraserows, 160 rcons_alloc_attr 161 }; 162 163 static struct wsscreen_descr mfb_stdscreen = { 164 "std", 0, 0, 165 &mfb_emulops, 166 0, 0, 167 WSSCREEN_REVERSE 168 }; 169 170 static const struct wsscreen_descr *_mfb_scrlist[] = { 171 &mfb_stdscreen, 172 }; 173 174 static const struct wsscreen_list mfb_screenlist = { 175 sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist 176 }; 177 178 static int mfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 179 static int mfbmmap __P((void *, off_t, int)); 180 181 static int mfb_alloc_screen __P((void *, const struct wsscreen_descr *, 182 void **, int *, int *, long *)); 183 static void mfb_free_screen __P((void *, void *)); 184 static int mfb_show_screen __P((void *, void *, int, 185 void (*) (void *, int, int), void *)); 186 187 static const struct wsdisplay_accessops mfb_accessops = { 188 mfbioctl, 189 mfbmmap, 190 mfb_alloc_screen, 191 mfb_free_screen, 192 mfb_show_screen, 193 0 /* load_font */ 194 }; 195 196 int mfb_cnattach __P((tc_addr_t)); 197 static int mfbintr __P((void *)); 198 static void mfbinit __P((struct fb_devconfig *)); 199 200 static int set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *)); 201 static int get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *)); 202 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *)); 203 static void bt431_set_curpos __P((struct mfb_softc *)); 204 205 /* bit order reverse */ 206 static const u_int8_t flip[256] = { 207 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 208 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 209 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 210 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 211 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 212 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 213 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 214 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 215 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 216 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 217 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 218 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 219 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 220 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 221 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 222 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 223 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 224 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 225 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 226 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 227 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 228 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 229 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 230 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 231 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 232 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 233 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 234 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 235 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 236 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 237 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 238 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 239 }; 240 241 static int 242 mfbmatch(parent, match, aux) 243 struct device *parent; 244 struct cfdata *match; 245 void *aux; 246 { 247 struct tc_attach_args *ta = aux; 248 249 if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0) 250 return (0); 251 252 return (1); 253 } 254 255 static void 256 mfb_getdevconfig(dense_addr, dc) 257 tc_addr_t dense_addr; 258 struct fb_devconfig *dc; 259 { 260 struct raster *rap; 261 struct rcons *rcp; 262 int i; 263 264 dc->dc_vaddr = dense_addr; 265 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET); 266 267 dc->dc_wid = 1280; 268 dc->dc_ht = 1024; 269 dc->dc_depth = 8; 270 dc->dc_rowbytes = 2048; 271 dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET; 272 dc->dc_blanked = 0; 273 274 /* initialize colormap and cursor resource */ 275 mfbinit(dc); 276 277 /* clear the screen */ 278 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 279 *(u_int32_t *)(dc->dc_videobase + i) = 0; 280 281 /* initialize the raster */ 282 rap = &dc->dc_raster; 283 rap->width = dc->dc_wid; 284 rap->height = dc->dc_ht; 285 rap->depth = dc->dc_depth; 286 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t); 287 rap->pixels = (u_int32_t *)dc->dc_videobase; 288 289 /* initialize the raster console blitter */ 290 rcp = &dc->dc_rcons; 291 rcp->rc_sp = rap; 292 rcp->rc_crow = rcp->rc_ccol = -1; 293 rcp->rc_crowp = &rcp->rc_crow; 294 rcp->rc_ccolp = &rcp->rc_ccol; 295 rcons_init(rcp, 34, 80); 296 297 mfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow; 298 mfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol; 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->dc_rcons; /* one and only for now */ 441 *curxp = 0; 442 *curyp = 0; 443 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 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 483 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr); 484 485 wsdisplay_cnattach(&mfb_stdscreen, &dcp->dc_rcons, 486 0, 0, defattr); 487 mfb_consaddr = addr; 488 return (0); 489 } 490 491 492 static int 493 mfbintr(arg) 494 void *arg; 495 { 496 struct mfb_softc *sc = arg; 497 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 498 void *vdac, *curs; 499 int v; 500 volatile register int junk; 501 502 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET); 503 #if 0 504 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0; 505 #endif 506 if (sc->sc_changed == 0) 507 return (1); 508 509 vdac = (void *)(mfbbase + MX_BT455_OFFSET); 510 curs = (void *)(mfbbase + MX_BT431_OFFSET); 511 v = sc->sc_changed; 512 sc->sc_changed = 0; 513 if (v & DATA_ENB_CHANGED) { 514 SELECT431(curs, BT431_REG_COMMAND); 515 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404; 516 } 517 if (v & DATA_CURCMAP_CHANGED) { 518 u_int8_t *cp = sc->sc_cursor.cc_color; 519 520 SELECT455(vdac, 8); 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_cmap) = 0; tc_wmb(); 526 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb(); 527 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 528 529 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 530 BYTE(vdac, bt_ovly) = cp[0]; tc_wmb(); 531 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 532 } 533 if (v & DATA_CURSHAPE_CHANGED) { 534 u_int8_t *ip, *mp, img, msk; 535 int bcnt; 536 537 ip = (u_int8_t *)sc->sc_cursor.cc_image; 538 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 539 bcnt = 0; 540 SELECT431(curs, BT431_REG_CRAM_BASE); 541 542 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 543 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 544 /* pad right half 32 pixel when smaller than 33 */ 545 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 546 HALF(curs, bt_ram) = 0; 547 tc_wmb(); 548 } 549 else { 550 img = *ip++; 551 msk = *mp++; 552 img &= msk; /* cookie off image */ 553 HALF(curs, bt_ram) 554 = (flip[msk] << 8) | flip[img]; 555 tc_wmb(); 556 } 557 bcnt += 2; 558 } 559 /* pad unoccupied scan lines */ 560 while (bcnt < CURSOR_MAX_SIZE * 16) { 561 HALF(curs, bt_ram) = 0; 562 tc_wmb(); 563 bcnt += 2; 564 } 565 } 566 return (1); 567 } 568 569 static void 570 mfbinit(dc) 571 struct fb_devconfig *dc; 572 { 573 caddr_t mfbbase = (caddr_t)dc->dc_vaddr; 574 void *vdac = (void *)(mfbbase + MX_BT455_OFFSET); 575 void *curs = (void *)(mfbbase + MX_BT431_OFFSET); 576 int i; 577 578 SELECT431(curs, BT431_REG_COMMAND); 579 HALF(curs, bt_ctl) = 0x0404; tc_wmb(); 580 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb(); 581 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb(); 582 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb(); 583 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb(); 584 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb(); 585 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb(); 586 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 587 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 588 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb(); 589 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb(); 590 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb(); 591 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb(); 592 593 /* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */ 594 SELECT455(vdac, 0); 595 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 596 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 597 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 598 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 599 BYTE(vdac, bt_cmap) = 0xff; tc_wmb(); 600 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 601 for (i = 2; i < 16; i++) { 602 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 603 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 604 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 605 } 606 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 607 BYTE(vdac, bt_ovly) = 0xff; tc_wmb(); 608 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 609 610 SELECT431(curs, BT431_REG_CRAM_BASE); 611 for (i = 0; i < 512; i++) { 612 HALF(curs, bt_ram) = 0; tc_wmb(); 613 } 614 } 615 616 static int 617 set_cursor(sc, p) 618 struct mfb_softc *sc; 619 struct wsdisplay_cursor *p; 620 { 621 #define cc (&sc->sc_cursor) 622 int v, count, index; 623 624 v = p->which; 625 if (v & WSDISPLAY_CURSOR_DOCMAP) { 626 index = p->cmap.index; 627 count = p->cmap.count; 628 if (index >= 2 || (index + count) > 2) 629 return (EINVAL); 630 if (!uvm_useracc(p->cmap.red, count, B_READ)) 631 return (EFAULT); 632 } 633 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 634 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 635 return (EINVAL); 636 count = ((p->size.x < 33) ? 4 : 8) * p->size.y; 637 if (!uvm_useracc(p->image, count, B_READ) || 638 !uvm_useracc(p->mask, count, B_READ)) 639 return (EFAULT); 640 } 641 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 642 if (v & WSDISPLAY_CURSOR_DOCUR) 643 cc->cc_hot = p->hot; 644 if (v & WSDISPLAY_CURSOR_DOPOS) 645 set_curpos(sc, &p->pos); 646 bt431_set_curpos(sc); 647 } 648 649 sc->sc_changed = 0; 650 if (v & WSDISPLAY_CURSOR_DOCUR) { 651 sc->sc_curenb = p->enable; 652 sc->sc_changed |= DATA_ENB_CHANGED; 653 } 654 if (v & WSDISPLAY_CURSOR_DOCMAP) { 655 copyin(p->cmap.red, &cc->cc_color[index], count); 656 sc->sc_changed |= DATA_CURCMAP_CHANGED; 657 } 658 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 659 cc->cc_size = p->size; 660 memset(cc->cc_image, 0, sizeof cc->cc_image); 661 copyin(p->image, cc->cc_image, count); 662 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count); 663 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 664 } 665 666 return (0); 667 #undef cc 668 } 669 670 static int 671 get_cursor(sc, p) 672 struct mfb_softc *sc; 673 struct wsdisplay_cursor *p; 674 { 675 return (ENOTTY); /* XXX */ 676 } 677 678 static void 679 set_curpos(sc, curpos) 680 struct mfb_softc *sc; 681 struct wsdisplay_curpos *curpos; 682 { 683 struct fb_devconfig *dc = sc->sc_dc; 684 int x = curpos->x, y = curpos->y; 685 686 if (y < 0) 687 y = 0; 688 else if (y > dc->dc_ht) 689 y = dc->dc_ht; 690 if (x < 0) 691 x = 0; 692 else if (x > dc->dc_wid) 693 x = dc->dc_wid; 694 sc->sc_cursor.cc_pos.x = x; 695 sc->sc_cursor.cc_pos.y = y; 696 } 697 698 static void 699 bt431_set_curpos(sc) 700 struct mfb_softc *sc; 701 { 702 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 703 void *curs = (void *)(mfbbase + MX_BT431_OFFSET); 704 u_int16_t twin; 705 int x, y, s; 706 707 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 708 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 709 710 x += sc->sc_cursor.cc_magic.x; 711 y += sc->sc_cursor.cc_magic.y; 712 713 s = spltty(); 714 715 SELECT431(curs, BT431_REG_CURSOR_X_LOW); 716 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb(); 717 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb(); 718 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb(); 719 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb(); 720 721 splx(s); 722 } 723