Home | History | Annotate | Line # | Download | only in pci
gffb.c revision 1.2
      1 /*	$NetBSD: gffb.c,v 1.2 2013/10/02 16:35:38 macallan Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007, 2012 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
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: gffb.c,v 1.2 2013/10/02 16:35:38 macallan Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/kernel.h>
     39 #include <sys/device.h>
     40 #include <sys/malloc.h>
     41 #include <sys/lwp.h>
     42 #include <sys/kauth.h>
     43 #include <sys/atomic.h>
     44 
     45 #include <dev/videomode/videomode.h>
     46 
     47 #include <dev/pci/pcivar.h>
     48 #include <dev/pci/pcireg.h>
     49 #include <dev/pci/pcidevs.h>
     50 #include <dev/pci/pciio.h>
     51 #include <dev/pci/gffbreg.h>
     52 
     53 #include <dev/wscons/wsdisplayvar.h>
     54 #include <dev/wscons/wsconsio.h>
     55 #include <dev/wsfont/wsfont.h>
     56 #include <dev/rasops/rasops.h>
     57 #include <dev/wscons/wsdisplay_vconsvar.h>
     58 #include <dev/pci/wsdisplay_pci.h>
     59 #include <dev/wscons/wsdisplay_glyphcachevar.h>
     60 
     61 #include <dev/i2c/i2cvar.h>
     62 
     63 #include "opt_gffb.h"
     64 #include "opt_vcons.h"
     65 
     66 #ifdef GFFB_DEBUG
     67 #define DPRINTF printf
     68 #else
     69 #define DPRINTF while(0) printf
     70 #endif
     71 
     72 struct gffb_softc {
     73 	device_t sc_dev;
     74 
     75 	pci_chipset_tag_t sc_pc;
     76 	pcitag_t sc_pcitag;
     77 
     78 	bus_space_tag_t sc_memt;
     79 	bus_space_tag_t sc_iot;
     80 
     81 	bus_space_handle_t sc_regh, sc_fbh;
     82 	bus_addr_t sc_fb, sc_reg;
     83 	bus_size_t sc_fbsize, sc_regsize;
     84 	uint8_t *sc_fbaddr;
     85 	size_t sc_vramsize;
     86 
     87 	int sc_width, sc_height, sc_depth, sc_stride;
     88 	int sc_locked;
     89 	struct vcons_screen sc_console_screen;
     90 	struct wsscreen_descr sc_defaultscreen_descr;
     91 	const struct wsscreen_descr *sc_screens[1];
     92 	struct wsscreen_list sc_screenlist;
     93 	struct vcons_data vd;
     94 	int sc_mode;
     95 	u_char sc_cmap_red[256];
     96 	u_char sc_cmap_green[256];
     97 	u_char sc_cmap_blue[256];
     98 	int sc_put, sc_current, sc_free;
     99 	glyphcache sc_gc;
    100 };
    101 
    102 static int	gffb_match(device_t, cfdata_t, void *);
    103 static void	gffb_attach(device_t, device_t, void *);
    104 
    105 CFATTACH_DECL_NEW(gffb, sizeof(struct gffb_softc),
    106     gffb_match, gffb_attach, NULL, NULL);
    107 
    108 static int	gffb_ioctl(void *, void *, u_long, void *, int,
    109 			     struct lwp *);
    110 static paddr_t	gffb_mmap(void *, void *, off_t, int);
    111 static void	gffb_init_screen(void *, struct vcons_screen *, int, long *);
    112 
    113 static int	gffb_putcmap(struct gffb_softc *, struct wsdisplay_cmap *);
    114 static int 	gffb_getcmap(struct gffb_softc *, struct wsdisplay_cmap *);
    115 static void	gffb_restore_palette(struct gffb_softc *);
    116 static int 	gffb_putpalreg(struct gffb_softc *, uint8_t, uint8_t,
    117 			    uint8_t, uint8_t);
    118 
    119 static void	gffb_init(struct gffb_softc *);
    120 
    121 static void	gffb_make_room(struct gffb_softc *, int);
    122 
    123 #if notyet
    124 static void	gffb_flush_engine(struct gffb_softc *);
    125 static void	gffb_rectfill(struct gffb_softc *, int, int, int, int,
    126 			    uint32_t);
    127 static void	gffb_bitblt(void *, int, int, int, int, int,
    128 			    int, int);
    129 
    130 static void	gffb_cursor(void *, int, int, int);
    131 static void	gffb_putchar(void *, int, int, u_int, long);
    132 static void	gffb_putchar_aa(void *, int, int, u_int, long);
    133 static void	gffb_copycols(void *, int, int, int, int);
    134 static void	gffb_erasecols(void *, int, int, int, long);
    135 static void	gffb_copyrows(void *, int, int, int);
    136 static void	gffb_eraserows(void *, int, int, long);
    137 #endif /* notyet */
    138 
    139 struct wsdisplay_accessops gffb_accessops = {
    140 	gffb_ioctl,
    141 	gffb_mmap,
    142 	NULL,	/* alloc_screen */
    143 	NULL,	/* free_screen */
    144 	NULL,	/* show_screen */
    145 	NULL, 	/* load_font */
    146 	NULL,	/* pollc */
    147 	NULL	/* scroll */
    148 };
    149 
    150 static int
    151 gffb_match(device_t parent, cfdata_t match, void *aux)
    152 {
    153 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
    154 
    155 	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
    156 		return 0;
    157 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NVIDIA)
    158 		return 0;
    159 
    160 	/* only card tested on so far - likely need a list */
    161 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GEFORCE2MX)
    162 		return 100;
    163 	return (0);
    164 }
    165 
    166 static void
    167 gffb_attach(device_t parent, device_t self, void *aux)
    168 {
    169 	struct gffb_softc	*sc = device_private(self);
    170 	struct pci_attach_args	*pa = aux;
    171 	struct rasops_info	*ri;
    172 	bus_space_tag_t		tag;
    173 	struct wsemuldisplaydev_attach_args aa;
    174 	prop_dictionary_t	dict;
    175 	unsigned long		defattr;
    176 	bool			is_console;
    177 	int			i, j;
    178 	uint8_t			cmap[768];
    179 
    180 	sc->sc_pc = pa->pa_pc;
    181 	sc->sc_pcitag = pa->pa_tag;
    182 	sc->sc_memt = pa->pa_memt;
    183 	sc->sc_iot = pa->pa_iot;
    184 	sc->sc_dev = self;
    185 
    186 	pci_aprint_devinfo(pa, NULL);
    187 
    188 	/* fill in parameters from properties */
    189 	dict = device_properties(self);
    190 	if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
    191 		aprint_error("%s: no width property\n", device_xname(self));
    192 		return;
    193 	}
    194 	if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
    195 		aprint_error("%s: no height property\n", device_xname(self));
    196 		return;
    197 	}
    198 
    199 #ifdef GLYPHCACHE_DEBUG
    200 	/* leave some visible VRAM unused so we can see the glyph cache */
    201 	sc->sc_height -= 200;
    202 #endif
    203 
    204 	if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
    205 		aprint_error("%s: no depth property\n", device_xname(self));
    206 		return;
    207 	}
    208 	if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) {
    209 		aprint_error("%s: no linebytes property\n",
    210 		    device_xname(self));
    211 		return;
    212 	}
    213 
    214 	prop_dictionary_get_bool(dict, "is_console", &is_console);
    215 
    216 	if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM,
    217 	    BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR,
    218 	    &tag, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) {
    219 		aprint_error("%s: failed to map the framebuffer.\n",
    220 		    device_xname(sc->sc_dev));
    221 	}
    222 	sc->sc_fbaddr = bus_space_vaddr(tag, sc->sc_fbh);
    223 
    224 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0,
    225 	    &tag, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) {
    226 		aprint_error("%s: failed to map registers.\n",
    227 		    device_xname(sc->sc_dev));
    228 	}
    229 
    230 	aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
    231 	    (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
    232 
    233 	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
    234 		"default",
    235 		0, 0,
    236 		NULL,
    237 		8, 16,
    238 		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
    239 		NULL
    240 	};
    241 	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
    242 	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
    243 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
    244 	sc->sc_locked = 0;
    245 
    246 	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
    247 	    &gffb_accessops);
    248 	sc->vd.init_screen = gffb_init_screen;
    249 
    250 	sc->sc_vramsize = bus_space_read_4(sc->sc_memt, sc->sc_regh,
    251 	    GFFB_VRAM) & 0xfff00000;
    252 
    253 	printf("vram: %d MB\n", sc->sc_vramsize >> 20);
    254 	printf("put: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT));
    255 	printf("get: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET));
    256 	/* init engine here */
    257 	gffb_init(sc);
    258 	printf("put: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT));
    259 	printf("get: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET));
    260 
    261 	ri = &sc->sc_console_screen.scr_ri;
    262 
    263 #if notyet
    264 	sc->sc_gc.gc_bitblt = gffb_bitblt;
    265 	sc->sc_gc.gc_blitcookie = sc;
    266 	sc->sc_gc.gc_rop = R128_ROP3_S;
    267 #endif
    268 
    269 	if (is_console) {
    270 		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
    271 		    &defattr);
    272 		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    273 
    274 #if notyet
    275 		gffb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
    276 		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
    277 #else
    278 		memset(sc->sc_fbaddr + 0x2000,
    279 		    ri->ri_devcmap[(defattr >> 16) & 0xff],
    280 		    sc->sc_height * sc->sc_stride);
    281 #endif
    282 		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
    283 		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
    284 		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
    285 		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
    286 #if notyet
    287 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
    288 				(0x800000 / sc->sc_stride) - sc->sc_height - 5,
    289 				sc->sc_width,
    290 				ri->ri_font->fontwidth,
    291 				ri->ri_font->fontheight,
    292 				defattr);
    293 #endif
    294 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
    295 		    defattr);
    296 		vcons_replay_msgbuf(&sc->sc_console_screen);
    297 	} else {
    298 		/*
    299 		 * since we're not the console we can postpone the rest
    300 		 * until someone actually allocates a screen for us
    301 		 */
    302 		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
    303 			/* do some minimal setup to avoid weirdnesses later */
    304 			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
    305 			    &defattr);
    306 		} else
    307 			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    308 #if notyet
    309 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
    310 				(0x800000 / sc->sc_stride) - sc->sc_height - 5,
    311 				sc->sc_width,
    312 				ri->ri_font->fontwidth,
    313 				ri->ri_font->fontheight,
    314 				defattr);
    315 #endif
    316 	}
    317 
    318 	j = 0;
    319 	rasops_get_cmap(ri, cmap, sizeof(cmap));
    320 	for (i = 0; i < 256; i++) {
    321 		sc->sc_cmap_red[i] = cmap[j];
    322 		sc->sc_cmap_green[i] = cmap[j + 1];
    323 		sc->sc_cmap_blue[i] = cmap[j + 2];
    324 		gffb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
    325 		j += 3;
    326 	}
    327 
    328 	/* no suspend/resume support yet */
    329 	pmf_device_register(sc->sc_dev, NULL, NULL);
    330 
    331 	aa.console = is_console;
    332 	aa.scrdata = &sc->sc_screenlist;
    333 	aa.accessops = &gffb_accessops;
    334 	aa.accesscookie = &sc->vd;
    335 
    336 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
    337 }
    338 
    339 static int
    340 gffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    341 	struct lwp *l)
    342 {
    343 	struct vcons_data *vd = v;
    344 	struct gffb_softc *sc = vd->cookie;
    345 	struct wsdisplay_fbinfo *wdf;
    346 	struct vcons_screen *ms = vd->active;
    347 
    348 	switch (cmd) {
    349 	case WSDISPLAYIO_GTYPE:
    350 		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
    351 		return 0;
    352 
    353 	/* PCI config read/write passthrough. */
    354 	case PCI_IOC_CFGREAD:
    355 	case PCI_IOC_CFGWRITE:
    356 		return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
    357 		    cmd, data, flag, l);
    358 
    359 	case WSDISPLAYIO_GET_BUSID:
    360 		return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
    361 		    sc->sc_pcitag, data);
    362 
    363 	case WSDISPLAYIO_GINFO:
    364 		if (ms == NULL)
    365 			return ENODEV;
    366 		wdf = (void *)data;
    367 		wdf->height = ms->scr_ri.ri_height;
    368 		wdf->width = ms->scr_ri.ri_width;
    369 		wdf->depth = ms->scr_ri.ri_depth;
    370 		wdf->cmsize = 256;
    371 		return 0;
    372 
    373 	case WSDISPLAYIO_GETCMAP:
    374 		return gffb_getcmap(sc,
    375 		    (struct wsdisplay_cmap *)data);
    376 
    377 	case WSDISPLAYIO_PUTCMAP:
    378 		return gffb_putcmap(sc,
    379 		    (struct wsdisplay_cmap *)data);
    380 
    381 	case WSDISPLAYIO_LINEBYTES:
    382 		*(u_int *)data = sc->sc_stride;
    383 		return 0;
    384 
    385 	case WSDISPLAYIO_SMODE: {
    386 		int new_mode = *(int*)data;
    387 		if (new_mode != sc->sc_mode) {
    388 			sc->sc_mode = new_mode;
    389 			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
    390 				gffb_init(sc);
    391 				gffb_restore_palette(sc);
    392 #if notyet
    393 				glyphcache_wipe(&sc->sc_gc);
    394 				gffb_rectfill(sc, 0, 0, sc->sc_width,
    395 				    sc->sc_height, ms->scr_ri.ri_devcmap[
    396 				    (ms->scr_defattr >> 16) & 0xff]);
    397 #endif
    398 				vcons_redraw_screen(ms);
    399 			}
    400 		}
    401 		}
    402 		return 0;
    403 #if notyet
    404 	case WSDISPLAYIO_GET_EDID: {
    405 		struct wsdisplayio_edid_info *d = data;
    406 		return wsdisplayio_get_edid(sc->sc_dev, d);
    407 	}
    408 #endif
    409 	}
    410 	return EPASSTHROUGH;
    411 }
    412 
    413 static paddr_t
    414 gffb_mmap(void *v, void *vs, off_t offset, int prot)
    415 {
    416 	struct vcons_data *vd = v;
    417 	struct gffb_softc *sc = vd->cookie;
    418 	paddr_t pa;
    419 
    420 	/* 'regular' framebuffer mmap()ing */
    421 	if (offset < sc->sc_fbsize) {
    422 		pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset + 0x2000,
    423 		    0, prot, BUS_SPACE_MAP_LINEAR);
    424 		return pa;
    425 	}
    426 
    427 	/*
    428 	 * restrict all other mappings to processes with superuser privileges
    429 	 * or the kernel itself
    430 	 */
    431 	if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
    432 	    NULL, NULL, NULL, NULL) != 0) {
    433 		aprint_normal("%s: mmap() rejected.\n",
    434 		    device_xname(sc->sc_dev));
    435 		return -1;
    436 	}
    437 
    438 	if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
    439 		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
    440 		    BUS_SPACE_MAP_LINEAR);
    441 		return pa;
    442 	}
    443 
    444 	if ((offset >= sc->sc_reg) &&
    445 	    (offset < (sc->sc_reg + sc->sc_regsize))) {
    446 		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
    447 		    BUS_SPACE_MAP_LINEAR);
    448 		return pa;
    449 	}
    450 
    451 #ifdef PCI_MAGIC_IO_RANGE
    452 	/* allow mapping of IO space */
    453 	if ((offset >= PCI_MAGIC_IO_RANGE) &&
    454 	    (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
    455 		pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
    456 		    0, prot, BUS_SPACE_MAP_LINEAR);
    457 		return pa;
    458 	}
    459 #endif
    460 
    461 #ifdef OFB_ALLOW_OTHERS
    462 	if (offset >= 0x80000000) {
    463 		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
    464 		    BUS_SPACE_MAP_LINEAR);
    465 		return pa;
    466 	}
    467 #endif
    468 	return -1;
    469 }
    470 
    471 static void
    472 gffb_init_screen(void *cookie, struct vcons_screen *scr,
    473     int existing, long *defattr)
    474 {
    475 	struct gffb_softc *sc = cookie;
    476 	struct rasops_info *ri = &scr->scr_ri;
    477 
    478 	ri->ri_depth = sc->sc_depth;
    479 	ri->ri_width = sc->sc_width;
    480 	ri->ri_height = sc->sc_height;
    481 	ri->ri_stride = sc->sc_stride;
    482 	ri->ri_bits = sc->sc_fbaddr + 0x2000;
    483 	ri->ri_flg = RI_CENTER;
    484 	if (sc->sc_depth == 8)
    485 		ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
    486 
    487 	rasops_init(ri, 0, 0);
    488 	ri->ri_caps = WSSCREEN_WSCOLORS;
    489 	scr->scr_flags |= VCONS_DONT_READ;
    490 
    491 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
    492 		    sc->sc_width / ri->ri_font->fontwidth);
    493 
    494 	ri->ri_hw = scr;
    495 #if notyet
    496 	ri->ri_ops.copyrows = gffb_copyrows;
    497 	ri->ri_ops.copycols = gffb_copycols;
    498 	ri->ri_ops.eraserows = gffb_eraserows;
    499 	ri->ri_ops.erasecols = gffb_erasecols;
    500 	ri->ri_ops.cursor = gffb_cursor;
    501 	if (FONT_IS_ALPHA(ri->ri_font)) {
    502 		ri->ri_ops.putchar = gffb_putchar_aa;
    503 	} else
    504 		ri->ri_ops.putchar = gffb_putchar;
    505 #endif
    506 }
    507 
    508 static int
    509 gffb_putcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm)
    510 {
    511 	u_char *r, *g, *b;
    512 	u_int index = cm->index;
    513 	u_int count = cm->count;
    514 	int i, error;
    515 	u_char rbuf[256], gbuf[256], bbuf[256];
    516 
    517 #ifdef R128FB_DEBUG
    518 	aprint_debug("putcmap: %d %d\n",index, count);
    519 #endif
    520 	if (cm->index >= 256 || cm->count > 256 ||
    521 	    (cm->index + cm->count) > 256)
    522 		return EINVAL;
    523 	error = copyin(cm->red, &rbuf[index], count);
    524 	if (error)
    525 		return error;
    526 	error = copyin(cm->green, &gbuf[index], count);
    527 	if (error)
    528 		return error;
    529 	error = copyin(cm->blue, &bbuf[index], count);
    530 	if (error)
    531 		return error;
    532 
    533 	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
    534 	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
    535 	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
    536 
    537 	r = &sc->sc_cmap_red[index];
    538 	g = &sc->sc_cmap_green[index];
    539 	b = &sc->sc_cmap_blue[index];
    540 
    541 	for (i = 0; i < count; i++) {
    542 		gffb_putpalreg(sc, index, *r, *g, *b);
    543 		index++;
    544 		r++, g++, b++;
    545 	}
    546 	return 0;
    547 }
    548 
    549 static int
    550 gffb_getcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm)
    551 {
    552 	u_int index = cm->index;
    553 	u_int count = cm->count;
    554 	int error;
    555 
    556 	if (index >= 255 || count > 256 || index + count > 256)
    557 		return EINVAL;
    558 
    559 	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
    560 	if (error)
    561 		return error;
    562 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
    563 	if (error)
    564 		return error;
    565 	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
    566 	if (error)
    567 		return error;
    568 
    569 	return 0;
    570 }
    571 
    572 static void
    573 gffb_restore_palette(struct gffb_softc *sc)
    574 {
    575 	int i;
    576 
    577 	for (i = 0; i < (1 << sc->sc_depth); i++) {
    578 		gffb_putpalreg(sc, i, sc->sc_cmap_red[i],
    579 		    sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
    580 	}
    581 }
    582 
    583 static int
    584 gffb_putpalreg(struct gffb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
    585     uint8_t b)
    586 {
    587 	/* port 0 */
    588 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    589 	    GFFB_PDIO0 + GFFB_PEL_IW, idx);
    590 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    591 	    GFFB_PDIO0 + GFFB_PEL_D, r);
    592 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    593 	    GFFB_PDIO0 + GFFB_PEL_D, g);
    594 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    595 	    GFFB_PDIO0 + GFFB_PEL_D, b);
    596 
    597 	/* port 1 */
    598 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    599 	    GFFB_PDIO1 + GFFB_PEL_IW, idx);
    600 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    601 	    GFFB_PDIO1 + GFFB_PEL_D, r);
    602 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    603 	    GFFB_PDIO1 + GFFB_PEL_D, g);
    604 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    605 	    GFFB_PDIO1 + GFFB_PEL_D, b);
    606 
    607 	return 0;
    608 }
    609 
    610 
    611 static void
    612 gffb_dma_kickoff(struct gffb_softc *sc)
    613 {
    614 	volatile uint8_t scratch;
    615 
    616 	if(sc->sc_current != sc->sc_put) {
    617 		sc->sc_put = sc->sc_current;
    618 		membar_sync();
    619 		scratch = *sc->sc_fbaddr;
    620 		bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT,
    621 		    sc->sc_put);
    622 	}
    623 }
    624 
    625 static void
    626 gffb_dmanext(struct gffb_softc *sc, uint32_t data)
    627 {
    628 	bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, sc->sc_current, data);
    629 	sc->sc_current += 4;
    630 }
    631 
    632 static void
    633 gffb_dmastart(struct gffb_softc *sc, uint32_t tag, int size)
    634 {
    635 	if(sc->sc_free <= (size << 2))
    636 		gffb_make_room(sc, size);
    637 	gffb_dmanext(sc, ((size) << 18) | (tag));
    638 	sc->sc_free -= ((size + 1) << 2);
    639 }
    640 
    641 /*
    642  * from xf86_video_nv/nv_xaa.c:
    643  * There is a HW race condition with videoram command buffers.
    644  * You can't jump to the location of your put offset.  We write put
    645  * at the jump offset + SKIPS dwords with noop padding in between
    646  * to solve this problem
    647  */
    648 
    649 #define SKIPS  8
    650 
    651 static void
    652 gffb_make_room(struct gffb_softc *sc, int size)
    653 {
    654 	uint32_t get;
    655 
    656 	size = (size + 1) << 2;	/* slots -> offset */
    657 
    658 	while (sc->sc_free < size) {
    659 		get = bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET);
    660 
    661 		if (sc->sc_put >= get) {
    662 			sc->sc_free = 0x2000 - sc->sc_current;
    663 			if (sc->sc_free < size) {
    664 				gffb_dmanext(sc, 0x20000000);
    665 				if(get <= SKIPS) {
    666 					if (sc->sc_put <= SKIPS) {
    667 						/* corner case - will be idle */
    668 						bus_space_write_4(sc->sc_memt,
    669 						    sc->sc_regh, GFFB_FIFO_PUT,
    670 						    SKIPS + 1);
    671 					}
    672 					do {
    673 						get = bus_space_read_4(
    674 						    sc->sc_memt, sc->sc_regh,
    675 						    GFFB_FIFO_GET);
    676 					} while (get <= SKIPS);
    677 				}
    678 				bus_space_write_4(sc->sc_memt, sc->sc_regh,
    679 				     GFFB_FIFO_PUT, SKIPS);
    680 				sc->sc_current = sc->sc_put = SKIPS;
    681 				sc->sc_free = get - (SKIPS + 1);
    682 			}
    683 		} else
    684 			sc->sc_free = get - sc->sc_current - 1;
    685 	}
    686 }
    687 
    688 static void
    689 gffb_sync(struct gffb_softc *sc)
    690 {
    691 	int bail;
    692 
    693 	bail = 100000;
    694 	while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET) !=
    695 	    sc->sc_put) && (bail > 0)) {
    696 		bail--;
    697 		delay(1);
    698 	}
    699 	if (bail == 0) printf("DMA timed out\n");
    700 
    701 	bail = 100000;
    702 	while((bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_BUSY) != 0) &&
    703 	    (bail > 0)) {
    704 		bail--;
    705 		delay(1);
    706 	}
    707 	if (bail == 0) printf("engine timed out\n");
    708 }
    709 
    710 static void
    711 gffb_init(struct gffb_softc *sc)
    712 {
    713 	int i;
    714 
    715 	/* init display start */
    716 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
    717 	    GFFB_CRTC0 + GFFB_DISPLAYSTART, 0x2000);
    718 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
    719 	    GFFB_CRTC1 + GFFB_DISPLAYSTART, 0x2000);
    720 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    721 	    GFFB_PDIO0 + GFFB_PEL_MASK, 0xff);
    722 	bus_space_write_1(sc->sc_memt, sc->sc_regh,
    723 	    GFFB_PDIO1 + GFFB_PEL_MASK, 0xff);
    724 
    725 	/* DMA stuff. A whole lot of magic number voodoo from xf86-video-nv */
    726 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PMC + 0x140, 0);
    727 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PMC + 0x200, 0xffff00ff);
    728 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PMC + 0x200, 0xffffffff);
    729 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x800, 8);
    730 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x840, 3);
    731 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x500, 0);
    732 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x400, 0xffffffff);
    733 	for (i = 0; i < 8; i++) {
    734 		bus_space_write_4(sc->sc_memt, sc->sc_regh,
    735 		    GFFB_PMC + 0x240 + (i * 0x10), 0);
    736 		bus_space_write_4(sc->sc_memt, sc->sc_regh,
    737 		    GFFB_PMC + 0x244 + (i * 0x10), sc->sc_vramsize - 1);
    738 	}
    739 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN, 0x80000010);
    740 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x04, 0x80011201);
    741 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x08, 0x80000011);
    742 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x0c, 0x80011202);
    743 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x10, 0x80000012);
    744 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x14, 0x80011203);
    745 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x18, 0x80000013);
    746 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x1c, 0x80011204);
    747 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x20, 0x80000014);
    748 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x24, 0x80011205);
    749 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x28, 0x80000015);
    750 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2c, 0x80011206);
    751 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x30, 0x80000016);
    752 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x34, 0x80011207);
    753 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x38, 0x80000017);
    754 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x3c, 0x80011208);
    755 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2000, 0x00003000);
    756 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2004, sc->sc_vramsize - 1);
    757 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2008, 0x00000002);
    758 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x200c, 0x00000002);
    759 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2010, 0x01008042);	/* different for nv40 */
    760 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2014, 0);
    761 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2018, 0x12001200);
    762 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x201c, 0);
    763 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2020, 0x01008043);
    764 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2024, 0);
    765 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2028, 0);
    766 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x202c, 0);
    767 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2030, 0x01008044);
    768 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2034, 0x00000002);
    769 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2038, 0);
    770 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x203c, 0);
    771 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2040, 0x01008019);
    772 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2044, 0);
    773 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2048, 0);
    774 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x204c, 0);
    775 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2050, 0x0100a05c);
    776 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2054, 0);
    777 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2058, 0);
    778 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x205c, 0);
    779 	/* XXX 0x0100805f if !WaitVSynvPossible */
    780 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2060, 0x0100809f);
    781 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2064, 0);
    782 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2068, 0x12001200);
    783 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x206c, 0);
    784 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2070, 0x0100804a);
    785 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2074, 0x00000002);
    786 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2078, 0);
    787 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x207c, 0);
    788 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2080, 0x01018077);
    789 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2084, 0);
    790 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2088, 0x12001200);
    791 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x208c, 0);
    792 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2090, 0x00003002);
    793 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2094, 0x00007fff);
    794 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2098, 0x00000002);	/* start of command buffer? */
    795 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x209c, 0x00000002);
    796 	/* __BIG_ENDIAN part? */
    797 	/* PGRAPH setup */
    798 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0500, 0);
    799 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0504, 0x00000001);
    800 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1200, 0);
    801 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1250, 0);
    802 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1204, 0x00000100);	/* different on nv40 */
    803 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1240, 0);
    804 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1244, 0);
    805 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x122c, 0x00001209);	/* different on nv40 */
    806 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1000, 0);
    807 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1050, 0);
    808 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0210, 0x03000100);
    809 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0214, 0x00000110);
    810 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0218, 0x00000112);
    811 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x050c, 0x0000ffff);
    812 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1258, 0x0000ffff);
    813 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0140, 0);
    814 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0100, 0xffffffff);
    815 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1054, 0x00000001);
    816 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1230, 0);
    817 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1280, 0);
    818 #if BYTE_ORDER == BIG_ENDIAN
    819 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1224, 0x800f0078);
    820 #else
    821 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1224, 0x000f0078);
    822 #endif
    823 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1220, 0x00000001);
    824 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1200, 0x00000001);
    825 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1250, 0x00000001);
    826 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1254, 0x00000001);
    827 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0500, 0x00000001);
    828 
    829 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_CMDSTART, 0x00000002);
    830 	bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET, 0);
    831 	sc->sc_put = 0;
    832 	sc->sc_current = 0;
    833 	sc->sc_free = 0x2000;
    834 
    835 	for(i = 0; i < SKIPS; i++)
    836 		gffb_dmanext(sc, 0);
    837 
    838 	gffb_dmanext(sc, 0x00040000);
    839 	gffb_dmanext(sc, 0x80000010);
    840 	gffb_dmanext(sc, 0x00042000);
    841 	gffb_dmanext(sc, 0x80000011);
    842 	gffb_dmanext(sc, 0x00044000);
    843 	gffb_dmanext(sc, 0x80000012);
    844 	gffb_dmanext(sc, 0x00046000);
    845 	gffb_dmanext(sc, 0x80000013);
    846 	gffb_dmanext(sc, 0x00048000);
    847 	gffb_dmanext(sc, 0x80000014);
    848 	gffb_dmanext(sc, 0x0004A000);
    849 	gffb_dmanext(sc, 0x80000015);
    850 	gffb_dmanext(sc, 0x0004C000);
    851 	gffb_dmanext(sc, 0x80000016);
    852 	gffb_dmanext(sc, 0x0004E000);
    853 	gffb_dmanext(sc, 0x80000017);
    854 	sc->sc_free = 0x2000 - sc->sc_current;
    855 
    856 	gffb_dmastart(sc, SURFACE_FORMAT, 4);
    857 	gffb_dmanext(sc, SURFACE_FORMAT_DEPTH8);
    858 	gffb_dmanext(sc, sc->sc_stride | (sc->sc_stride << 16));
    859 	gffb_dmanext(sc, 0);
    860 	gffb_dmanext(sc, 0);
    861 
    862 	gffb_dmastart(sc, RECT_FORMAT, 1);
    863 	gffb_dmanext(sc, RECT_FORMAT_DEPTH8);
    864 
    865 	gffb_dmastart(sc, ROP_SET, 1);
    866 	gffb_dmanext(sc, 0xcc);
    867 
    868 	gffb_dma_kickoff(sc);
    869 	gffb_sync(sc);
    870 	printf("put %x current %x\n", sc->sc_put, sc->sc_current);
    871 }
    872 
    873