1 /* $NetBSD: sfbplus.c,v 1.6 2000/09/09 06:15:17 nisimura Exp $ */ 2 3 /* 4 * Copyright (c) 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: sfbplus.c,v 1.6 2000/09/09 06:15:17 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 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/bt459reg.h> 56 #include <dev/ic/bt463reg.h> 57 #include <dev/tc/sfbreg.h> 58 #include <dev/pci/tgareg.h> 59 60 #include <uvm/uvm_extern.h> 61 62 #if defined(pmax) 63 #define machine_btop(x) mips_btop(x) 64 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x) 65 #endif 66 67 #if defined(__alpha__) || defined(alpha) 68 #define machine_btop(x) alpha_btop(x) 69 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 70 #endif 71 72 /* Bt459/Bt463 hardware registers */ 73 #define bt_lo 0 74 #define bt_hi 1 75 #define bt_reg 2 76 #define bt_cmap 3 77 78 #define REG(base, index) *((u_int32_t *)(base) + (index)) 79 #define SELECT(vdac, regno) do { \ 80 REG(vdac, bt_lo) = ((regno) & 0x00ff); \ 81 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \ 82 tc_wmb(); \ 83 } while (0) 84 85 struct fb_devconfig { 86 vaddr_t dc_vaddr; /* memory space virtual base address */ 87 paddr_t dc_paddr; /* memory space physical base address */ 88 vsize_t dc_size; /* size of slot memory */ 89 int dc_wid; /* width of frame buffer */ 90 int dc_ht; /* height of frame buffer */ 91 int dc_depth; /* depth, bits per pixel */ 92 int dc_rowbytes; /* bytes in a FB scan line */ 93 vaddr_t dc_videobase; /* base of flat frame buffer */ 94 int dc_blanked; /* currently has video disabled */ 95 96 struct rasops_info rinfo; 97 }; 98 99 struct hwcmap256 { 100 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 101 u_int8_t r[CMAP_SIZE]; 102 u_int8_t g[CMAP_SIZE]; 103 u_int8_t b[CMAP_SIZE]; 104 }; 105 106 struct hwcursor64 { 107 struct wsdisplay_curpos cc_pos; 108 struct wsdisplay_curpos cc_hot; 109 struct wsdisplay_curpos cc_size; 110 struct wsdisplay_curpos cc_magic; 111 #define CURSOR_MAX_SIZE 64 112 u_int8_t cc_color[6]; 113 u_int64_t cc_image[64 + 64]; 114 }; 115 116 struct hwops { 117 void (*setlut) __P((void *, struct hwcmap256 *)); 118 void (*getlut) __P((void *, struct hwcmap256 *)); 119 void (*visible) __P((void *, int)); 120 void (*locate) __P((void *, int, int)); 121 void (*shape) __P((void *, struct wsdisplay_curpos *, u_int64_t *)); 122 void (*color) __P((void *, u_int8_t *)); 123 }; 124 125 struct sfb_softc { 126 struct device sc_dev; 127 struct fb_devconfig *sc_dc; /* device configuration */ 128 struct hwcmap256 sc_cmap; /* software copy of colormap */ 129 struct hwcursor64 sc_cursor; /* software copy of cursor */ 130 int sc_curenb; /* cursor sprite enabled */ 131 int sc_changed; /* need update of colormap */ 132 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 133 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 134 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 135 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 136 #define DATA_ALL_CHANGED 0x0f 137 int nscreens; 138 struct hwops sc_hwops; 139 void *sc_hw0, *sc_hw1; 140 }; 141 142 #define HX_MAGIC_X 368 143 #define HX_MAGIC_Y 38 144 145 static int sfbpmatch __P((struct device *, struct cfdata *, void *)); 146 static void sfbpattach __P((struct device *, struct device *, void *)); 147 148 struct cfattach sfbp_ca = { 149 sizeof(struct sfb_softc), sfbpmatch, sfbpattach, 150 }; 151 152 static void sfbp_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 153 static struct fb_devconfig sfbp_console_dc; 154 static tc_addr_t sfbp_consaddr; 155 156 extern const struct wsdisplay_emulops sfbp_emulops, sfbp_emulops32; 157 158 static struct wsscreen_descr sfb_stdscreen = { 159 "std", 0, 0, 160 NULL, /* textops */ 161 0, 0, 162 WSSCREEN_REVERSE 163 }; 164 165 static const struct wsscreen_descr *_sfb_scrlist[] = { 166 &sfb_stdscreen, 167 }; 168 169 static const struct wsscreen_list sfb_screenlist = { 170 sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist 171 }; 172 173 static int sfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 174 static paddr_t sfbmmap __P((void *, off_t, int)); 175 176 static int sfb_alloc_screen __P((void *, const struct wsscreen_descr *, 177 void **, int *, int *, long *)); 178 static void sfb_free_screen __P((void *, void *)); 179 static int sfb_show_screen __P((void *, void *, int, 180 void (*) (void *, int, int), void *)); 181 /* EXPORT */ int sfb_alloc_attr __P((void *, int, int, int, long *)); 182 183 static const struct wsdisplay_accessops sfb_accessops = { 184 sfbioctl, 185 sfbmmap, 186 sfb_alloc_screen, 187 sfb_free_screen, 188 sfb_show_screen, 189 0 /* load_font */ 190 }; 191 192 static void bt459visible __P((void *, int)); 193 static void bt459locate __P((void *, int, int)); 194 static void bt459shape __P((void *, struct wsdisplay_curpos *, u_int64_t *)); 195 static void bt459color __P((void *, u_int8_t *)); 196 static void bt459setlut __P((void *, struct hwcmap256 *)); 197 198 static void sfbpvisible __P((void *, int)); 199 static void sfbplocate __P((void *, int, int)); 200 static void sfbpshape __P((void *, struct wsdisplay_curpos *, u_int64_t *)); 201 static void bt463color __P((void *, u_int8_t *)); 202 static void noplut __P((void *, struct hwcmap256 *)); 203 204 205 /* EXPORT */ int sfbp_cnattach __P((tc_addr_t)); 206 static int sfbpintr __P((void *)); 207 static void sfbpinit __P((struct fb_devconfig *)); 208 209 static int get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *)); 210 static int set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *)); 211 static int set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *)); 212 static int get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *)); 213 214 215 /* 216 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 217 * M M M M I I I I M I M I M I M I 218 * [ before ] [ after ] 219 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 220 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 221 */ 222 static const u_int8_t shuffle[256] = { 223 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 224 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 225 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 226 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 227 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 228 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 229 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 230 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 231 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 232 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 233 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 234 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 235 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 236 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 237 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 238 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 239 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 240 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 241 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 242 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 243 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 244 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 245 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 246 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 247 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 248 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 249 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 250 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 251 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 252 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 253 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 254 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 255 }; 256 257 static int 258 sfbpmatch(parent, match, aux) 259 struct device *parent; 260 struct cfdata *match; 261 void *aux; 262 { 263 struct tc_attach_args *ta = aux; 264 265 if (strncmp("PMAGD", ta->ta_modname, 5) != 0) 266 return (0); 267 268 return (1); 269 } 270 271 static void 272 sfbp_getdevconfig(dense_addr, dc) 273 tc_addr_t dense_addr; 274 struct fb_devconfig *dc; 275 { 276 caddr_t sfbasic; 277 int i, hsetup, vsetup, vbase, cookie; 278 279 dc->dc_vaddr = dense_addr; 280 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr); 281 282 sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET); 283 hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP); 284 vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP); 285 i = *(u_int32_t *)(sfbasic + SFB_ASIC_DEEP); 286 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) = vbase = 1; 287 288 dc->dc_wid = (hsetup & 0x1ff) << 2; 289 dc->dc_ht = (vsetup & 0x7ff); 290 dc->dc_depth = (i & 1) ? 32 : 8; 291 dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8); 292 dc->dc_videobase = dc->dc_vaddr + 0x800000 + vbase * 4096; /* XXX */ 293 dc->dc_blanked = 0; 294 295 /* initialize colormap and cursor resource */ 296 sfbpinit(dc); 297 298 /* clear the screen */ 299 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 300 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 301 302 dc->rinfo.ri_flg = RI_CENTER; 303 dc->rinfo.ri_depth = dc->dc_depth; 304 dc->rinfo.ri_bits = (void *)dc->dc_videobase; 305 dc->rinfo.ri_width = dc->dc_wid; 306 dc->rinfo.ri_height = dc->dc_ht; 307 dc->rinfo.ri_stride = dc->dc_rowbytes; 308 dc->rinfo.ri_hw = sfbasic; 309 310 wsfont_init(); 311 /* prefer 8 pixel wide font */ 312 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0) 313 cookie = wsfont_find(NULL, 0, 0, 0); 314 if (cookie <= 0) { 315 printf("sfb: font table is empty\n"); 316 return; 317 } 318 319 /* the accelerated sfb_putchar() needs LSbit left */ 320 if (wsfont_lock(cookie, &dc->rinfo.ri_font, 321 WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) { 322 printf("sfb: couldn't lock font\n"); 323 return; 324 } 325 dc->rinfo.ri_wsfcookie = cookie; 326 327 rasops_init(&dc->rinfo, 34, 80); 328 329 /* XXX shouldn't be global */ 330 sfb_stdscreen.nrows = dc->rinfo.ri_rows; 331 sfb_stdscreen.ncols = dc->rinfo.ri_cols; 332 sfb_stdscreen.textops 333 = (dc->dc_depth == 8) ? &sfbp_emulops : &sfbp_emulops32; 334 sfb_stdscreen.capabilities = dc->rinfo.ri_caps; 335 /* our accelerated putchar can't underline */ 336 sfb_stdscreen.capabilities &= ~WSSCREEN_UNDERLINE; 337 } 338 339 static void 340 sfbpattach(parent, self, aux) 341 struct device *parent, *self; 342 void *aux; 343 { 344 struct sfb_softc *sc = (struct sfb_softc *)self; 345 struct tc_attach_args *ta = aux; 346 struct wsemuldisplaydev_attach_args waa; 347 struct hwcmap256 *cm; 348 caddr_t sfbasic; 349 int console; 350 351 console = (ta->ta_addr == sfbp_consaddr); 352 if (console) { 353 sc->sc_dc = &sfbp_console_dc; 354 sc->nscreens = 1; 355 } 356 else { 357 sc->sc_dc = (struct fb_devconfig *) 358 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 359 sfbp_getdevconfig(ta->ta_addr, sc->sc_dc); 360 } 361 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 362 sc->sc_dc->dc_depth); 363 364 cm = &sc->sc_cmap; 365 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */ 366 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */ 367 368 sc->sc_cursor.cc_magic.x = HX_MAGIC_X; 369 sc->sc_cursor.cc_magic.y = HX_MAGIC_Y; 370 371 if (sc->sc_dc->dc_depth == 8) { 372 sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET; 373 sc->sc_hw1 = sc->sc_hw0; 374 sc->sc_hwops.visible = bt459visible; 375 sc->sc_hwops.locate = bt459locate; 376 sc->sc_hwops.shape = bt459shape; 377 sc->sc_hwops.color = bt459color; 378 sc->sc_hwops.setlut = bt459setlut; 379 sc->sc_hwops.getlut = noplut; 380 } 381 else { 382 sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_ASIC_OFFSET; 383 sc->sc_hw1 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET; 384 sc->sc_hwops.visible = sfbpvisible; 385 sc->sc_hwops.locate = sfbplocate; 386 sc->sc_hwops.shape = sfbpshape; 387 sc->sc_hwops.color = bt463color; 388 sc->sc_hwops.setlut = noplut; 389 sc->sc_hwops.getlut = noplut; 390 } 391 392 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc); 393 394 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET); 395 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0; tc_wmb(); 396 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; tc_wmb(); 397 398 waa.console = console; 399 waa.scrdata = &sfb_screenlist; 400 waa.accessops = &sfb_accessops; 401 waa.accesscookie = sc; 402 403 config_found(self, &waa, wsemuldisplaydevprint); 404 } 405 406 static int 407 sfbioctl(v, cmd, data, flag, p) 408 void *v; 409 u_long cmd; 410 caddr_t data; 411 int flag; 412 struct proc *p; 413 { 414 struct sfb_softc *sc = v; 415 struct fb_devconfig *dc = sc->sc_dc; 416 int turnoff; 417 418 switch (cmd) { 419 case WSDISPLAYIO_GTYPE: 420 *(u_int *)data = WSDISPLAY_TYPE_SFB; /* XXX SFBP XXX */ 421 return (0); 422 423 case WSDISPLAYIO_GINFO: 424 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 425 wsd_fbip->height = sc->sc_dc->dc_ht; 426 wsd_fbip->width = sc->sc_dc->dc_wid; 427 wsd_fbip->depth = sc->sc_dc->dc_depth; 428 wsd_fbip->cmsize = CMAP_SIZE; 429 #undef fbt 430 return (0); 431 432 case WSDISPLAYIO_GETCMAP: 433 return get_cmap(sc, (struct wsdisplay_cmap *)data); 434 435 case WSDISPLAYIO_PUTCMAP: 436 return set_cmap(sc, (struct wsdisplay_cmap *)data); 437 438 case WSDISPLAYIO_SVIDEO: 439 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 440 if ((dc->dc_blanked == 0) ^ turnoff) { 441 dc->dc_blanked = turnoff; 442 #if 0 /* XXX later XXX */ 443 Low order 3bit control visibilities of screen and builtin cursor. 444 #endif /* XXX XXX XXX */ 445 } 446 return (0); 447 448 case WSDISPLAYIO_GVIDEO: 449 *(u_int *)data = dc->dc_blanked ? 450 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 451 return (0); 452 453 case WSDISPLAYIO_GCURPOS: 454 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 455 return (0); 456 457 case WSDISPLAYIO_SCURPOS: { 458 struct wsdisplay_curpos *pos = (void *)data; 459 int x, y; 460 461 x = pos->x; 462 y = pos->y; 463 if (y < 0) 464 y = 0; 465 else if (y > dc->dc_ht) 466 y = dc->dc_ht; 467 if (x < 0) 468 x = 0; 469 else if (x > dc->dc_wid) 470 x = dc->dc_wid; 471 sc->sc_cursor.cc_pos.x = x; 472 sc->sc_cursor.cc_pos.y = y; 473 x -= sc->sc_cursor.cc_hot.x; 474 y -= sc->sc_cursor.cc_hot.y; 475 x += sc->sc_cursor.cc_magic.x; 476 y += sc->sc_cursor.cc_magic.y; 477 (*sc->sc_hwops.locate)(sc->sc_hw0, x, y); 478 return (0); 479 } 480 481 case WSDISPLAYIO_GCURMAX: 482 ((struct wsdisplay_curpos *)data)->x = 483 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 484 return (0); 485 486 case WSDISPLAYIO_GCURSOR: 487 return get_cursor(sc, (struct wsdisplay_cursor *)data); 488 489 case WSDISPLAYIO_SCURSOR: 490 return set_cursor(sc, (struct wsdisplay_cursor *)data); 491 } 492 return ENOTTY; 493 } 494 495 paddr_t 496 sfbmmap(v, offset, prot) 497 void *v; 498 off_t offset; 499 int prot; 500 { 501 struct sfb_softc *sc = v; 502 503 if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */ 504 return (-1); 505 return machine_btop(sc->sc_dc->dc_paddr + offset); 506 } 507 508 static int 509 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 510 void *v; 511 const struct wsscreen_descr *type; 512 void **cookiep; 513 int *curxp, *curyp; 514 long *attrp; 515 { 516 struct sfb_softc *sc = v; 517 long defattr; 518 519 if (sc->nscreens > 0) 520 return (ENOMEM); 521 522 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */ 523 *curxp = 0; 524 *curyp = 0; 525 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 526 *attrp = defattr; 527 sc->nscreens++; 528 return (0); 529 } 530 531 void 532 sfb_free_screen(v, cookie) 533 void *v; 534 void *cookie; 535 { 536 struct sfb_softc *sc = v; 537 538 if (sc->sc_dc == &sfbp_console_dc) 539 panic("sfb_free_screen: console"); 540 541 sc->nscreens--; 542 } 543 544 static int 545 sfb_show_screen(v, cookie, waitok, cb, cbarg) 546 void *v; 547 void *cookie; 548 int waitok; 549 void (*cb) __P((void *, int, int)); 550 void *cbarg; 551 { 552 553 return (0); 554 } 555 556 int 557 sfbp_cnattach(addr) 558 tc_addr_t addr; 559 { 560 struct fb_devconfig *dcp = &sfbp_console_dc; 561 long defattr; 562 563 sfbp_getdevconfig(addr, dcp); 564 565 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 566 567 wsdisplay_cnattach(&sfb_stdscreen, &dcp->rinfo, 0, 0, defattr); 568 sfbp_consaddr = addr; 569 return(0); 570 } 571 572 static int 573 sfbpintr(arg) 574 void *arg; 575 { 576 struct sfb_softc *sc = arg; 577 caddr_t sfbasic = (caddr_t)sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET; 578 int v; 579 u_int32_t sisr; 580 581 #define cc (&sc->sc_cursor) 582 sisr = *((u_int32_t *)sfbasic + TGA_REG_SISR); 583 584 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0; 585 586 if (sc->sc_changed == 0) 587 goto finish; 588 589 v = sc->sc_changed; 590 sc->sc_changed = 0; 591 592 if (v & DATA_ENB_CHANGED) 593 (*sc->sc_hwops.visible)(sc->sc_hw0, sc->sc_curenb); 594 if (v & DATA_CURCMAP_CHANGED) 595 (*sc->sc_hwops.color)(sc->sc_hw1, cc->cc_color); 596 if (v & DATA_CURSHAPE_CHANGED) 597 (*sc->sc_hwops.shape)(sc->sc_hw0, &cc->cc_size, cc->cc_image); 598 if (v & DATA_CMAP_CHANGED) 599 (*sc->sc_hwops.setlut)(sc->sc_hw1, &sc->sc_cmap); 600 601 finish: 602 *((u_int32_t *)sfbasic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb(); 603 return (1); 604 #undef cc 605 } 606 607 static void 608 sfbpinit(dc) 609 struct fb_devconfig *dc; 610 { 611 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET); 612 caddr_t vdac = (caddr_t)(dc->dc_vaddr + SFB_RAMDAC_OFFSET); 613 int i; 614 615 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0; 616 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0; 617 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0; /* MODE_SIMPLE */ 618 *(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3; /* ROP_COPY */ 619 620 if (dc->dc_depth == 8) { 621 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */ 622 623 SELECT(vdac, BT459_IREG_COMMAND_0); 624 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb(); 625 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb(); 626 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb(); 627 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb(); 628 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb(); 629 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb(); 630 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb(); 631 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb(); 632 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb(); 633 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb(); 634 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb(); 635 636 SELECT(vdac, BT459_IREG_CCR); 637 REG(vdac, bt_reg) = 0x0; tc_wmb(); 638 REG(vdac, bt_reg) = 0x0; tc_wmb(); 639 REG(vdac, bt_reg) = 0x0; tc_wmb(); 640 REG(vdac, bt_reg) = 0x0; tc_wmb(); 641 REG(vdac, bt_reg) = 0x0; tc_wmb(); 642 REG(vdac, bt_reg) = 0x0; tc_wmb(); 643 REG(vdac, bt_reg) = 0x0; tc_wmb(); 644 REG(vdac, bt_reg) = 0x0; tc_wmb(); 645 REG(vdac, bt_reg) = 0x0; tc_wmb(); 646 REG(vdac, bt_reg) = 0x0; tc_wmb(); 647 REG(vdac, bt_reg) = 0x0; tc_wmb(); 648 REG(vdac, bt_reg) = 0x0; tc_wmb(); 649 REG(vdac, bt_reg) = 0x0; tc_wmb(); 650 651 /* build sane colormap */ 652 SELECT(vdac, 0); 653 REG(vdac, bt_cmap) = 0; tc_wmb(); 654 REG(vdac, bt_cmap) = 0; tc_wmb(); 655 REG(vdac, bt_cmap) = 0; tc_wmb(); 656 for (i = 1; i < CMAP_SIZE; i++) { 657 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 658 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 659 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 660 } 661 662 /* clear out cursor image */ 663 SELECT(vdac, BT459_IREG_CRAM_BASE); 664 for (i = 0; i < 1024; i++) 665 REG(vdac, bt_reg) = 0xff; tc_wmb(); 666 667 /* 668 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 669 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for 670 * image color. CCOLOR_1 will be never used. 671 */ 672 SELECT(vdac, BT459_IREG_CCOLOR_1); 673 REG(vdac, bt_reg) = 0xff; tc_wmb(); 674 REG(vdac, bt_reg) = 0xff; tc_wmb(); 675 REG(vdac, bt_reg) = 0xff; tc_wmb(); 676 677 REG(vdac, bt_reg) = 0; tc_wmb(); 678 REG(vdac, bt_reg) = 0; tc_wmb(); 679 REG(vdac, bt_reg) = 0; tc_wmb(); 680 681 REG(vdac, bt_reg) = 0xff; tc_wmb(); 682 REG(vdac, bt_reg) = 0xff; tc_wmb(); 683 REG(vdac, bt_reg) = 0xff; tc_wmb(); 684 } else { 685 SELECT(vdac, BT463_IREG_COMMAND_0); 686 REG(vdac, bt_reg) = 0x40; tc_wmb(); /* CMD 0 */ 687 REG(vdac, bt_reg) = 0x46; tc_wmb(); /* CMD 1 */ 688 REG(vdac, bt_reg) = 0xc0; tc_wmb(); /* CMD 2 */ 689 REG(vdac, bt_reg) = 0; tc_wmb(); /* !? 204 !? */ 690 REG(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 0:7 */ 691 REG(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 8:15 */ 692 REG(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 16:23 */ 693 REG(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 24:27 */ 694 REG(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 0:7 */ 695 REG(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 8:15 */ 696 REG(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 16:23 */ 697 REG(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 24:27 */ 698 REG(vdac, bt_reg) = 0x00; tc_wmb(); 699 700 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */ 701 { 702 static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = { 703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 704 }; 705 706 SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE); 707 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) { 708 REG(vdac, bt_reg) = windowtype[i]; /* 0:7 */ 709 REG(vdac, bt_reg) = windowtype[i] >> 8; /* 8:15 */ 710 REG(vdac, bt_reg) = windowtype[i] >> 16; /* 16:23 */ 711 } 712 } 713 #endif 714 715 SELECT(vdac, BT463_IREG_CPALETTE_RAM); 716 REG(vdac, bt_cmap) = 0; tc_wmb(); 717 REG(vdac, bt_cmap) = 0; tc_wmb(); 718 REG(vdac, bt_cmap) = 0; tc_wmb(); 719 for (i = 1; i < 256; i++) { 720 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 721 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 722 REG(vdac, bt_cmap) = 0xff; tc_wmb(); 723 } 724 725 /* !? Eeeh !? */ 726 SELECT(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */); 727 for (i = 0; i < 256; i++) { 728 REG(vdac, bt_cmap) = i; tc_wmb(); 729 REG(vdac, bt_cmap) = i; tc_wmb(); 730 REG(vdac, bt_cmap) = i; tc_wmb(); 731 } 732 } 733 } 734 735 static int 736 get_cmap(sc, p) 737 struct sfb_softc *sc; 738 struct wsdisplay_cmap *p; 739 { 740 u_int index = p->index, count = p->count; 741 742 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 743 return (EINVAL); 744 745 if (!uvm_useracc(p->red, count, B_WRITE) || 746 !uvm_useracc(p->green, count, B_WRITE) || 747 !uvm_useracc(p->blue, count, B_WRITE)) 748 return (EFAULT); 749 750 copyout(&sc->sc_cmap.r[index], p->red, count); 751 copyout(&sc->sc_cmap.g[index], p->green, count); 752 copyout(&sc->sc_cmap.b[index], p->blue, count); 753 754 return (0); 755 } 756 757 static int 758 set_cmap(sc, p) 759 struct sfb_softc *sc; 760 struct wsdisplay_cmap *p; 761 { 762 u_int index = p->index, count = p->count; 763 764 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 765 return (EINVAL); 766 767 if (!uvm_useracc(p->red, count, B_READ) || 768 !uvm_useracc(p->green, count, B_READ) || 769 !uvm_useracc(p->blue, count, B_READ)) 770 return (EFAULT); 771 772 copyin(p->red, &sc->sc_cmap.r[index], count); 773 copyin(p->green, &sc->sc_cmap.g[index], count); 774 copyin(p->blue, &sc->sc_cmap.b[index], count); 775 776 sc->sc_changed |= DATA_CMAP_CHANGED; 777 778 return (0); 779 } 780 781 782 static int 783 set_cursor(sc, p) 784 struct sfb_softc *sc; 785 struct wsdisplay_cursor *p; 786 { 787 #define cc (&sc->sc_cursor) 788 int v, index, count, icount, x, y; 789 790 v = p->which; 791 if (v & WSDISPLAY_CURSOR_DOCMAP) { 792 index = p->cmap.index; 793 count = p->cmap.count; 794 if (index >= 2 || (index + count) > 2) 795 return (EINVAL); 796 if (!uvm_useracc(p->cmap.red, count, B_READ) || 797 !uvm_useracc(p->cmap.green, count, B_READ) || 798 !uvm_useracc(p->cmap.blue, count, B_READ)) 799 return (EFAULT); 800 } 801 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 802 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 803 return (EINVAL); 804 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 805 if (!uvm_useracc(p->image, icount, B_READ) || 806 !uvm_useracc(p->mask, icount, B_READ)) 807 return (EFAULT); 808 } 809 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 810 if (v & WSDISPLAY_CURSOR_DOCUR) 811 cc->cc_hot = p->hot; 812 if (v & WSDISPLAY_CURSOR_DOPOS) { 813 struct fb_devconfig *dc = sc->sc_dc; 814 815 x = p->pos.x; 816 y = p->pos.y; 817 if (y < 0) 818 y = 0; 819 else if (y > dc->dc_ht) 820 y = dc->dc_ht; 821 if (x < 0) 822 x = 0; 823 else if (x > dc->dc_wid) 824 x = dc->dc_wid; 825 sc->sc_cursor.cc_pos.x = x; 826 sc->sc_cursor.cc_pos.y = y; 827 } 828 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 829 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 830 x += sc->sc_cursor.cc_magic.x; 831 y += sc->sc_cursor.cc_magic.y; 832 (*sc->sc_hwops.locate)(sc->sc_hw0, x, y); 833 } 834 835 sc->sc_changed = 0; 836 if (v & WSDISPLAY_CURSOR_DOCUR) { 837 sc->sc_curenb = p->enable; 838 sc->sc_changed |= DATA_ENB_CHANGED; 839 } 840 if (v & WSDISPLAY_CURSOR_DOCMAP) { 841 copyin(p->cmap.red, &cc->cc_color[index], count); 842 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 843 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 844 sc->sc_changed |= DATA_CURCMAP_CHANGED; 845 } 846 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 847 cc->cc_size = p->size; 848 memset(cc->cc_image, 0, sizeof cc->cc_image); 849 copyin(p->image, cc->cc_image, icount); 850 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount); 851 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 852 } 853 854 return (0); 855 #undef cc 856 } 857 858 static int 859 get_cursor(sc, p) 860 struct sfb_softc *sc; 861 struct wsdisplay_cursor *p; 862 { 863 return (ENOTTY); /* XXX */ 864 } 865 866 int 867 sfb_alloc_attr(id, fg, bg, flags, attrp) 868 void *id; 869 int fg, bg, flags; 870 long *attrp; 871 { 872 if (flags & (WSATTR_HILIT | WSATTR_BLINK | 873 WSATTR_UNDERLINE | WSATTR_WSCOLORS)) 874 return (EINVAL); 875 if (flags & WSATTR_REVERSE) 876 *attrp = 1; 877 else 878 *attrp = 0; 879 return (0); 880 } 881 882 static void 883 bt459visible(hw, on) 884 void *hw; 885 int on; 886 { 887 SELECT(hw, BT459_IREG_CCR); 888 REG(hw, bt_reg) = (on) ? 0xc0 : 0x00; 889 tc_wmb(); 890 } 891 892 static void 893 sfbpvisible(hw, on) 894 void *hw; 895 int on; 896 { 897 } 898 899 static void 900 bt459locate(hw, x, y) 901 void *hw; 902 int x, y; 903 { 904 int s; 905 906 s = spltty(); 907 SELECT(hw, BT459_IREG_CURSOR_X_LOW); 908 REG(hw, bt_reg) = x; tc_wmb(); 909 REG(hw, bt_reg) = x >> 8; tc_wmb(); 910 REG(hw, bt_reg) = y; tc_wmb(); 911 REG(hw, bt_reg) = y >> 8; tc_wmb(); 912 splx(s); 913 } 914 915 static void 916 sfbplocate(hw, x, y) 917 void *hw; 918 int x, y; 919 { 920 *((u_int32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff); 921 tc_wmb(); 922 } 923 924 static void 925 bt459color(hw, cp) 926 void *hw; 927 u_int8_t *cp; 928 { 929 SELECT(hw, BT459_IREG_CCOLOR_2); 930 REG(hw, bt_reg) = cp[1]; tc_wmb(); 931 REG(hw, bt_reg) = cp[3]; tc_wmb(); 932 REG(hw, bt_reg) = cp[5]; tc_wmb(); 933 934 REG(hw, bt_reg) = cp[0]; tc_wmb(); 935 REG(hw, bt_reg) = cp[2]; tc_wmb(); 936 REG(hw, bt_reg) = cp[4]; tc_wmb(); 937 } 938 939 static void 940 bt463color(hw, cp) 941 void *hw; 942 u_int8_t *cp; 943 { 944 } 945 946 static void 947 bt459shape(hw, size, image) 948 void *hw; 949 struct wsdisplay_curpos *size; 950 u_int64_t *image; 951 { 952 u_int8_t *ip, *mp, img, msk; 953 u_int8_t u; 954 int bcnt; 955 956 ip = (u_int8_t *)image; 957 mp = (u_int8_t *)(image + CURSOR_MAX_SIZE); 958 959 bcnt = 0; 960 SELECT(hw, BT459_IREG_CRAM_BASE+0); 961 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 962 while (bcnt < size->y * 16) { 963 /* pad right half 32 pixel when smaller than 33 */ 964 if ((bcnt & 0x8) && size->x < 33) { 965 REG(hw, bt_reg) = 0; tc_wmb(); 966 REG(hw, bt_reg) = 0; tc_wmb(); 967 } 968 else { 969 img = *ip++; 970 msk = *mp++; 971 img &= msk; /* cookie off image */ 972 u = (msk & 0x0f) << 4 | (img & 0x0f); 973 REG(hw, bt_reg) = shuffle[u]; tc_wmb(); 974 u = (msk & 0xf0) | (img & 0xf0) >> 4; 975 REG(hw, bt_reg) = shuffle[u]; tc_wmb(); 976 } 977 bcnt += 2; 978 } 979 /* pad unoccupied scan lines */ 980 while (bcnt < CURSOR_MAX_SIZE * 16) { 981 REG(hw, bt_reg) = 0; tc_wmb(); 982 REG(hw, bt_reg) = 0; tc_wmb(); 983 bcnt += 2; 984 } 985 } 986 987 static void 988 sfbpshape(hw, size, image) 989 void *hw; 990 struct wsdisplay_curpos *size; 991 u_int64_t *image; 992 { 993 } 994 995 static void 996 bt459setlut(hw, cm) 997 void *hw; 998 struct hwcmap256 *cm; 999 { 1000 int index; 1001 1002 SELECT(hw, 0); 1003 for (index = 0; index < CMAP_SIZE; index++) { 1004 REG(hw, bt_cmap) = cm->r[index]; tc_wmb(); 1005 REG(hw, bt_cmap) = cm->g[index]; tc_wmb(); 1006 REG(hw, bt_cmap) = cm->b[index]; tc_wmb(); 1007 } 1008 } 1009 1010 static void 1011 noplut(hw, cm) 1012 void *hw; 1013 struct hwcmap256 *cm; 1014 { 1015 } 1016