1 /* $NetBSD: gffb.c,v 1.39 2026/08/18 15:22:02 martin Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * A console driver for nvidia geforce graphics controllers 30 * tested on macppc only so far, should work on other hardware as long as 31 * something sets up a usable graphics mode and sets the right device properties 32 * This driver should work with all NV1x and NV3x hardware but so far it's been 33 * tested only on NV11 / GeForce2 MX and 5200, U and Go variants ( the 5200 Go 34 * is used in various PowerBooks and iMac G5, and Apple shipped 5200U cards with 35 * some G5s). Needs testing with more hardware and if successful, PCI IDs need 36 * to be added to gffb_match() 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: gffb.c,v 1.39 2026/08/18 15:22:02 martin Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 #include <sys/lwp.h> 47 #include <sys/kauth.h> 48 #include <sys/atomic.h> 49 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/pcireg.h> 52 #include <dev/pci/pcidevs.h> 53 #include <dev/pci/pciio.h> 54 #include <dev/pci/gffbreg.h> 55 56 #include <dev/wscons/wsdisplayvar.h> 57 #include <dev/wscons/wsconsio.h> 58 #include <dev/wsfont/wsfont.h> 59 #include <dev/rasops/rasops.h> 60 #include <dev/wscons/wsdisplay_vconsvar.h> 61 #include <dev/pci/wsdisplay_pci.h> 62 #include <dev/wscons/wsdisplay_glyphcachevar.h> 63 64 #include "opt_gffb.h" 65 #include "opt_vcons.h" 66 67 #ifdef GFFB_DEBUG 68 #define DPRINTF printf 69 #else 70 #define DPRINTF while(0) printf 71 #endif 72 73 struct gffb_softc { 74 device_t sc_dev; 75 76 pci_chipset_tag_t sc_pc; 77 pcitag_t sc_pcitag; 78 79 bus_space_tag_t sc_memt; 80 bus_space_tag_t sc_iot; 81 82 bus_space_handle_t sc_regh, sc_fbh; 83 bus_addr_t sc_fb, sc_reg; 84 bus_size_t sc_fbsize, sc_regsize; 85 uint8_t *sc_fbaddr; 86 size_t sc_vramsize; 87 uint32_t sc_fboffset; 88 89 int sc_width, sc_height, sc_depth, sc_stride; 90 int sc_locked, sc_accel, sc_mobile, sc_video, sc_bl_level; 91 struct vcons_screen sc_console_screen; 92 struct wsscreen_descr sc_defaultscreen_descr; 93 const struct wsscreen_descr *sc_screens[1]; 94 struct wsscreen_list sc_screenlist; 95 struct vcons_data vd; 96 int sc_mode, sc_arch; 97 u_char sc_cmap_red[256]; 98 u_char sc_cmap_green[256]; 99 u_char sc_cmap_blue[256]; 100 int sc_put, sc_current, sc_free; 101 uint32_t sc_rop; 102 void (*sc_putchar)(void *, int, int, u_int, long); 103 kmutex_t sc_lock; 104 glyphcache sc_gc; 105 /* cursor stuff */ 106 uint8_t sc_image[128], sc_mask[128]; 107 uint8_t sc_cstate; 108 uint16_t *sc_cimg; 109 int sc_cursor_x, sc_cursor_y, sc_hot_x, sc_hot_y; 110 uint16_t sc_cmap[3]; 111 }; 112 113 static int gffb_match(device_t, cfdata_t, void *); 114 static void gffb_attach(device_t, device_t, void *); 115 116 CFATTACH_DECL_NEW(gffb, sizeof(struct gffb_softc), 117 gffb_match, gffb_attach, NULL, NULL); 118 119 static int gffb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 120 static paddr_t gffb_mmap(void *, void *, off_t, int); 121 static void gffb_init_screen(void *, struct vcons_screen *, int, long *); 122 123 static int gffb_putcmap(struct gffb_softc *, struct wsdisplay_cmap *); 124 static int gffb_getcmap(struct gffb_softc *, struct wsdisplay_cmap *); 125 static void gffb_restore_palette(struct gffb_softc *); 126 static int gffb_putpalreg(struct gffb_softc *, uint8_t, uint8_t, 127 uint8_t, uint8_t); 128 static void gffb_setvideo(struct gffb_softc *, int); 129 static int gffb_get_backlight(struct gffb_softc *); 130 static void gffb_set_backlight(struct gffb_softc *, int); 131 static void gffb_brightness_up(device_t); 132 static void gffb_brightness_down(device_t); 133 134 static void gffb_init(struct gffb_softc *); 135 136 static void gffb_make_room(struct gffb_softc *, int); 137 static void gffb_sync(struct gffb_softc *); 138 139 static void gffb_rectfill(struct gffb_softc *, int, int, int, int, 140 uint32_t); 141 static void gffb_rectfill_a(void *, int, int, int, int, long); 142 static void gffb_bitblt(void *, int, int, int, int, int, int, int); 143 static void gffb_rop(struct gffb_softc *, int); 144 145 static int gffb_set_cursor(struct gffb_softc *, struct wsdisplay_cursor *); 146 static int gffb_set_curpos(struct gffb_softc *, struct wsdisplay_curpos *); 147 148 static void gffb_cursor(void *, int, int, int); 149 static void gffb_putchar(void *, int, int, u_int, long); 150 static void gffb_putchar_mono(void *, int, int, u_int, long); 151 static void gffb_copycols(void *, int, int, int, int); 152 static void gffb_erasecols(void *, int, int, int, long); 153 static void gffb_copyrows(void *, int, int, int); 154 static void gffb_eraserows(void *, int, int, long); 155 static int gffb_allocattr(void *, int, int, int, long *); 156 157 #define GFFB_READ_4(o) bus_space_read_stream_4(sc->sc_memt, sc->sc_regh, (o)) 158 #define GFFB_READ_1(o) bus_space_read_1(sc->sc_memt, sc->sc_regh, (o)) 159 #define GFFB_WRITE_4(o, v) bus_space_write_stream_4(sc->sc_memt, sc->sc_regh, (o), (v)) 160 #define GFFB_WRITE_1(o, v) bus_space_write_1(sc->sc_memt, sc->sc_regh, (o), (v)) 161 162 struct wsdisplay_accessops gffb_accessops = { 163 gffb_ioctl, 164 gffb_mmap, 165 NULL, /* alloc_screen */ 166 NULL, /* free_screen */ 167 NULL, /* show_screen */ 168 NULL, /* load_font */ 169 NULL, /* pollc */ 170 NULL /* scroll */ 171 }; 172 173 static void 174 gffb_write_crtc(struct gffb_softc *sc, int head, uint8_t reg, uint8_t val) 175 { 176 if (head == 0) { 177 GFFB_WRITE_1(GFFB_PCIO0 + 0x3d4, reg); 178 GFFB_WRITE_1(GFFB_PCIO0 + 0x3d5, val); 179 } else { 180 GFFB_WRITE_1(GFFB_PCIO1 + 0x3d4, reg); 181 GFFB_WRITE_1(GFFB_PCIO1 + 0x3d5, val); 182 } 183 } 184 185 static uint8_t 186 gffb_read_crtc(struct gffb_softc *sc, int head, uint8_t reg) 187 { 188 if (head == 0) { 189 GFFB_WRITE_1(GFFB_PCIO0 + 0x3d4, reg); 190 return GFFB_READ_1(GFFB_PCIO0 + 0x3d5); 191 } else { 192 GFFB_WRITE_1(GFFB_PCIO1 + 0x3d4, reg); 193 return GFFB_READ_1(GFFB_PCIO1 + 0x3d5); 194 } 195 } 196 197 static int 198 gffb_match(device_t parent, cfdata_t match, void *aux) 199 { 200 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 201 202 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) 203 return 0; 204 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NVIDIA) 205 return 0; 206 207 /* only cards tested on so far - likely needs a list */ 208 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GEFORCE2MX) 209 return 100; 210 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GEFORCE_6800U) 211 return 100; 212 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GF_FXGO5200) 213 return 100; 214 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GF_FX5200U) 215 return 100; 216 return (0); 217 } 218 219 static void 220 gffb_attach(device_t parent, device_t self, void *aux) 221 { 222 struct gffb_softc *sc = device_private(self); 223 struct pci_attach_args *pa = aux; 224 struct rasops_info *ri; 225 bus_space_tag_t tag; 226 struct wsemuldisplaydev_attach_args aa; 227 prop_dictionary_t dict; 228 unsigned long defattr; 229 pcireg_t reg; 230 bool is_console = FALSE; 231 uint32_t addr; 232 int i, j, f; 233 uint8_t cmap[768]; 234 235 sc->sc_pc = pa->pa_pc; 236 sc->sc_pcitag = pa->pa_tag; 237 sc->sc_memt = pa->pa_memt; 238 sc->sc_iot = pa->pa_iot; 239 sc->sc_dev = self; 240 241 sc->sc_mobile = 0; 242 sc->sc_video = 0; 243 244 /* first, see what kind of chip we've got */ 245 reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PCI_ID_REG); 246 switch (PCI_PRODUCT(reg)) { 247 case PCI_PRODUCT_NVIDIA_GEFORCE2MX: 248 sc->sc_accel = true; 249 sc->sc_arch = 10; 250 break; 251 case PCI_PRODUCT_NVIDIA_GEFORCE_6800U: 252 sc->sc_accel = false; 253 sc->sc_arch = 40; 254 break; 255 case PCI_PRODUCT_NVIDIA_GF_FXGO5200: 256 sc->sc_mobile = 1; 257 /* FALLTHROUGH */ 258 case PCI_PRODUCT_NVIDIA_GF_FX5200U: 259 sc->sc_accel = true; 260 sc->sc_arch = 30; 261 break; 262 default: 263 sc->sc_accel = false; 264 sc->sc_arch = 0; 265 } 266 267 pci_aprint_devinfo(pa, NULL); 268 DPRINTF("%s accel %d arch %d\n", __func__, sc->sc_accel, sc->sc_arch); 269 /* fill in parameters from properties */ 270 dict = device_properties(self); 271 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) { 272 aprint_error("%s: no width property\n", device_xname(self)); 273 return; 274 } 275 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) { 276 aprint_error("%s: no height property\n", device_xname(self)); 277 return; 278 } 279 280 #ifdef GLYPHCACHE_DEBUG 281 /* leave some visible VRAM unused so we can see the glyph cache */ 282 sc->sc_height -= 300; 283 #endif 284 285 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) { 286 aprint_error("%s: no depth property\n", device_xname(self)); 287 return; 288 } 289 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) { 290 aprint_error("%s: no linebytes property\n", 291 device_xname(self)); 292 return; 293 } 294 295 /* 296 * we need this for the unaccelerated case, aka nv40 297 */ 298 sc->sc_fboffset = 0; 299 if (prop_dictionary_get_uint32(dict, "address", &addr)) { 300 sc->sc_fboffset = addr & 0x000fffff; /* XXX */ 301 } 302 DPRINTF("%s: fboffset %8x\n", __func__, sc->sc_fboffset); 303 prop_dictionary_get_bool(dict, "is_console", &is_console); 304 305 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0, 306 &tag, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 307 aprint_error("%s: failed to map registers.\n", 308 device_xname(sc->sc_dev)); 309 } 310 /* 311 * first thing we need to make sure register access uses host byte order 312 * so we can recycle as much of xf86-video-nv as possible 313 */ 314 #if BYTE_ORDER == BIG_ENDIAN 315 uint32_t mreg = GFFB_READ_4(GFFB_PMC + 4); 316 if ((mreg & 0x01000001) == 0) { 317 GFFB_WRITE_4(GFFB_PMC + 4, 0x01000001); 318 } 319 #endif 320 sc->sc_vramsize = GFFB_READ_4(GFFB_VRAM) & 0xfff00000; 321 322 /* don't map more VRAM than we actually have */ 323 if (pci_mapreg_info(sc->sc_pc, sc->sc_pcitag, 324 0x14, PCI_MAPREG_TYPE_MEM, &sc->sc_fb, &sc->sc_fbsize, &f)) { 325 aprint_error("%s: can't find the framebuffer?!\n", 326 device_xname(sc->sc_dev)); 327 } 328 if (sc->sc_vramsize == 0) sc->sc_vramsize = sc->sc_fbsize; 329 330 /* don't map (much) more than we actually need */ 331 if (bus_space_map(sc->sc_memt, sc->sc_fb, 0x1000000, 332 BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR, 333 &sc->sc_fbh)) { 334 aprint_error("%s: failed to map the framebuffer.\n", 335 device_xname(sc->sc_dev)); 336 } 337 sc->sc_fbaddr = bus_space_vaddr(tag, sc->sc_fbh); 338 339 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self), 340 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb); 341 aprint_normal_dev(sc->sc_dev, "%d MB video memory\n", 342 (int)(sc->sc_vramsize >> 20)); 343 344 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 345 "default", 346 0, 0, 347 NULL, 348 8, 16, 349 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 350 WSSCREEN_RESIZE, 351 NULL 352 }; 353 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 354 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 355 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 356 sc->sc_locked = 0; 357 358 #ifdef GFFB_DEBUG 359 printf("put: %08x\n", GFFB_READ_4(GFFB_FIFO_PUT)); 360 printf("get: %08x\n", GFFB_READ_4(GFFB_FIFO_GET)); 361 #endif 362 363 /* 364 * we don't have hardware synchronization so we need a lock to serialize 365 * access to the DMA buffer between normal and kernel output 366 * actually it might be enough to use atomic ops on sc_current, sc_free 367 * etc. but for now we'll play it safe 368 * XXX we will probably deadlock if we take an interrupt while sc_lock 369 * is held and then try to printf() 370 */ 371 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 372 373 /* init engine here */ 374 gffb_init(sc); 375 gffb_setvideo(sc, 1); 376 377 if (sc->sc_mobile) { 378 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP, 379 gffb_brightness_up, TRUE); 380 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN, 381 gffb_brightness_down, TRUE); 382 } 383 384 #ifdef GFFB_DEBUG 385 printf("put: %08x\n", GFFB_READ_4(GFFB_FIFO_PUT)); 386 printf("get: %08x\n", GFFB_READ_4(GFFB_FIFO_GET)); 387 #endif 388 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 389 &gffb_accessops); 390 sc->vd.init_screen = gffb_init_screen; 391 392 393 ri = &sc->sc_console_screen.scr_ri; 394 395 if (sc->sc_accel) { 396 sc->sc_gc.gc_bitblt = gffb_bitblt; 397 sc->sc_gc.gc_rectfill = gffb_rectfill_a; 398 sc->sc_gc.gc_blitcookie = sc; 399 sc->sc_gc.gc_rop = 0xcc; 400 sc->vd.show_screen_cookie = &sc->sc_gc; 401 sc->vd.show_screen_cb = glyphcache_adapt; 402 } 403 404 if (is_console) { 405 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 406 &defattr); 407 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 408 409 if (sc->sc_accel) { 410 gffb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 411 ri->ri_devcmap[(defattr >> 16) & 0xf]); 412 } else { 413 memset(sc->sc_fbaddr + sc->sc_fboffset, 414 ri->ri_devcmap[(defattr >> 16) & 0xf], 415 sc->sc_stride * sc->sc_height); 416 } 417 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 418 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 419 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 420 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 421 422 if (sc->sc_accel) 423 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 424 (0x800000 / sc->sc_stride) - sc->sc_height - 5, 425 sc->sc_width, 426 ri->ri_font->fontwidth, 427 ri->ri_font->fontheight, 428 defattr); 429 430 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 431 defattr); 432 vcons_replay_msgbuf(&sc->sc_console_screen); 433 } else { 434 /* 435 * since we're not the console we can postpone the rest 436 * until someone actually allocates a screen for us 437 */ 438 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 439 /* do some minimal setup to avoid weirdnesses later */ 440 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 441 &defattr); 442 } else 443 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 444 445 if (sc->sc_accel) 446 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 447 (0x800000 / sc->sc_stride) - sc->sc_height - 5, 448 sc->sc_width, 449 ri->ri_font->fontwidth, 450 ri->ri_font->fontheight, 451 defattr); 452 } 453 454 j = 0; 455 rasops_get_cmap(ri, cmap, sizeof(cmap)); 456 for (i = 0; i < 256; i++) { 457 sc->sc_cmap_red[i] = cmap[j]; 458 sc->sc_cmap_green[i] = cmap[j + 1]; 459 sc->sc_cmap_blue[i] = cmap[j + 2]; 460 gffb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 461 j += 3; 462 } 463 464 /* no suspend/resume support yet */ 465 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 466 aprint_error_dev(sc->sc_dev, 467 "couldn't establish power handler\n"); 468 469 aa.console = is_console; 470 aa.scrdata = &sc->sc_screenlist; 471 aa.accessops = &gffb_accessops; 472 aa.accesscookie = &sc->vd; 473 474 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 475 } 476 477 static int 478 gffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 479 { 480 struct vcons_data *vd = v; 481 struct gffb_softc *sc = vd->cookie; 482 struct wsdisplay_fbinfo *wdf; 483 struct vcons_screen *ms = vd->active; 484 struct wsdisplay_param *param; 485 486 switch (cmd) { 487 case WSDISPLAYIO_GTYPE: 488 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 489 return 0; 490 491 /* PCI config read/write passthrough. */ 492 case PCI_IOC_CFGREAD: 493 case PCI_IOC_CFGWRITE: 494 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 495 cmd, data, flag, l); 496 497 case WSDISPLAYIO_GET_BUSID: 498 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 499 sc->sc_pcitag, data); 500 501 case WSDISPLAYIO_GINFO: 502 if (ms == NULL) 503 return ENODEV; 504 wdf = (void *)data; 505 wdf->height = ms->scr_ri.ri_height; 506 wdf->width = ms->scr_ri.ri_width; 507 wdf->depth = ms->scr_ri.ri_depth; 508 wdf->cmsize = 256; 509 return 0; 510 511 case WSDISPLAYIO_GETCMAP: 512 return gffb_getcmap(sc, 513 (struct wsdisplay_cmap *)data); 514 515 case WSDISPLAYIO_PUTCMAP: 516 return gffb_putcmap(sc, 517 (struct wsdisplay_cmap *)data); 518 519 case WSDISPLAYIO_LINEBYTES: 520 *(u_int *)data = sc->sc_stride; 521 return 0; 522 523 case WSDISPLAYIO_SMODE: { 524 int new_mode = *(int*)data; 525 if (new_mode != sc->sc_mode) { 526 sc->sc_mode = new_mode; 527 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 528 gffb_init(sc); 529 gffb_restore_palette(sc); 530 if (sc->sc_accel) { 531 glyphcache_wipe(&sc->sc_gc); 532 gffb_rectfill(sc, 0, 0, sc->sc_width, 533 sc->sc_height, ms->scr_ri.ri_devcmap[ 534 (ms->scr_defattr >> 16) & 0xf]); 535 } else { 536 memset(sc->sc_fbaddr + sc->sc_fboffset, 537 ms->scr_ri.ri_devcmap[ 538 (ms->scr_defattr >> 16) & 0xf], 539 sc->sc_stride * sc->sc_height); 540 } 541 vcons_redraw_screen(ms); 542 } 543 } 544 } 545 return 0; 546 547 case WSDISPLAYIO_GET_EDID: { 548 struct wsdisplayio_edid_info *d = data; 549 return wsdisplayio_get_edid(sc->sc_dev, d); 550 } 551 552 case WSDISPLAYIO_GET_FBINFO: { 553 struct wsdisplayio_fbinfo *fbi = data; 554 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 555 } 556 557 case WSDISPLAYIO_GETPARAM: 558 param = (struct wsdisplay_param *)data; 559 if (sc->sc_mobile == 0) 560 return EPASSTHROUGH; 561 switch (param->param) { 562 563 case WSDISPLAYIO_PARAM_BRIGHTNESS: 564 param->min = 0; 565 param->max = 255; 566 param->curval = sc->sc_bl_level; 567 return 0; 568 569 case WSDISPLAYIO_PARAM_BACKLIGHT: 570 param->min = 0; 571 param->max = 1; 572 param->curval = sc->sc_video; 573 return 0; 574 } 575 return EPASSTHROUGH; 576 577 case WSDISPLAYIO_SETPARAM: 578 param = (struct wsdisplay_param *)data; 579 if (sc->sc_mobile == 0) 580 return EPASSTHROUGH; 581 switch (param->param) { 582 583 case WSDISPLAYIO_PARAM_BRIGHTNESS: 584 gffb_set_backlight(sc, param->curval); 585 return 0; 586 587 case WSDISPLAYIO_PARAM_BACKLIGHT: 588 gffb_setvideo(sc, param->curval); 589 return 0; 590 } 591 return EPASSTHROUGH; 592 593 case WSDISPLAYIO_GVIDEO: 594 if (sc->sc_video) 595 *(int *)data = WSDISPLAYIO_VIDEO_ON; 596 else 597 *(int *)data = WSDISPLAYIO_VIDEO_OFF; 598 return 0; 599 600 case WSDISPLAYIO_SVIDEO: 601 gffb_setvideo(sc, *(int *)data == WSDISPLAYIO_VIDEO_ON); 602 return 0; 603 604 case WSDISPLAYIO_GCURMAX: 605 ((struct wsdisplay_curpos *)data)->x = 32; 606 ((struct wsdisplay_curpos *)data)->y = 32; 607 return 0; 608 609 case WSDISPLAYIO_SCURSOR: 610 return gffb_set_cursor(sc, (struct wsdisplay_cursor *)data); 611 612 case WSDISPLAYIO_GCURSOR: 613 return EPASSTHROUGH; 614 615 case WSDISPLAYIO_GCURPOS: 616 ((struct wsdisplay_curpos *)data)->x = sc->sc_cursor_x; 617 ((struct wsdisplay_curpos *)data)->y = sc->sc_cursor_y; 618 return 0; 619 620 case WSDISPLAYIO_SCURPOS: 621 return gffb_set_curpos(sc, (struct wsdisplay_curpos *)data); 622 623 } 624 return EPASSTHROUGH; 625 } 626 627 static paddr_t 628 gffb_mmap(void *v, void *vs, off_t offset, int prot) 629 { 630 struct vcons_data *vd = v; 631 struct gffb_softc *sc = vd->cookie; 632 paddr_t pa; 633 634 /* 'regular' framebuffer mmap()ing */ 635 if (offset < sc->sc_vramsize) { 636 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset + 0x2000, 637 0, prot, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 638 return pa; 639 } 640 641 /* 642 * restrict all other mappings to processes with superuser privileges 643 * or the kernel itself 644 */ 645 if (kauth_authorize_machdep(kauth_cred_get(), 646 KAUTH_MACHDEP_UNMANAGEDMEM, 647 NULL, NULL, NULL, NULL) != 0) { 648 aprint_normal("%s: mmap() rejected.\n", 649 device_xname(sc->sc_dev)); 650 return -1; 651 } 652 653 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 654 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 655 BUS_SPACE_MAP_LINEAR); 656 return pa; 657 } 658 659 if ((offset >= sc->sc_reg) && 660 (offset < (sc->sc_reg + sc->sc_regsize))) { 661 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 662 BUS_SPACE_MAP_LINEAR); 663 return pa; 664 } 665 666 #ifdef PCI_MAGIC_IO_RANGE 667 /* allow mapping of IO space */ 668 if ((offset >= PCI_MAGIC_IO_RANGE) && 669 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) { 670 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE, 671 0, prot, BUS_SPACE_MAP_LINEAR); 672 return pa; 673 } 674 #endif 675 676 return -1; 677 } 678 679 static void 680 gffb_init_screen(void *cookie, struct vcons_screen *scr, 681 int existing, long *defattr) 682 { 683 struct gffb_softc *sc = cookie; 684 struct rasops_info *ri = &scr->scr_ri; 685 686 ri->ri_depth = sc->sc_depth; 687 ri->ri_width = sc->sc_width; 688 ri->ri_height = sc->sc_height; 689 ri->ri_stride = sc->sc_stride; 690 if (sc->sc_depth == 8) 691 ri->ri_bits = sc->sc_fbaddr + sc->sc_fboffset; 692 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 693 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA; 694 695 rasops_init(ri, 0, 0); 696 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_RESIZE | WSSCREEN_UNDERLINE | 697 WSSCREEN_HILIT; 698 scr->scr_flags |= VCONS_LOADFONT; 699 700 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 701 sc->sc_width / ri->ri_font->fontwidth); 702 703 ri->ri_hw = scr; 704 705 if (sc->sc_accel) { 706 ri->ri_ops.copyrows = gffb_copyrows; 707 ri->ri_ops.copycols = gffb_copycols; 708 ri->ri_ops.eraserows = gffb_eraserows; 709 ri->ri_ops.erasecols = gffb_erasecols; 710 ri->ri_ops.cursor = gffb_cursor; 711 ri->ri_ops.allocattr = gffb_allocattr; 712 if (FONT_IS_ALPHA(ri->ri_font)) { 713 sc->sc_putchar = ri->ri_ops.putchar; 714 ri->ri_ops.putchar = gffb_putchar; 715 } else { 716 ri->ri_ops.putchar = gffb_putchar_mono; 717 } 718 } else { 719 scr->scr_flags |= VCONS_DONT_READ; 720 } 721 } 722 723 static int 724 gffb_putcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm) 725 { 726 u_char *r, *g, *b; 727 u_int index = cm->index; 728 u_int count = cm->count; 729 int i, error; 730 u_char rbuf[256], gbuf[256], bbuf[256]; 731 732 #ifdef GFFB_DEBUG 733 aprint_debug("putcmap: %d %d\n",index, count); 734 #endif 735 if (cm->index >= 256 || cm->count > 256 || 736 (cm->index + cm->count) > 256) 737 return EINVAL; 738 error = copyin(cm->red, &rbuf[index], count); 739 if (error) 740 return error; 741 error = copyin(cm->green, &gbuf[index], count); 742 if (error) 743 return error; 744 error = copyin(cm->blue, &bbuf[index], count); 745 if (error) 746 return error; 747 748 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 749 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 750 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 751 752 r = &sc->sc_cmap_red[index]; 753 g = &sc->sc_cmap_green[index]; 754 b = &sc->sc_cmap_blue[index]; 755 756 for (i = 0; i < count; i++) { 757 gffb_putpalreg(sc, index, *r, *g, *b); 758 index++; 759 r++, g++, b++; 760 } 761 return 0; 762 } 763 764 static int 765 gffb_getcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm) 766 { 767 u_int index = cm->index; 768 u_int count = cm->count; 769 int error; 770 771 if (index >= 255 || count > 256 || index + count > 256) 772 return EINVAL; 773 774 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 775 if (error) 776 return error; 777 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 778 if (error) 779 return error; 780 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 781 if (error) 782 return error; 783 784 return 0; 785 } 786 787 static void 788 gffb_restore_palette(struct gffb_softc *sc) 789 { 790 int i; 791 792 for (i = 0; i < (1 << sc->sc_depth); i++) { 793 gffb_putpalreg(sc, i, sc->sc_cmap_red[i], 794 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]); 795 } 796 } 797 798 static int 799 gffb_putpalreg(struct gffb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 800 uint8_t b) 801 { 802 /* port 0 */ 803 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_IW, idx); 804 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_D, r); 805 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_D, g); 806 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_D, b); 807 808 /* port 1 */ 809 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_IW, idx); 810 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_D, r); 811 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_D, g); 812 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_D, b); 813 814 return 0; 815 } 816 817 static void 818 gffb_setvideo(struct gffb_softc *sc, int on) 819 { 820 uint8_t reg0, reg1; 821 822 if (sc->sc_video == on) 823 return; 824 825 reg0 = gffb_read_crtc(sc, 0, 0x1a) & 0x3f; 826 reg1 = gffb_read_crtc(sc, 1, 0x1a) & 0x3f; 827 828 if (!on) { 829 reg0 |= 0xc0; 830 reg1 |= 0xc0; 831 } 832 833 834 gffb_write_crtc(sc, 0, 0x1a, reg0); 835 gffb_write_crtc(sc, 1, 0x1a, reg1); 836 837 sc->sc_video = on; 838 839 if(sc->sc_mobile) { 840 gffb_set_backlight(sc, sc->sc_bl_level); 841 } 842 } 843 844 static void 845 gffb_dma_kickoff(struct gffb_softc *sc) 846 { 847 volatile uint32_t junk; 848 if (sc->sc_current != sc->sc_put) { 849 sc->sc_put = sc->sc_current; 850 bus_space_barrier(sc->sc_memt, sc->sc_fbh, 0, 0x1000000, 851 BUS_SPACE_BARRIER_WRITE); 852 junk = *sc->sc_fbaddr; 853 __USE(junk); 854 GFFB_WRITE_4(GFFB_FIFO_PUT, sc->sc_put); 855 bus_space_barrier(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT, 4, 856 BUS_SPACE_BARRIER_WRITE); 857 } 858 } 859 860 static void 861 gffb_dmanext(struct gffb_softc *sc, uint32_t data) 862 { 863 bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, sc->sc_current, data); 864 sc->sc_current += 4; 865 } 866 867 static void 868 gffb_dmastart(struct gffb_softc *sc, uint32_t tag, int size) 869 { 870 if(sc->sc_free <= (size << 2)) 871 gffb_make_room(sc, size); 872 gffb_dmanext(sc, ((size) << 18) | (tag)); 873 sc->sc_free -= ((size + 1) << 2); 874 } 875 876 /* 877 * from xf86_video_nv/nv_xaa.c: 878 * There is a HW race condition with videoram command buffers. 879 * You can't jump to the location of your put offset. We write put 880 * at the jump offset + SKIPS dwords with noop padding in between 881 * to solve this problem 882 */ 883 884 #define SKIPS 8 885 886 static void 887 gffb_make_room(struct gffb_softc *sc, int size) 888 { 889 uint32_t get; 890 891 size = (size + 1) << 2; /* slots -> offset */ 892 893 while (sc->sc_free < size) { 894 get = GFFB_READ_4(GFFB_FIFO_GET); 895 896 if (sc->sc_put >= get) { 897 sc->sc_free = 0x2000 - sc->sc_current; 898 if (sc->sc_free < size) { 899 gffb_dmanext(sc, 0x20000000); 900 if(get <= (SKIPS << 2)) { 901 if (sc->sc_put <= (SKIPS << 2)) { 902 /* corner case - will be idle */ 903 GFFB_WRITE_4(GFFB_FIFO_PUT, 904 (SKIPS + 1) << 2); 905 } 906 do { 907 get =GFFB_READ_4(GFFB_FIFO_GET); 908 } while (get <= (SKIPS << 2)); 909 } 910 GFFB_WRITE_4(GFFB_FIFO_PUT, SKIPS << 2); 911 sc->sc_current = sc->sc_put = (SKIPS << 2); 912 sc->sc_free = get - ((SKIPS + 1) << 2); 913 } 914 } else 915 sc->sc_free = get - sc->sc_current - 4; 916 } 917 } 918 919 static void 920 gffb_sync(struct gffb_softc *sc) 921 { 922 int bail; 923 int i; 924 925 /* 926 * if there are commands in the buffer make sure the chip is actually 927 * trying to run them 928 */ 929 gffb_dma_kickoff(sc); 930 931 /* now wait for the command buffer to drain... */ 932 bail = 100000000; 933 while ((GFFB_READ_4(GFFB_FIFO_GET) != sc->sc_put) && (bail > 0)) { 934 bail--; 935 } 936 if (bail == 0) { 937 printf("FIFO isn't moving\n"); 938 goto crap; 939 } 940 941 /* ... and for the engine to go idle */ 942 bail = 100000000; 943 while((GFFB_READ_4(GFFB_BUSY) != 0) && (bail > 0)) { 944 bail--; 945 } 946 if (bail == 0) goto crap; 947 return; 948 crap: 949 /* if we time out fill the buffer with NOPs and cross fingers */ 950 DPRINTF("GET %08x\n", GFFB_READ_4(GFFB_FIFO_GET)); 951 sc->sc_put = 0; 952 sc->sc_current = 0; 953 for (i = 0; i < 0x2000; i += 4) 954 bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, i, 0); 955 aprint_error_dev(sc->sc_dev, "DMA lockup\n"); 956 } 957 958 static int 959 gffb_get_backlight(struct gffb_softc *sc) 960 { 961 uint32_t pmc; 962 pmc = (GFFB_READ_4(GFFB_PMC + 0x10F0) & 0x7FFF0000) >> 16; 963 pmc = (pmc - GFFB_BL_MIN) * 256 / (GFFB_BL_MAX - GFFB_BL_MIN); 964 return pmc; 965 } 966 967 static void 968 gffb_set_backlight(struct gffb_softc *sc, int level) 969 { 970 uint32_t pmc = GFFB_READ_4(GFFB_PMC + 0x10F0) & 0x0000ffff; 971 uint32_t bl, pcrt; 972 973 if (level < 0) level = 0; 974 if (level > 255) level = 255; 975 976 pcrt = GFFB_READ_4(GFFB_CRTC0 + 0x081C) & 0xFFFFFFFC; 977 bl = (level * (GFFB_BL_MAX - GFFB_BL_MIN) / 256) + GFFB_BL_MIN; 978 pmc |= bl << 16; 979 if (sc->sc_video && (level > 0)) { 980 pcrt |= 0x1; 981 pmc |= 0x80000000; 982 } 983 GFFB_WRITE_4(GFFB_PMC + 0x10F0, pmc); 984 GFFB_WRITE_4(GFFB_CRTC0 + 0x081C, pcrt); 985 DPRINTF("%s: %d %08x %08x\n", __func__, level, pmc, pcrt); 986 sc->sc_bl_level = level; 987 } 988 989 static void 990 gffb_brightness_up(device_t dev) 991 { 992 struct gffb_softc *sc = device_private(dev); 993 994 sc->sc_video = 1; 995 gffb_set_backlight(sc, sc->sc_bl_level + 8); 996 } 997 998 static void 999 gffb_brightness_down(device_t dev) 1000 { 1001 struct gffb_softc *sc = device_private(dev); 1002 1003 gffb_set_backlight(sc, sc->sc_bl_level - 8); 1004 } 1005 1006 void 1007 gffb_init(struct gffb_softc *sc) 1008 { 1009 int i; 1010 uint32_t foo; 1011 1012 if (!sc->sc_accel) return; 1013 DPRINTF("%s offset %08x %08x\n", __func__, 1014 GFFB_READ_4(GFFB_CRTC0 + GFFB_DISPLAYSTART), 1015 GFFB_READ_4(GFFB_CRTC1 + GFFB_DISPLAYSTART)); 1016 1017 sc->sc_fboffset = 0x2000; 1018 1019 if (sc->sc_mobile) { 1020 sc->sc_bl_level = gffb_get_backlight(sc); 1021 } 1022 1023 /* init display start */ 1024 GFFB_WRITE_4(GFFB_CRTC0 + GFFB_DISPLAYSTART, sc->sc_fboffset); 1025 GFFB_WRITE_4(GFFB_CRTC1 + GFFB_DISPLAYSTART, sc->sc_fboffset); 1026 1027 /* make sure we do 8bit per channel */ 1028 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_MASK, 0xff); 1029 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_MASK, 0xff); 1030 1031 /* DMA stuff. A whole lot of magic number voodoo from xf86-video-nv */ 1032 GFFB_WRITE_4(GFFB_PMC + 0x140, 0); 1033 GFFB_WRITE_4(GFFB_PMC + 0x200, 0xffff00ff); 1034 GFFB_WRITE_4(GFFB_PMC + 0x200, 0xffffffff); 1035 GFFB_WRITE_4(GFFB_PTIMER + 0x800, 8); 1036 GFFB_WRITE_4(GFFB_PTIMER + 0x840, 3); 1037 GFFB_WRITE_4(GFFB_PTIMER + 0x500, 0); 1038 GFFB_WRITE_4(GFFB_PTIMER + 0x400, 0xffffffff); 1039 for (i = 0; i < 8; i++) { 1040 GFFB_WRITE_4(GFFB_PFB + 0x0240 + (i * 0x10), 0); 1041 GFFB_WRITE_4(GFFB_PFB + 0x0244 + (i * 0x10), 1042 sc->sc_vramsize - 1); 1043 } 1044 1045 GFFB_WRITE_4(GFFB_PRAMIN, 0x80000010); 1046 GFFB_WRITE_4(GFFB_PRAMIN + 0x04, 0x80011201); 1047 GFFB_WRITE_4(GFFB_PRAMIN + 0x08, 0x80000011); 1048 GFFB_WRITE_4(GFFB_PRAMIN + 0x0c, 0x80011202); 1049 GFFB_WRITE_4(GFFB_PRAMIN + 0x10, 0x80000012); 1050 GFFB_WRITE_4(GFFB_PRAMIN + 0x14, 0x80011203); 1051 GFFB_WRITE_4(GFFB_PRAMIN + 0x18, 0x80000013); 1052 GFFB_WRITE_4(GFFB_PRAMIN + 0x1c, 0x80011204); 1053 GFFB_WRITE_4(GFFB_PRAMIN + 0x20, 0x80000014); 1054 GFFB_WRITE_4(GFFB_PRAMIN + 0x24, 0x80011205); 1055 GFFB_WRITE_4(GFFB_PRAMIN + 0x28, 0x80000015); 1056 GFFB_WRITE_4(GFFB_PRAMIN + 0x2c, 0x80011206); 1057 GFFB_WRITE_4(GFFB_PRAMIN + 0x30, 0x80000016); 1058 GFFB_WRITE_4(GFFB_PRAMIN + 0x34, 0x80011207); 1059 GFFB_WRITE_4(GFFB_PRAMIN + 0x38, 0x80000017); 1060 GFFB_WRITE_4(GFFB_PRAMIN + 0x3c, 0x80011208); 1061 GFFB_WRITE_4(GFFB_PRAMIN + 0x2000, 0x00003000); 1062 GFFB_WRITE_4(GFFB_PRAMIN + 0x2004, sc->sc_vramsize - 1); 1063 GFFB_WRITE_4(GFFB_PRAMIN + 0x2008, 0x00000002); 1064 GFFB_WRITE_4(GFFB_PRAMIN + 0x200c, 0x00000002); 1065 GFFB_WRITE_4(GFFB_PRAMIN + 0x2010, 0x01008062); /* nv10+ */ 1066 GFFB_WRITE_4(GFFB_PRAMIN + 0x2014, 0); 1067 GFFB_WRITE_4(GFFB_PRAMIN + 0x2018, 0x12001200); 1068 GFFB_WRITE_4(GFFB_PRAMIN + 0x201c, 0); 1069 GFFB_WRITE_4(GFFB_PRAMIN + 0x2020, 0x01008043); 1070 GFFB_WRITE_4(GFFB_PRAMIN + 0x2024, 0); 1071 GFFB_WRITE_4(GFFB_PRAMIN + 0x2028, 0); 1072 GFFB_WRITE_4(GFFB_PRAMIN + 0x202c, 0); 1073 GFFB_WRITE_4(GFFB_PRAMIN + 0x2030, 0x01008044); 1074 GFFB_WRITE_4(GFFB_PRAMIN + 0x2034, 0x00000002); 1075 GFFB_WRITE_4(GFFB_PRAMIN + 0x2038, 0); 1076 GFFB_WRITE_4(GFFB_PRAMIN + 0x203c, 0); 1077 GFFB_WRITE_4(GFFB_PRAMIN + 0x2040, 0x01008019); 1078 GFFB_WRITE_4(GFFB_PRAMIN + 0x2044, 0); 1079 GFFB_WRITE_4(GFFB_PRAMIN + 0x2048, 0); 1080 GFFB_WRITE_4(GFFB_PRAMIN + 0x204c, 0); 1081 GFFB_WRITE_4(GFFB_PRAMIN + 0x2050, 0x0100a05c); 1082 GFFB_WRITE_4(GFFB_PRAMIN + 0x2054, 0); 1083 GFFB_WRITE_4(GFFB_PRAMIN + 0x2058, 0); 1084 GFFB_WRITE_4(GFFB_PRAMIN + 0x205c, 0); 1085 /* XXX 0x0100805f if !WaitVSyncPossible */ 1086 GFFB_WRITE_4(GFFB_PRAMIN + 0x2060, 0x0100805f); 1087 GFFB_WRITE_4(GFFB_PRAMIN + 0x2064, 0); 1088 GFFB_WRITE_4(GFFB_PRAMIN + 0x2068, 0x12001200); 1089 GFFB_WRITE_4(GFFB_PRAMIN + 0x206c, 0); 1090 GFFB_WRITE_4(GFFB_PRAMIN + 0x2070, 0x0100804a); 1091 GFFB_WRITE_4(GFFB_PRAMIN + 0x2074, 0x00000002); 1092 GFFB_WRITE_4(GFFB_PRAMIN + 0x2078, 0); 1093 GFFB_WRITE_4(GFFB_PRAMIN + 0x207c, 0); 1094 GFFB_WRITE_4(GFFB_PRAMIN + 0x2080, 0x01018077); 1095 GFFB_WRITE_4(GFFB_PRAMIN + 0x2084, 0); 1096 GFFB_WRITE_4(GFFB_PRAMIN + 0x2088, 0x12001200); 1097 GFFB_WRITE_4(GFFB_PRAMIN + 0x208c, 0); 1098 GFFB_WRITE_4(GFFB_PRAMIN + 0x2090, 0x00003002); 1099 GFFB_WRITE_4(GFFB_PRAMIN + 0x2094, 0x00007fff); 1100 /* command buffer start with some flag in the lower bits */ 1101 GFFB_WRITE_4(GFFB_PRAMIN + 0x2098, sc->sc_vramsize | 0x00000002); 1102 GFFB_WRITE_4(GFFB_PRAMIN + 0x209c, 0x00000002); 1103 #if BYTE_ORDER == BIG_ENDIAN 1104 GFFB_WRITE_4(GFFB_PRAMIN + 0x2010, 0x01088062); 1105 GFFB_WRITE_4(GFFB_PRAMIN + 0x2020, 0x01088043); 1106 GFFB_WRITE_4(GFFB_PRAMIN + 0x2030, 0x01088044); 1107 GFFB_WRITE_4(GFFB_PRAMIN + 0x2040, 0x01088019); 1108 GFFB_WRITE_4(GFFB_PRAMIN + 0x2050, 0x0108a05c); 1109 GFFB_WRITE_4(GFFB_PRAMIN + 0x2060, 0x0108805f); 1110 GFFB_WRITE_4(GFFB_PRAMIN + 0x2070, 0x0108804a); 1111 GFFB_WRITE_4(GFFB_PRAMIN + 0x2080, 0x01098077); 1112 GFFB_WRITE_4(GFFB_PRAMIN + 0x2034, 0x00000001); 1113 GFFB_WRITE_4(GFFB_PRAMIN + 0x2074, 0x00000001); 1114 #endif 1115 /* PGRAPH setup */ 1116 GFFB_WRITE_4(GFFB_PGRAPH + 0x0080, 0xFFFFFFFF); 1117 GFFB_WRITE_4(GFFB_PGRAPH + 0x0080, 0x00000000); 1118 1119 GFFB_WRITE_4(GFFB_PGRAPH + 0x0140, 0x00000000); 1120 GFFB_WRITE_4(GFFB_PGRAPH + 0x0100, 0xFFFFFFFF); 1121 GFFB_WRITE_4(GFFB_PGRAPH + 0x0144, 0x10010100); 1122 GFFB_WRITE_4(GFFB_PGRAPH + 0x0714, 0xFFFFFFFF); 1123 GFFB_WRITE_4(GFFB_PGRAPH + 0x0720, 0x00000001); 1124 /* 1125 * xf86_video_nv does this in two writes, 1126 * not sure if they can be combined 1127 */ 1128 foo = GFFB_READ_4(GFFB_PGRAPH + 0x0710); 1129 foo &= 0x0007ff00; 1130 foo |= 0x00020100; 1131 GFFB_WRITE_4(GFFB_PGRAPH + 0x0710, foo); 1132 1133 /* NV_ARCH_10 */ 1134 if(sc->sc_arch == 10) { 1135 GFFB_WRITE_4(GFFB_PGRAPH + 0x0084, 0x00118700); 1136 GFFB_WRITE_4(GFFB_PGRAPH + 0x0088, 0x24E00810); 1137 GFFB_WRITE_4(GFFB_PGRAPH + 0x008C, 0x55DE0030); 1138 1139 for(i = 0; i < 128; i += 4) { 1140 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B00 + i, 1141 GFFB_READ_4(GFFB_PFB + 0x0240 + i)); 1142 } 1143 1144 GFFB_WRITE_4(GFFB_PGRAPH + 0x640, 0); 1145 GFFB_WRITE_4(GFFB_PGRAPH + 0x644, 0); 1146 GFFB_WRITE_4(GFFB_PGRAPH + 0x684, sc->sc_vramsize - 1); 1147 GFFB_WRITE_4(GFFB_PGRAPH + 0x688, sc->sc_vramsize - 1); 1148 1149 GFFB_WRITE_4(GFFB_PGRAPH + 0x0810, 0x00000000); 1150 GFFB_WRITE_4(GFFB_PGRAPH + 0x0608, 0xFFFFFFFF); 1151 } else { 1152 /* nv30 */ 1153 GFFB_WRITE_4(GFFB_PGRAPH + 0x0084, 0x40108700); 1154 GFFB_WRITE_4(GFFB_PGRAPH + 0x0890, 0x00140000); 1155 GFFB_WRITE_4(GFFB_PGRAPH + 0x008C, 0xf00e0431); 1156 GFFB_WRITE_4(GFFB_PGRAPH + 0x0090, 0x00008000); 1157 GFFB_WRITE_4(GFFB_PGRAPH + 0x0610, 0xf04b1f36); 1158 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B80, 0x1002d888); 1159 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B88, 0x62ff007f); 1160 1161 for (i = 0; i < 128; i += 4) { 1162 GFFB_WRITE_4(GFFB_PGRAPH + 0x0900 + i, 1163 GFFB_READ_4(GFFB_PFB + 0x0240 + i)); 1164 GFFB_WRITE_4(GFFB_PGRAPH + 0x6900 + i, 1165 GFFB_READ_4(GFFB_PFB + 0x0240 + i)); 1166 } 1167 1168 GFFB_WRITE_4(GFFB_PGRAPH + 0x09A4, 1169 GFFB_READ_4(GFFB_PFB + 0x0200)); 1170 GFFB_WRITE_4(GFFB_PGRAPH + 0x09A8, 1171 GFFB_READ_4(GFFB_PFB + 0x0204)); 1172 GFFB_WRITE_4(GFFB_PGRAPH + 0x0750, 0x00EA0000); 1173 GFFB_WRITE_4(GFFB_PGRAPH + 0x0754, 1174 GFFB_READ_4(GFFB_PFB + 0x0200)); 1175 GFFB_WRITE_4(GFFB_PGRAPH + 0x0750, 0x00EA0004); 1176 GFFB_WRITE_4(GFFB_PGRAPH + 0x0754, 1177 GFFB_READ_4(GFFB_PFB + 0x0204)); 1178 1179 GFFB_WRITE_4(GFFB_PGRAPH + 0x0820, 0); 1180 GFFB_WRITE_4(GFFB_PGRAPH + 0x0824, 0); 1181 GFFB_WRITE_4(GFFB_PGRAPH + 0x0864, sc->sc_vramsize - 1); 1182 GFFB_WRITE_4(GFFB_PGRAPH + 0x0868, sc->sc_vramsize - 1); 1183 1184 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B20, 0x00000000); 1185 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B04, 0xFFFFFFFF); 1186 } 1187 1188 /* 1189 * cursor sprite setup for 32x32, RGB555 1190 * we should be able to use ARGB8888 / 64x64 but for some reason 1191 * I couldn't get that to work right ( thanks to xf86-video-nv being all 1192 * magic number voodoo ), and it's not like we need it anyway 1193 */ 1194 GFFB_WRITE_4(GFFB_CRTC0 + 0x810, 0x02000100); 1195 GFFB_WRITE_4(GFFB_CRTC1 + 0x810, 0x02000100); 1196 GFFB_WRITE_4(GFFB_RAMDAC0 + GFFB_CURPOS, 0x00800080); 1197 GFFB_WRITE_4(GFFB_RAMDAC1 + GFFB_CURPOS, 0x00000080); 1198 /* we put the cursor image at 16MB - 32KB */ 1199 int coffset = 0x00ff8000, c0, c1, c2; 1200 c0 = ((coffset >> 17) & 0x7f) | 0x80; 1201 c1 = ((coffset >> 11) << 2) & 0xfe; 1202 sc->sc_cstate = c1; 1203 c2 = coffset >> 24; 1204 gffb_write_crtc(sc, 0, 0x30, c0); 1205 gffb_write_crtc(sc, 0, 0x31, c1); 1206 gffb_write_crtc(sc, 0, 0x2f, c2); 1207 gffb_write_crtc(sc, 1, 0x30, c0); 1208 gffb_write_crtc(sc, 1, 0x31, c1); 1209 gffb_write_crtc(sc, 1, 0x2f, c2); 1210 sc->sc_cimg = (uint16_t *)(sc->sc_fbaddr + coffset); 1211 for (i = 0; i < 1024; i++) { 1212 sc->sc_cimg[i] = 0x8000 | (0x1f << 10); 1213 } 1214 sc->sc_hot_x = 0; 1215 sc->sc_hot_y = 0; 1216 1217 /* PFIFO setup */ 1218 GFFB_WRITE_4(GFFB_PGRAPH + 0x053C, 0); 1219 GFFB_WRITE_4(GFFB_PGRAPH + 0x0540, 0); 1220 GFFB_WRITE_4(GFFB_PGRAPH + 0x0544, 0x00007FFF); 1221 GFFB_WRITE_4(GFFB_PGRAPH + 0x0548, 0x00007FFF); 1222 1223 GFFB_WRITE_4(GFFB_PFIFO + 0x0500, 0); 1224 GFFB_WRITE_4(GFFB_PFIFO + 0x0504, 0x00000001); 1225 GFFB_WRITE_4(GFFB_PFIFO + 0x1200, 0); 1226 GFFB_WRITE_4(GFFB_PFIFO + 0x1250, 0); 1227 GFFB_WRITE_4(GFFB_PFIFO + 0x1204, 0x00000100); /* different on nv40 */ 1228 GFFB_WRITE_4(GFFB_PFIFO + 0x1240, 0); 1229 GFFB_WRITE_4(GFFB_PFIFO + 0x1244, 0); 1230 GFFB_WRITE_4(GFFB_PFIFO + 0x122c, 0x00001209); /* different on nv40 */ 1231 GFFB_WRITE_4(GFFB_PFIFO + 0x1000, 0); 1232 GFFB_WRITE_4(GFFB_PFIFO + 0x1050, 0); 1233 GFFB_WRITE_4(GFFB_PFIFO + 0x0210, 0x03000100); 1234 GFFB_WRITE_4(GFFB_PFIFO + 0x0214, 0x00000110); 1235 GFFB_WRITE_4(GFFB_PFIFO + 0x0218, 0x00000112); 1236 GFFB_WRITE_4(GFFB_PFIFO + 0x050c, 0x0000ffff); 1237 GFFB_WRITE_4(GFFB_PFIFO + 0x1258, 0x0000ffff); 1238 GFFB_WRITE_4(GFFB_PFIFO + 0x0140, 0); 1239 GFFB_WRITE_4(GFFB_PFIFO + 0x0100, 0xffffffff); 1240 GFFB_WRITE_4(GFFB_PFIFO + 0x1054, 0x00000001); 1241 GFFB_WRITE_4(GFFB_PFIFO + 0x1230, 0); 1242 GFFB_WRITE_4(GFFB_PFIFO + 0x1280, 0); 1243 #if BYTE_ORDER == BIG_ENDIAN 1244 GFFB_WRITE_4(GFFB_PFIFO + 0x1224, 0x800f0078); 1245 #else 1246 GFFB_WRITE_4(GFFB_PFIFO + 0x1224, 0x000f0078); 1247 #endif 1248 GFFB_WRITE_4(GFFB_PFIFO + 0x1220, 0x00000001); 1249 GFFB_WRITE_4(GFFB_PFIFO + 0x1200, 0x00000001); 1250 GFFB_WRITE_4(GFFB_PFIFO + 0x1250, 0x00000001); 1251 GFFB_WRITE_4(GFFB_PFIFO + 0x1254, 0x00000001); 1252 GFFB_WRITE_4(GFFB_PFIFO + 0x0500, 0x00000001); 1253 1254 GFFB_WRITE_4(GFFB_PMC + 0x8704, 1); 1255 GFFB_WRITE_4(GFFB_PMC + 0x8140, 0); 1256 GFFB_WRITE_4(GFFB_PMC + 0x8920, 0); 1257 GFFB_WRITE_4(GFFB_PMC + 0x8924, 0); 1258 GFFB_WRITE_4(GFFB_PMC + 0x8908, sc->sc_vramsize - 1); 1259 GFFB_WRITE_4(GFFB_PMC + 0x890C, sc->sc_vramsize - 1); 1260 GFFB_WRITE_4(GFFB_PMC + 0x1588, 0); 1261 1262 GFFB_WRITE_4(GFFB_FIFO_GET, 0); 1263 GFFB_WRITE_4(GFFB_CMDSTART, 0x00000002); 1264 sc->sc_put = 0; 1265 sc->sc_current = 0; 1266 sc->sc_free = 0x2000; 1267 1268 for(i = 0; i < SKIPS; i++) 1269 gffb_dmanext(sc, 0); 1270 1271 gffb_dmanext(sc, 0x00040000); 1272 gffb_dmanext(sc, 0x80000010); 1273 gffb_dmanext(sc, 0x00042000); 1274 gffb_dmanext(sc, 0x80000011); 1275 gffb_dmanext(sc, 0x00044000); 1276 gffb_dmanext(sc, 0x80000012); 1277 gffb_dmanext(sc, 0x00046000); 1278 gffb_dmanext(sc, 0x80000013); 1279 gffb_dmanext(sc, 0x00048000); 1280 gffb_dmanext(sc, 0x80000014); 1281 gffb_dmanext(sc, 0x0004A000); 1282 gffb_dmanext(sc, 0x80000015); 1283 gffb_dmanext(sc, 0x0004C000); 1284 gffb_dmanext(sc, 0x80000016); 1285 gffb_dmanext(sc, 0x0004E000); 1286 gffb_dmanext(sc, 0x80000017); 1287 sc->sc_free = 0x2000 - sc->sc_current; 1288 1289 gffb_dmastart(sc, SURFACE_FORMAT, 4); 1290 gffb_dmanext(sc, SURFACE_FORMAT_DEPTH8); 1291 gffb_dmanext(sc, sc->sc_stride | (sc->sc_stride << 16)); 1292 gffb_dmanext(sc, sc->sc_fboffset); /* src offset */ 1293 gffb_dmanext(sc, sc->sc_fboffset); /* dst offset */ 1294 1295 gffb_dmastart(sc, RECT_FORMAT, 1); 1296 gffb_dmanext(sc, RECT_FORMAT_DEPTH8); 1297 1298 gffb_dmastart(sc, PATTERN_FORMAT, 1); 1299 gffb_dmanext(sc, PATTERN_FORMAT_DEPTH8); 1300 1301 gffb_dmastart(sc, PATTERN_COLOR_0, 4); 1302 gffb_dmanext(sc, 0xffffffff); 1303 gffb_dmanext(sc, 0xffffffff); 1304 gffb_dmanext(sc, 0xffffffff); 1305 gffb_dmanext(sc, 0xffffffff); 1306 1307 gffb_dmastart(sc, ROP_SET, 1); 1308 gffb_dmanext(sc, 0xcc); 1309 sc->sc_rop = 0xcc; 1310 DPRINTF("put %x current %x\n", sc->sc_put, sc->sc_current); 1311 1312 gffb_dma_kickoff(sc); 1313 DPRINTF("put %x current %x\n", sc->sc_put, sc->sc_current); 1314 #ifdef GFFB_DEBUG 1315 printf("put: %08x\n", GFFB_READ_4(GFFB_FIFO_PUT)); 1316 printf("get: %08x\n", GFFB_READ_4(GFFB_FIFO_GET)); 1317 #endif 1318 gffb_sync(sc); 1319 DPRINTF("put %x current %x\n", sc->sc_put, sc->sc_current); 1320 } 1321 1322 static void 1323 gffb_rop(struct gffb_softc *sc, int rop) 1324 { 1325 if (rop == sc->sc_rop) 1326 return; 1327 sc->sc_rop = rop; 1328 gffb_dmastart(sc, ROP_SET, 1); 1329 gffb_dmanext(sc, rop); 1330 } 1331 1332 static void 1333 gffb_rectfill(struct gffb_softc *sc, int x, int y, int wi, int he, 1334 uint32_t colour) 1335 { 1336 if (!sc->sc_accel) return; 1337 mutex_enter(&sc->sc_lock); 1338 gffb_rop(sc, 0xcc); 1339 1340 gffb_dmastart(sc, RECT_SOLID_COLOR, 1); 1341 gffb_dmanext(sc, colour); 1342 1343 gffb_dmastart(sc, RECT_SOLID_RECTS(0), 2); 1344 gffb_dmanext(sc, (x << 16) | y); 1345 gffb_dmanext(sc, (wi << 16) | he); 1346 gffb_dma_kickoff(sc); 1347 mutex_exit(&sc->sc_lock); 1348 } 1349 1350 static void 1351 gffb_rectfill_a(void *cookie, int dstx, int dsty, 1352 int width, int height, long attr) 1353 { 1354 struct gffb_softc *sc = cookie; 1355 1356 gffb_rectfill(sc, dstx, dsty, width, height, 1357 sc->vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]); 1358 } 1359 1360 static void 1361 gffb_bitblt(void *cookie, int xs, int ys, int xd, int yd, 1362 int wi, int he, int rop) 1363 { 1364 struct gffb_softc *sc = cookie; 1365 1366 if (!sc->sc_accel) return; 1367 mutex_enter(&sc->sc_lock); 1368 1369 gffb_rop(sc, rop); 1370 1371 gffb_dmastart(sc, BLIT_POINT_SRC, 3); 1372 gffb_dmanext(sc, (ys << 16) | xs); 1373 gffb_dmanext(sc, (yd << 16) | xd); 1374 gffb_dmanext(sc, (he << 16) | wi); 1375 gffb_dma_kickoff(sc); 1376 mutex_exit(&sc->sc_lock); 1377 } 1378 1379 static void 1380 gffb_cursor(void *cookie, int on, int row, int col) 1381 { 1382 struct rasops_info *ri = cookie; 1383 struct vcons_screen *scr = ri->ri_hw; 1384 struct gffb_softc *sc = scr->scr_cookie; 1385 int x, y, wi, he; 1386 1387 wi = ri->ri_font->fontwidth; 1388 he = ri->ri_font->fontheight; 1389 1390 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1391 x = ri->ri_ccol * wi + ri->ri_xorigin; 1392 y = ri->ri_crow * he + ri->ri_yorigin; 1393 if (ri->ri_flg & RI_CURSOR) { 1394 gffb_bitblt(sc, x, y, x, y, wi, he, 0x33); 1395 ri->ri_flg &= ~RI_CURSOR; 1396 } 1397 ri->ri_crow = row; 1398 ri->ri_ccol = col; 1399 if (on) { 1400 x = ri->ri_ccol * wi + ri->ri_xorigin; 1401 y = ri->ri_crow * he + ri->ri_yorigin; 1402 gffb_bitblt(sc, x, y, x, y, wi, he, 0x33); 1403 ri->ri_flg |= RI_CURSOR; 1404 } 1405 } else { 1406 scr->scr_ri.ri_crow = row; 1407 scr->scr_ri.ri_ccol = col; 1408 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1409 } 1410 1411 } 1412 1413 static void 1414 gffb_putchar(void *cookie, int row, int col, u_int c, long attr) 1415 { 1416 struct rasops_info *ri = cookie; 1417 struct wsdisplay_font *font = PICK_FONT(ri, c); 1418 struct vcons_screen *scr = ri->ri_hw; 1419 struct gffb_softc *sc = scr->scr_cookie; 1420 int x, y, wi, he, rv = GC_NOPE; 1421 uint32_t bg, fg; 1422 1423 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1424 return; 1425 1426 if (!CHAR_IN_FONT(c, font)) 1427 return; 1428 1429 wi = font->fontwidth; 1430 he = font->fontheight; 1431 1432 x = ri->ri_xorigin + col * wi; 1433 y = ri->ri_yorigin + row * he; 1434 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1435 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1436 1437 if (c == 0x20) { 1438 gffb_rectfill(sc, x, y, wi, he, bg); 1439 if (attr & WSATTR_UNDERLINE) 1440 gffb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1441 return; 1442 } 1443 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1444 if (rv == GC_OK) 1445 return; 1446 1447 /* 1448 * Use gffb_sync to wait for the engine to become idle before 1449 * we start scribbling into VRAM -- we wouldn't want to stomp on 1450 * a scroll in progress or a prior glyphcache_add that hasn't 1451 * completed yet on the GPU. 1452 */ 1453 mutex_enter(&sc->sc_lock); 1454 gffb_sync(sc); 1455 sc->sc_putchar(cookie, row, col, c, attr & 0xfffffff0); 1456 mutex_exit(&sc->sc_lock); 1457 1458 /* 1459 * If glyphcache_try asked us to, cache the newly written 1460 * character. This will issue a gffb_bitblt which will wait 1461 * for our CPU writes to the framebuffer in VRAM to complete 1462 * before triggering GPU reads from the framebuffer in VRAM. 1463 */ 1464 if (rv == GC_ADD) { 1465 glyphcache_add(&sc->sc_gc, c, x, y); 1466 } else if (attr & WSATTR_UNDERLINE) 1467 gffb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1468 1469 } 1470 1471 static void 1472 gffb_putchar_mono(void *cookie, int row, int col, u_int c, long attr) 1473 { 1474 struct rasops_info *ri = cookie; 1475 struct wsdisplay_font *font = PICK_FONT(ri, c); 1476 struct vcons_screen *scr = ri->ri_hw; 1477 struct gffb_softc *sc = scr->scr_cookie; 1478 void *data; 1479 int x, y, wi, he, i; 1480 uint32_t bg, fg; 1481 1482 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1483 return; 1484 1485 if (!CHAR_IN_FONT(c, font)) 1486 return; 1487 1488 wi = font->fontwidth; 1489 he = font->fontheight; 1490 1491 x = ri->ri_xorigin + col * wi; 1492 y = ri->ri_yorigin + row * he; 1493 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1494 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1495 1496 if (c == 0x20) { 1497 gffb_rectfill(sc, x, y, wi, he, bg); 1498 if (attr & WSATTR_UNDERLINE) 1499 gffb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1500 return; 1501 } 1502 1503 data = WSFONT_GLYPH(c, font); 1504 1505 mutex_enter(&sc->sc_lock); 1506 gffb_sync(sc); 1507 gffb_rop(sc, 0xcc); 1508 1509 gffb_dmastart(sc, RECT_EXPAND_TWO_COLOR_CLIP, 7); 1510 gffb_dmanext(sc, (y << 16) | (x & 0xFFFF)); 1511 gffb_dmanext(sc, ((y + he) << 16) | ((x + wi) & 0xFFFF)); 1512 gffb_dmanext(sc, bg); 1513 gffb_dmanext(sc, fg); 1514 gffb_dmanext(sc, (he << 16) | 32); 1515 gffb_dmanext(sc, (he << 16) | 32); 1516 gffb_dmanext(sc, (y << 16) | (x & 0xFFFF)); 1517 1518 gffb_dmastart(sc, RECT_EXPAND_TWO_COLOR_DATA(0), he); 1519 if (attr & WSATTR_HILIT) { 1520 switch (font->stride) { 1521 case 1: { 1522 uint8_t *data8 = data; 1523 uint32_t reg; 1524 for (i = 0; i < he; i++) { 1525 reg = *data8; 1526 reg |= reg >> 1; 1527 gffb_dmanext(sc, reg << 24); 1528 data8++; 1529 } 1530 break; 1531 } 1532 case 2: { 1533 uint16_t *data16 = data; 1534 uint32_t reg; 1535 for (i = 0; i < he; i++) { 1536 reg = *data16; 1537 reg |= reg >> 1; 1538 gffb_dmanext(sc, reg << 16); 1539 data16++; 1540 } 1541 break; 1542 } 1543 } 1544 } else { 1545 switch (font->stride) { 1546 case 1: { 1547 uint8_t *data8 = data; 1548 uint32_t reg; 1549 for (i = 0; i < he; i++) { 1550 reg = *data8; 1551 gffb_dmanext(sc, reg << 24); 1552 data8++; 1553 } 1554 break; 1555 } 1556 case 2: { 1557 uint16_t *data16 = data; 1558 uint32_t reg; 1559 for (i = 0; i < he; i++) { 1560 reg = *data16; 1561 gffb_dmanext(sc, reg << 16); 1562 data16++; 1563 } 1564 break; 1565 } 1566 } 1567 } 1568 gffb_dma_kickoff(sc); 1569 1570 mutex_exit(&sc->sc_lock); 1571 1572 if (attr & WSATTR_UNDERLINE) 1573 gffb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1574 1575 } 1576 1577 static int 1578 gffb_allocattr(void *cookie, int fg0, int bg0, int flg, long *attr) 1579 { 1580 struct rasops_info *ri = cookie; 1581 int fg = fg0, bg = bg0; 1582 1583 if ((flg & WSATTR_BLINK) != 0) 1584 return EINVAL; 1585 1586 if ((flg & WSATTR_REVERSE) != 0) { 1587 fg = bg0; 1588 bg = fg0; 1589 } 1590 1591 if (FONT_IS_ALPHA(ri->ri_font) && ((flg & WSATTR_HILIT) != 0)) { 1592 fg = fg0 < 8 ? fg0 + 8 : fg0; 1593 } 1594 1595 *attr = (bg << 16) | (fg << 24) | flg; 1596 return 0; 1597 } 1598 1599 static void 1600 gffb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1601 { 1602 struct rasops_info *ri = cookie; 1603 struct vcons_screen *scr = ri->ri_hw; 1604 struct gffb_softc *sc = scr->scr_cookie; 1605 int32_t xs, xd, y, width, height; 1606 1607 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1608 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1609 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1610 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1611 width = ri->ri_font->fontwidth * ncols; 1612 height = ri->ri_font->fontheight; 1613 gffb_bitblt(sc, xs, y, xd, y, width, height, 0xcc); 1614 } 1615 } 1616 1617 static void 1618 gffb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1619 { 1620 struct rasops_info *ri = cookie; 1621 struct vcons_screen *scr = ri->ri_hw; 1622 struct gffb_softc *sc = scr->scr_cookie; 1623 int32_t x, y, width, height, fg, bg, ul; 1624 1625 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1626 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1627 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1628 width = ri->ri_font->fontwidth * ncols; 1629 height = ri->ri_font->fontheight; 1630 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1631 1632 gffb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1633 } 1634 } 1635 1636 static void 1637 gffb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1638 { 1639 struct rasops_info *ri = cookie; 1640 struct vcons_screen *scr = ri->ri_hw; 1641 struct gffb_softc *sc = scr->scr_cookie; 1642 int32_t x, ys, yd, width, height; 1643 1644 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1645 x = ri->ri_xorigin; 1646 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1647 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1648 width = ri->ri_emuwidth; 1649 height = ri->ri_font->fontheight * nrows; 1650 gffb_bitblt(sc, x, ys, x, yd, width, height, 0xcc); 1651 } 1652 } 1653 1654 static void 1655 gffb_eraserows(void *cookie, int row, int nrows, long fillattr) 1656 { 1657 struct rasops_info *ri = cookie; 1658 struct vcons_screen *scr = ri->ri_hw; 1659 struct gffb_softc *sc = scr->scr_cookie; 1660 int32_t x, y, width, height, fg, bg, ul; 1661 1662 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1663 if ((row == 0) && (nrows == ri->ri_rows)) { 1664 /* fullclear */ 1665 x = 0; 1666 y = 0; 1667 width = sc->sc_width; 1668 height = sc->sc_height; 1669 } else { 1670 x = ri->ri_xorigin; 1671 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1672 width = ri->ri_emuwidth; 1673 height = ri->ri_font->fontheight * nrows; 1674 } 1675 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1676 1677 gffb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1678 } 1679 } 1680 1681 static int 1682 gffb_set_cursor(struct gffb_softc *sc, struct wsdisplay_cursor *wc) 1683 { 1684 unsigned flags; 1685 1686 uint8_t r[2], g[2], b[2]; 1687 unsigned index, count; 1688 int i, j, err; 1689 int redo_shape = 0; 1690 1691 flags = wc->which; 1692 1693 if (flags & WSDISPLAY_CURSOR_DOCMAP) { 1694 index = wc->cmap.index; 1695 count = wc->cmap.count; 1696 1697 if (index >= 2 || count > 2 - index) 1698 return EINVAL; 1699 1700 err = copyin(wc->cmap.red, &r[index], count); 1701 if (err) 1702 return err; 1703 err = copyin(wc->cmap.green, &g[index], count); 1704 if (err) 1705 return err; 1706 err = copyin(wc->cmap.blue, &b[index], count); 1707 if (err) 1708 return err; 1709 1710 for (i = index; i < index + count; i++) { 1711 sc->sc_cmap[i] = ((r[i] & 0xf8) << 7) | 1712 ((g[i] & 0xf8) << 2) | 1713 ((b[i] & 0xf8) >> 3) | 1714 0x8000; 1715 } 1716 redo_shape = 1; 1717 } 1718 1719 if (flags & WSDISPLAY_CURSOR_DOSHAPE) { 1720 if ((wc->size.x > 32) || 1721 (wc->size.y > 32)) 1722 return EINVAL; 1723 1724 if ((err = copyin(wc->image, sc->sc_image, 128)) != 0) 1725 return err; 1726 1727 if ((err = copyin(wc->mask, sc->sc_mask, 128)) != 0) 1728 return err; 1729 redo_shape = 1; 1730 } 1731 1732 if (redo_shape) { 1733 uint16_t *ptr = sc->sc_cimg; 1734 int img, msk, bit; 1735 for (i = 0; i < 128; i++) { 1736 img = sc->sc_image[i]; 1737 msk = sc->sc_mask[i]; 1738 bit = 0x01; 1739 for (j = 0; j < 8; j++) { 1740 if (msk & bit) { 1741 /* colour pixel */ 1742 *ptr = (img & bit) ? 1743 sc->sc_cmap[1] : sc->sc_cmap[0]; 1744 } else { 1745 /* transparent pixel */ 1746 *ptr = 0; 1747 } 1748 ptr++; 1749 bit = bit << 1; 1750 } 1751 } 1752 } 1753 1754 if (flags & WSDISPLAY_CURSOR_DOHOT) { 1755 sc->sc_hot_x = wc->hot.x; 1756 sc->sc_hot_y = wc->hot.y; 1757 flags |= WSDISPLAY_CURSOR_DOPOS; 1758 } 1759 1760 if (flags & WSDISPLAY_CURSOR_DOPOS) { 1761 gffb_set_curpos(sc, &wc->pos); 1762 } 1763 if (flags & WSDISPLAY_CURSOR_DOCUR) { 1764 int state = wc->enable == 0 ? 0 : 1; 1765 gffb_write_crtc(sc, 0, 0x31, sc->sc_cstate | state); 1766 gffb_write_crtc(sc, 1, 0x31, sc->sc_cstate | state); 1767 } 1768 return 0; 1769 } 1770 1771 static int 1772 gffb_set_curpos(struct gffb_softc *sc, struct wsdisplay_curpos *p) 1773 { 1774 uint32_t reg; 1775 1776 sc->sc_cursor_x = p->x - sc->sc_hot_x; 1777 sc->sc_cursor_y = p->y - sc->sc_hot_y; 1778 reg = (sc->sc_cursor_x & 0xffff) | (sc->sc_cursor_y << 16); 1779 GFFB_WRITE_4(GFFB_RAMDAC0 + GFFB_CURPOS, reg); 1780 GFFB_WRITE_4(GFFB_RAMDAC1 + GFFB_CURPOS, reg); 1781 return 0; 1782 } 1783 1784