Home | History | Annotate | Line # | Download | only in pci
unichromefb.c revision 1.2
      1 /* $NetBSD: unichromefb.c,v 1.2 2006/08/13 03:37:02 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006 Jared D. McNeill <jmcneill (at) invisible.ca>
      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  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *        This product includes software developed by Jared D. McNeill.
     18  * 4. Neither the name of The NetBSD Foundation nor the names of its
     19  *    contributors may be used to endorse or promote products derived
     20  *    from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     32  * POSSIBILITY OF SUCH DAMAGE.
     33  */
     34 
     35 /*
     36  * Copyright 1998-2006 VIA Technologies, Inc. All Rights Reserved.
     37  * Copyright 2001-2006 S3 Graphics, Inc. All Rights Reserved.
     38  *
     39  * Permission is hereby granted, free of charge, to any person obtaining a
     40  * copy of this software and associated documentation files (the "Software"),
     41  * to deal in the Software without restriction, including without limitation
     42  * the rights to use, copy, modify, merge, publish, distribute, sub license,
     43  * and/or sell copies of the Software, and to permit persons to whom the
     44  * Software is furnished to do so, subject to the following conditions:
     45  *
     46  * The above copyright notice and this permission notice (including the
     47  * next paragraph) shall be included in all copies or substantial portions
     48  * of the Software.
     49  *
     50  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     51  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     52  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     53  * THE AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     54  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     55  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     56  * DEALINGS IN THE SOFTWARE.
     57  */
     58 
     59 #include <sys/cdefs.h>
     60 __KERNEL_RCSID(0, "$NetBSD: unichromefb.c,v 1.2 2006/08/13 03:37:02 jmcneill Exp $");
     61 
     62 #include <sys/param.h>
     63 #include <sys/systm.h>
     64 #include <sys/device.h>
     65 #include <sys/malloc.h>
     66 
     67 #include <machine/bus.h>
     68 
     69 #include <dev/pci/pcivar.h>
     70 #include <dev/pci/pcireg.h>
     71 #include <dev/pci/pcidevs.h>
     72 
     73 #include <dev/wscons/wsdisplayvar.h>
     74 #include <dev/wscons/wsconsio.h>
     75 #include <dev/wsfont/wsfont.h>
     76 #include <dev/rasops/rasops.h>
     77 #include <dev/wscons/wsdisplay_vconsvar.h>
     78 
     79 #include <dev/pci/unichromereg.h>
     80 #include <dev/pci/unichromemode.h>
     81 #include <dev/pci/unichromehw.h>
     82 #include <dev/pci/unichromeconfig.h>
     83 #include <dev/pci/unichromeaccel.h>
     84 
     85 /* XXX */
     86 #define UNICHROMEFB_DEPTH	16
     87 #define UNICHROMEFB_MODE	VIA_RES_1280X1024
     88 #define UNICHROMEFB_WIDTH	1280
     89 #define UNICHROMEFB_HEIGHT	1024
     90 
     91 struct unichromefb_softc {
     92 	struct device		sc_dev;
     93 	struct vcons_data	sc_vd;
     94 	void *			sc_fbbase;
     95 	unsigned int		sc_fbaddr;
     96 	unsigned int		sc_fbsize;
     97 
     98 	bus_space_tag_t		sc_iot;
     99 	bus_space_handle_t	sc_ioh;
    100 
    101 	bus_space_tag_t		sc_memt;
    102 	bus_space_handle_t	sc_memh;
    103 
    104 	int			sc_width;
    105 	int			sc_height;
    106 	int			sc_depth;
    107 	int			sc_stride;
    108 
    109 	int			sc_wsmode;
    110 
    111 	int			sc_accel;
    112 };
    113 
    114 static int unichromefb_match(struct device *, struct cfdata *, void *);
    115 static void unichromefb_attach(struct device *, struct device *, void *);
    116 
    117 /* XXX */
    118 int unichromefb_cnattach(void);
    119 
    120 struct wsscreen_descr unichromefb_stdscreen = {
    121 	"fb",
    122 	0, 0,
    123 	NULL,
    124 	8, 16,
    125 };
    126 
    127 static int	unichromefb_ioctl(void *, void *, u_long, caddr_t, int,
    128 				  struct lwp *);
    129 static paddr_t	unichromefb_mmap(void *, void *, off_t, int);
    130 
    131 static void	unichromefb_init_screen(void *, struct vcons_screen *,
    132 					int, long *);
    133 
    134 /* hardware access */
    135 static uint8_t	uni_rd(struct unichromefb_softc *, int, uint8_t);
    136 static void	uni_wr(struct unichromefb_softc *, int, uint8_t, uint8_t);
    137 static void	uni_wr_mask(struct unichromefb_softc *, int, uint8_t,
    138 			    uint8_t, uint8_t);
    139 static void	uni_wr_x(struct unichromefb_softc *, struct io_reg *, int);
    140 static void	uni_wr_dac(struct unichromefb_softc *, uint8_t, uint8_t,
    141 			   uint8_t, uint8_t);
    142 
    143 /* helpers */
    144 static struct VideoModeTable *	uni_getmode(int);
    145 static void	uni_setmode(struct unichromefb_softc *, int, int);
    146 static void	uni_crt_lock(struct unichromefb_softc *);
    147 static void	uni_crt_unlock(struct unichromefb_softc *);
    148 static void	uni_crt_enable(struct unichromefb_softc *);
    149 static void	uni_crt_disable(struct unichromefb_softc *);
    150 static void	uni_screen_enable(struct unichromefb_softc *);
    151 static void	uni_screen_disable(struct unichromefb_softc *);
    152 static void	uni_set_start(struct unichromefb_softc *);
    153 static void	uni_set_crtc(struct unichromefb_softc *,
    154 			     struct crt_mode_table *, int, int, int);
    155 static void	uni_load_crtc(struct unichromefb_softc *, struct display_timing,
    156 			      int);
    157 static void	uni_load_reg(struct unichromefb_softc *, int, int,
    158 			     struct io_register *, int);
    159 static void	uni_fix_crtc(struct unichromefb_softc *);
    160 static void	uni_load_offset(struct unichromefb_softc *, int, int, int);
    161 static void	uni_load_fetchcnt(struct unichromefb_softc *, int, int, int);
    162 static void	uni_load_fifo(struct unichromefb_softc *, int, int, int);
    163 static void	uni_set_depth(struct unichromefb_softc *, int, int);
    164 static uint32_t	uni_get_clkval(struct unichromefb_softc *, int);
    165 static void	uni_set_vclk(struct unichromefb_softc *, uint32_t, int);
    166 static void	uni_init_dac(struct unichromefb_softc *, int);
    167 static void	uni_init_accel(struct unichromefb_softc *);
    168 static void	uni_set_accel_depth(struct unichromefb_softc *);
    169 
    170 /* graphics ops */
    171 static void	uni_wait_idle(struct unichromefb_softc *);
    172 static void	uni_fillrect(struct unichromefb_softc *,
    173 			     int, int, int, int, int);
    174 static void	uni_bitblit(struct unichromefb_softc *, int, int, int, int, int, int);
    175 
    176 /* rasops glue */
    177 static void	uni_copycols(void *, int, int, int, int);
    178 static void	uni_copyrows(void *, int, int, int);
    179 static void	uni_erasecols(void *, int, int, int, long);
    180 static void	uni_eraserows(void *, int, int, long);
    181 #if notyet
    182 static void	uni_cursor(void *, int, int, int);
    183 static void	uni_putchar(void *, int, int, u_int, long);
    184 #endif
    185 
    186 struct wsdisplay_accessops unichromefb_accessops = {
    187 	unichromefb_ioctl,
    188 	unichromefb_mmap,
    189 	NULL,
    190 	NULL,
    191 	NULL,
    192 	NULL,
    193 };
    194 
    195 static struct vcons_screen unichromefb_console_screen;
    196 
    197 const struct wsscreen_descr *_unichromefb_scrlist[] = {
    198 	&unichromefb_stdscreen,
    199 };
    200 
    201 struct wsscreen_list unichromefb_screenlist = {
    202 	sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *),
    203 	_unichromefb_scrlist
    204 };
    205 
    206 CFATTACH_DECL(unichromefb, sizeof(struct unichromefb_softc),
    207     unichromefb_match, unichromefb_attach, NULL, NULL);
    208 
    209 static int
    210 unichromefb_match(struct device *parent, struct cfdata *match, void *opaque)
    211 {
    212 	struct pci_attach_args *pa;
    213 
    214 	pa = (struct pci_attach_args *)opaque;
    215 
    216 	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
    217 	    PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
    218 		return 0;
    219 
    220 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
    221 		return 0;
    222 
    223 	switch (PCI_PRODUCT(pa->pa_id)) {
    224 	case PCI_PRODUCT_VIATECH_VT3314_IG:
    225 		return 10;	/* beat vga(4) */
    226 	}
    227 
    228 	return 0;
    229 }
    230 
    231 static void
    232 unichromefb_attach(struct device *parent, struct device *self, void *opaque)
    233 {
    234 	struct unichromefb_softc *sc;
    235 	struct pci_attach_args *pa;
    236 	struct rasops_info *ri;
    237 	struct wsemuldisplaydev_attach_args aa;
    238 	bus_space_handle_t ap_memh;
    239 	uint8_t val;
    240 	bus_addr_t mmiobase;
    241 	bus_size_t mmiosize;
    242 	long defattr;
    243 
    244 	sc = (struct unichromefb_softc *)self;
    245 	pa = (struct pci_attach_args *)opaque;
    246 
    247 	sc->sc_width = UNICHROMEFB_WIDTH;
    248 	sc->sc_height = UNICHROMEFB_HEIGHT;
    249 	sc->sc_depth = UNICHROMEFB_DEPTH;
    250 	sc->sc_stride = sc->sc_width * (sc->sc_depth / 8);
    251 
    252 	sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
    253 
    254 	sc->sc_iot = pa->pa_iot;
    255 	if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) {
    256 		aprint_error(": failed to map I/O registers\n");
    257 		return;
    258 	}
    259 
    260 	val = uni_rd(sc, VIASR, SR30);
    261 	sc->sc_fbaddr = val << 24;
    262 	val = uni_rd(sc, VIASR, SR39);
    263 	sc->sc_fbsize = val * (4*1024*1024);
    264 	if (sc->sc_fbsize < 16*1024*1024 || sc->sc_fbsize > 64*1024*1024)
    265 		sc->sc_fbsize = 16*1024*1024;
    266 	sc->sc_memt = pa->pa_memt;
    267 	if (bus_space_map(sc->sc_memt, sc->sc_fbaddr, sc->sc_fbsize,
    268 	    BUS_SPACE_MAP_LINEAR, &ap_memh)) {
    269 		aprint_error(": failed to map aperture at 0x%08x/0x%x\n",
    270 		    sc->sc_fbaddr, sc->sc_fbsize);
    271 		return;
    272 	}
    273 	sc->sc_fbbase = (caddr_t)bus_space_vaddr(sc->sc_memt, ap_memh);
    274 
    275 	if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0,
    276 	    &sc->sc_memt, &sc->sc_memh, &mmiobase, &mmiosize)) {
    277 		sc->sc_accel = 0;
    278 		aprint_error(": failed to map MMIO registers\n");
    279 	} else {
    280 		sc->sc_accel = 1;
    281 	}
    282 
    283 	aprint_naive("\n");
    284 	aprint_normal(": VIA UniChrome frame buffer\n");
    285 
    286 	if (sc->sc_accel)
    287 		aprint_normal("%s: MMIO @0x%08x/0x%x\n",
    288 		    sc->sc_dev.dv_xname, (uint32_t)mmiobase, (uint32_t)mmiosize);
    289 
    290 	ri = &unichromefb_console_screen.scr_ri;
    291 	memset(ri, 0, sizeof(struct rasops_info));
    292 
    293 	vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen,
    294 	    &unichromefb_accessops);
    295 	sc->sc_vd.init_screen = unichromefb_init_screen;
    296 
    297 	uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth);
    298 
    299 	uni_init_dac(sc, IGA1);
    300 	if (sc->sc_accel) {
    301 		uni_init_accel(sc);
    302 		uni_fillrect(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
    303 	}
    304 
    305 	aprint_normal("%s: FB @0x%08x (%dx%dx%d)\n", sc->sc_dev.dv_xname,
    306 	       sc->sc_fbaddr, sc->sc_width, sc->sc_height, sc->sc_depth);
    307 
    308 	unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    309 	vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr);
    310 
    311 	unichromefb_stdscreen.ncols = ri->ri_cols;
    312 	unichromefb_stdscreen.nrows = ri->ri_rows;
    313 	unichromefb_stdscreen.textops = &ri->ri_ops;
    314 	unichromefb_stdscreen.capabilities = ri->ri_caps;
    315 	unichromefb_stdscreen.modecookie = NULL;
    316 
    317 	wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr);
    318 
    319 	aa.console = 1; /* XXX */
    320 	aa.scrdata = &unichromefb_screenlist;
    321 	aa.accessops = &unichromefb_accessops;
    322 	aa.accesscookie = &sc->sc_vd;
    323 
    324 	config_found(self, &aa, wsemuldisplaydevprint);
    325 
    326 	return;
    327 }
    328 
    329 static int
    330 unichromefb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
    331 		  struct lwp *l)
    332 {
    333 	struct vcons_data *vd;
    334 	struct unichromefb_softc *sc;
    335 	struct wsdisplay_fbinfo *fb;
    336 
    337 	vd = (struct vcons_data *)v;
    338 	sc = (struct unichromefb_softc *)vd->cookie;
    339 
    340 	switch (cmd) {
    341 	case WSDISPLAYIO_GTYPE:
    342 		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
    343 		return 0;
    344 	case WSDISPLAYIO_GINFO:
    345 		if (vd->active != NULL) {
    346 			fb = (struct wsdisplay_fbinfo *)data;
    347 			fb->width = sc->sc_width;
    348 			fb->height = sc->sc_height;
    349 			fb->depth = sc->sc_depth;
    350 			fb->cmsize = 256;
    351 			return 0;
    352 		} else
    353 			return ENODEV;
    354 	case WSDISPLAYIO_GVIDEO:
    355 			return ENODEV;
    356 	case WSDISPLAYIO_SVIDEO:
    357 			return ENODEV;
    358 	case WSDISPLAYIO_GETCMAP:
    359 			return EINVAL;
    360 	case WSDISPLAYIO_PUTCMAP:
    361 			return EINVAL;
    362 	case WSDISPLAYIO_LINEBYTES:
    363 		*(u_int *)data = sc->sc_stride;
    364 		return 0;
    365 	case WSDISPLAYIO_SMODE:
    366 		{
    367 			int new_mode = *(int *)data;
    368 			if (new_mode != sc->sc_wsmode) {
    369 				sc->sc_wsmode = new_mode;
    370 				if (new_mode == WSDISPLAYIO_MODE_EMUL)
    371 					vcons_redraw_screen(vd->active);
    372 			}
    373 		}
    374 		return 0;
    375 	case WSDISPLAYIO_SSPLASH:
    376 		return ENODEV;
    377 	case WSDISPLAYIO_SPROGRESS:
    378 		return ENODEV;
    379 	}
    380 
    381 	return EPASSTHROUGH;
    382 }
    383 
    384 static paddr_t
    385 unichromefb_mmap(void *v, void *vs, off_t offset, int prot)
    386 {
    387 	return -1;
    388 }
    389 
    390 static void
    391 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing,
    392 			long *defattr)
    393 {
    394 	struct unichromefb_softc *sc;
    395 	struct rasops_info *ri;
    396 
    397 	sc = (struct unichromefb_softc *)c;
    398 	ri = &scr->scr_ri;
    399 	ri->ri_flg = RI_CENTER;
    400 	ri->ri_depth = sc->sc_depth;
    401 	ri->ri_width = sc->sc_width;
    402 	ri->ri_height = sc->sc_height;
    403 	ri->ri_stride = sc->sc_stride;
    404 	ri->ri_bits = sc->sc_fbbase;
    405 	if (existing)
    406 		ri->ri_flg |= RI_CLEAR;
    407 
    408 	switch (ri->ri_depth) {
    409 	case 32:
    410 		ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
    411 		ri->ri_rpos = 16;
    412 		ri->ri_gpos = 8;
    413 		ri->ri_bpos = 0;
    414 		break;
    415 	case 16:
    416 		ri->ri_rnum = 5;
    417 		ri->ri_gnum = 6;
    418 		ri->ri_bnum = 5;
    419 		ri->ri_rpos = 11;
    420 		ri->ri_gpos = 5;
    421 		ri->ri_bpos = 0;
    422 		break;
    423 	}
    424 
    425 	rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8);
    426 	ri->ri_caps = WSSCREEN_WSCOLORS;
    427 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
    428 	    sc->sc_width / ri->ri_font->fontwidth);
    429 
    430 	ri->ri_hw = scr;
    431 	if (sc->sc_accel) {
    432 		ri->ri_ops.copyrows = uni_copyrows;
    433 		ri->ri_ops.copycols = uni_copycols;
    434 		ri->ri_ops.eraserows = uni_eraserows;
    435 		ri->ri_ops.erasecols = uni_erasecols;
    436 #if notyet
    437 		ri->ri_ops.cursor = uni_cursor;
    438 		ri->ri_ops.putchar = uni_putchar;
    439 #endif
    440 	}
    441 
    442 	return;
    443 }
    444 
    445 /*
    446  * hardware access
    447  */
    448 static uint8_t
    449 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx)
    450 {
    451 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
    452 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
    453 }
    454 
    455 static void
    456 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val)
    457 {
    458 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
    459 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val);
    460 }
    461 
    462 static void
    463 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx,
    464     uint8_t val, uint8_t mask)
    465 {
    466 	uint8_t tmp;
    467 
    468 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
    469 	tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
    470 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1,
    471 	    ((val & mask) | (tmp & ~mask)));
    472 }
    473 
    474 static void
    475 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx,
    476     uint8_t r, uint8_t g, uint8_t b)
    477 {
    478 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx);
    479 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r);
    480 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g);
    481 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b);
    482 }
    483 
    484 static void
    485 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num)
    486 {
    487 	int i;
    488 	uint8_t tmp;
    489 
    490 	for (i = 0; i < num; i++) {
    491 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port,
    492 		    tbl[i].index);
    493 		tmp = bus_space_read_1(sc->sc_iot, sc->sc_iot,
    494 		    tbl[i].port + 1);
    495 		tmp = (tmp & (~tbl[i].mask)) | tbl[i].value;
    496 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1,
    497 		    tmp);
    498 	}
    499 }
    500 
    501 /*
    502  * helpers
    503  */
    504 static struct VideoModeTable *
    505 uni_getmode(int mode)
    506 {
    507 	int i;
    508 
    509 	for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
    510 		if (CLE266Modes[i].ModeIndex == mode)
    511 			return &CLE266Modes[i];
    512 
    513 	return NULL;
    514 }
    515 
    516 static void
    517 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp)
    518 {
    519 	struct VideoModeTable *vtbl;
    520 	struct crt_mode_table *crt;
    521 	int i;
    522 
    523 	/* XXX */
    524 	vtbl = uni_getmode(idx);
    525 	if (vtbl == NULL)
    526 		panic("%s: unsupported mode: %d\n", sc->sc_dev.dv_xname, idx);
    527 
    528 	crt = vtbl->crtc;
    529 
    530 	uni_screen_disable(sc);
    531 
    532 	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
    533 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0);
    534 
    535 	/* XXX assume CN900 for now */
    536 	uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs);
    537 
    538 	uni_crt_disable(sc);
    539 
    540 	/* Fill VPIT params */
    541 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc);
    542 
    543 	/* Write sequencer */
    544 	for (i = 1; i <= StdSR; i++) {
    545 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i);
    546 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1,
    547 		    VPIT.SR[i - 1]);
    548 	}
    549 
    550 	uni_set_start(sc);
    551 
    552 	uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
    553 
    554 	for (i = 0; i < StdGR; i++) {
    555 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i);
    556 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1,
    557 		    VPIT.GR[i]);
    558 	}
    559 
    560 	for (i = 0; i < StdAR; i++) {
    561 		(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
    562 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i);
    563 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR,
    564 		    VPIT.AR[i]);
    565 	}
    566 
    567 	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
    568 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20);
    569 
    570 	uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
    571 	/* set crt output path */
    572 	uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6);
    573 
    574 	uni_crt_enable(sc);
    575 	uni_screen_enable(sc);
    576 
    577 	return;
    578 }
    579 
    580 static void
    581 uni_crt_lock(struct unichromefb_softc *sc)
    582 {
    583 	uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7);
    584 }
    585 
    586 static void
    587 uni_crt_unlock(struct unichromefb_softc *sc)
    588 {
    589 	uni_wr_mask(sc, VIACR, CR11, 0, BIT7);
    590 	uni_wr_mask(sc, VIACR, CR47, 0, BIT0);
    591 }
    592 
    593 static void
    594 uni_crt_enable(struct unichromefb_softc *sc)
    595 {
    596 	uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4);
    597 }
    598 
    599 static void
    600 uni_crt_disable(struct unichromefb_softc *sc)
    601 {
    602 	uni_wr_mask(sc, VIACR, CR36, BIT5+BIT4, BIT5+BIT4);
    603 }
    604 
    605 static void
    606 uni_screen_enable(struct unichromefb_softc *sc)
    607 {
    608 	uni_wr_mask(sc, VIASR, SR01, 0, BIT5);
    609 }
    610 
    611 static void
    612 uni_screen_disable(struct unichromefb_softc *sc)
    613 {
    614 	uni_wr_mask(sc, VIASR, SR01, 0x20, BIT5);
    615 }
    616 
    617 static void
    618 uni_set_start(struct unichromefb_softc *sc)
    619 {
    620 	uni_crt_unlock(sc);
    621 
    622 	uni_wr(sc, VIACR, CR0C, 0x00);
    623 	uni_wr(sc, VIACR, CR0D, 0x00);
    624 	uni_wr(sc, VIACR, CR34, 0x00);
    625 	uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1);
    626 
    627 	uni_wr(sc, VIACR, CR62, 0x00);
    628 	uni_wr(sc, VIACR, CR63, 0x00);
    629 	uni_wr(sc, VIACR, CR64, 0x00);
    630 	uni_wr(sc, VIACR, CRA3, 0x00);
    631 
    632 	uni_crt_lock(sc);
    633 }
    634 
    635 static void
    636 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl,
    637     int mode, int bpp_byte, int iga)
    638 {
    639 	struct VideoModeTable *vtbl;
    640 	struct display_timing crtreg;
    641 	int i;
    642 	int index;
    643 	int haddr, vaddr;
    644 	uint8_t val;
    645 	uint32_t pll_d_n;
    646 
    647 	index = 0;
    648 
    649 	vtbl = uni_getmode(mode);
    650 	for (i = 0; i < vtbl->mode_array; i++) {
    651 		index = i;
    652 		if (ctbl[i].refresh_rate == 60)
    653 			break;
    654 	}
    655 
    656 	crtreg = ctbl[index].crtc;
    657 
    658 	haddr = crtreg.hor_addr;
    659 	vaddr = crtreg.ver_addr;
    660 
    661 	val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
    662 	if (ctbl[index].h_sync_polarity == NEGATIVE) {
    663 		if (ctbl[index].v_sync_polarity == NEGATIVE)
    664 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    665 			    (val & (~(BIT6+BIT7))) | (BIT6+BIT7));
    666 		else
    667 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    668 			    (val & (~(BIT6+BIT7))) | (BIT6));
    669 	} else {
    670 		if (ctbl[index].v_sync_polarity == NEGATIVE)
    671 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    672 			    (val & (~(BIT6+BIT7))) | (BIT7));
    673 		else
    674 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    675 			    (val & (~(BIT6+BIT7))));
    676 	}
    677 
    678 	if (iga == IGA1) {
    679 		uni_crt_unlock(sc);
    680 		uni_wr(sc, VIACR, CR09, 0x00);
    681 		uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6);
    682 		uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
    683 	}
    684 
    685 	uni_load_crtc(sc, crtreg, iga);
    686 	uni_fix_crtc(sc);
    687 	uni_crt_lock(sc);
    688 	uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
    689 
    690 	uni_load_offset(sc, haddr, bpp_byte, iga);
    691 	uni_load_fetchcnt(sc, haddr, bpp_byte, iga);
    692 	uni_load_fifo(sc, iga, haddr, vaddr);
    693 
    694 	uni_set_depth(sc, bpp_byte, iga);
    695 	pll_d_n = uni_get_clkval(sc, ctbl[index].clk);
    696 	uni_set_vclk(sc, pll_d_n, iga);
    697 }
    698 
    699 static void
    700 uni_load_crtc(struct unichromefb_softc *sc,
    701     struct display_timing device_timing, int iga)
    702 {
    703 	int regnum, val;
    704 	struct io_register *reg;
    705 	int i;
    706 
    707 	regnum = val = 0;
    708 	reg = NULL;
    709 
    710 	uni_crt_unlock(sc);
    711 
    712 	for (i = 0; i < 12; i++) {
    713 		switch (iga) {
    714 		case IGA1:
    715 			switch (i) {
    716 			case H_TOTAL_INDEX:
    717 				val = IGA1_HOR_TOTAL_FORMULA(
    718 				    device_timing.hor_total);
    719 				regnum = iga1_crtc_reg.hor_total.reg_num;
    720 				reg = iga1_crtc_reg.hor_total.reg;
    721 				break;
    722 			case H_ADDR_INDEX:
    723 				val = IGA1_HOR_ADDR_FORMULA(
    724 				    device_timing.hor_addr);
    725 				regnum = iga1_crtc_reg.hor_addr.reg_num;
    726 				reg = iga1_crtc_reg.hor_addr.reg;
    727 				break;
    728 			case H_BLANK_START_INDEX:
    729 				val = IGA1_HOR_BLANK_START_FORMULA(
    730 				    device_timing.hor_blank_start);
    731 				regnum = iga1_crtc_reg.hor_blank_start.reg_num;
    732 				reg = iga1_crtc_reg.hor_blank_start.reg;
    733 				break;
    734 			case H_BLANK_END_INDEX:
    735 				val = IGA1_HOR_BLANK_END_FORMULA(
    736 				    device_timing.hor_blank_start,
    737 				    device_timing.hor_blank_end);
    738 				regnum = iga1_crtc_reg.hor_blank_end.reg_num;
    739 				reg = iga1_crtc_reg.hor_blank_end.reg;
    740 				break;
    741 			case H_SYNC_START_INDEX:
    742 				val = IGA1_HOR_SYNC_START_FORMULA(
    743 				    device_timing.hor_sync_start);
    744 				regnum = iga1_crtc_reg.hor_sync_start.reg_num;
    745 				reg = iga1_crtc_reg.hor_sync_start.reg;
    746 				break;
    747 			case H_SYNC_END_INDEX:
    748 				val = IGA1_HOR_SYNC_END_FORMULA(
    749 				    device_timing.hor_sync_start,
    750 				    device_timing.hor_sync_end);
    751 				regnum = iga1_crtc_reg.hor_sync_end.reg_num;
    752 				reg = iga1_crtc_reg.hor_sync_end.reg;
    753 				break;
    754 			case V_TOTAL_INDEX:
    755 				val = IGA1_VER_TOTAL_FORMULA(
    756 				    device_timing.ver_total);
    757 				regnum = iga1_crtc_reg.ver_total.reg_num;
    758 				reg = iga1_crtc_reg.ver_total.reg;
    759 				break;
    760 			case V_ADDR_INDEX:
    761 				val = IGA1_VER_ADDR_FORMULA(
    762 				    device_timing.ver_addr);
    763 				regnum = iga1_crtc_reg.ver_addr.reg_num;
    764 				reg = iga1_crtc_reg.ver_addr.reg;
    765 				break;
    766 			case V_BLANK_START_INDEX:
    767 				val = IGA1_VER_BLANK_START_FORMULA(
    768 				    device_timing.ver_blank_start);
    769 				regnum = iga1_crtc_reg.ver_blank_start.reg_num;
    770 				reg = iga1_crtc_reg.ver_blank_start.reg;
    771 				break;
    772 			case V_BLANK_END_INDEX:
    773 				val = IGA1_VER_BLANK_END_FORMULA(
    774 				    device_timing.ver_blank_start,
    775 				    device_timing.ver_blank_end);
    776 				regnum = iga1_crtc_reg.ver_blank_end.reg_num;
    777 				reg = iga1_crtc_reg.ver_blank_end.reg;
    778 				break;
    779 			case V_SYNC_START_INDEX:
    780 				val = IGA1_VER_SYNC_START_FORMULA(
    781 				    device_timing.ver_sync_start);
    782 				regnum = iga1_crtc_reg.ver_sync_start.reg_num;
    783 				reg = iga1_crtc_reg.ver_sync_start.reg;
    784 				break;
    785 			case V_SYNC_END_INDEX:
    786 				val = IGA1_VER_SYNC_END_FORMULA(
    787 				    device_timing.ver_sync_start,
    788 				    device_timing.ver_sync_end);
    789 				regnum = iga1_crtc_reg.ver_sync_end.reg_num;
    790 				reg = iga1_crtc_reg.ver_sync_end.reg;
    791 				break;
    792 			default:
    793 				printf("%s: unknown index %d while setting up CRTC\n",
    794 				    sc->sc_dev.dv_xname, i);
    795 				break;
    796 			}
    797 			break;
    798 		case IGA2:
    799 			printf("%s: %s: IGA2 not supported\n",
    800 			    sc->sc_dev.dv_xname, __func__);
    801 			break;
    802 		}
    803 
    804 		uni_load_reg(sc, val, regnum, reg, VIACR);
    805 	}
    806 
    807 	uni_crt_lock(sc);
    808 }
    809 
    810 static void
    811 uni_load_reg(struct unichromefb_softc *sc, int timing, int regnum,
    812     struct io_register *reg, int type)
    813 {
    814 	int regmask, bitnum, data;
    815 	int i, j;
    816 	int shift_next_reg;
    817 	int startidx, endidx, cridx;
    818 	uint16_t getbit;
    819 
    820 	bitnum = 0;
    821 
    822 	for (i = 0; i < regnum; i++) {
    823 		regmask = data = 0;
    824 		startidx = reg[i].start_bit;
    825 		endidx = reg[i].end_bit;
    826 		cridx = reg[i].io_addr;
    827 
    828 		shift_next_reg = bitnum;
    829 
    830 		for (j = startidx; j <= endidx; j++) {
    831 			regmask = regmask | (BIT0 << j);
    832 			getbit = (timing & (BIT0 << bitnum));
    833 			data = data | ((getbit >> shift_next_reg) << startidx);
    834 			++bitnum;
    835 		}
    836 
    837 		if (type == VIACR)
    838 			uni_wr_mask(sc, VIACR, cridx, data, regmask);
    839 		else
    840 			uni_wr_mask(sc, VIASR, cridx, data, regmask);
    841 	}
    842 
    843 	return;
    844 }
    845 
    846 static void
    847 uni_fix_crtc(struct unichromefb_softc *sc)
    848 {
    849 	uni_wr_mask(sc, VIACR, CR03, 0x80, BIT7);
    850 	uni_wr(sc, VIACR, CR18, 0xff);
    851 	uni_wr_mask(sc, VIACR, CR07, 0x10, BIT4);
    852 	uni_wr_mask(sc, VIACR, CR09, 0x40, BIT6);
    853 	uni_wr_mask(sc, VIACR, CR35, 0x10, BIT4);
    854 	uni_wr_mask(sc, VIACR, CR33, 0x06, BIT0+BIT1+BIT2);
    855 	uni_wr(sc, VIACR, CR17, 0xe3);
    856 	uni_wr(sc, VIACR, CR08, 0x00);
    857 	uni_wr(sc, VIACR, CR14, 0x00);
    858 
    859 	return;
    860 }
    861 
    862 static void
    863 uni_load_offset(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
    864 {
    865 
    866 	switch (iga) {
    867 	case IGA1:
    868 		uni_load_reg(sc,
    869 		    IGA1_OFFSET_FORMULA(haddr, bpp),
    870 		    offset_reg.iga1_offset_reg.reg_num,
    871 		    offset_reg.iga1_offset_reg.reg,
    872 		    VIACR);
    873 		break;
    874 	default:
    875 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    876 		    __func__);
    877 		break;
    878 	}
    879 
    880 	return;
    881 }
    882 
    883 static void
    884 uni_load_fetchcnt(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
    885 {
    886 
    887 	switch (iga) {
    888 	case IGA1:
    889 		uni_load_reg(sc,
    890 		    IGA1_FETCH_COUNT_FORMULA(haddr, bpp),
    891 		    fetch_count_reg.iga1_fetch_count_reg.reg_num,
    892 		    fetch_count_reg.iga1_fetch_count_reg.reg,
    893 		    VIASR);
    894 		break;
    895 	default:
    896 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    897 		    __func__);
    898 		break;
    899 	}
    900 
    901 	return;
    902 }
    903 
    904 static void
    905 uni_load_fifo(struct unichromefb_softc *sc, int iga, int horact, int veract)
    906 {
    907 	int val, regnum;
    908 	struct io_register *reg;
    909 	int iga1_fifo_max_depth, iga1_fifo_threshold;
    910 	int iga1_fifo_high_threshold, iga1_display_queue_expire_num;
    911 
    912 	reg = NULL;
    913 	iga1_fifo_max_depth = iga1_fifo_threshold = 0;
    914 	iga1_fifo_high_threshold = iga1_display_queue_expire_num = 0;
    915 
    916 	switch (iga) {
    917 	case IGA1:
    918 		/* XXX if (type == CN900) { */
    919 		iga1_fifo_max_depth = CN900_IGA1_FIFO_MAX_DEPTH;
    920 		iga1_fifo_threshold = CN900_IGA1_FIFO_THRESHOLD;
    921 		iga1_fifo_high_threshold = CN900_IGA1_FIFO_HIGH_THRESHOLD;
    922 		if (horact > 1280 && veract > 1024)
    923 			iga1_display_queue_expire_num = 16;
    924 		else
    925 			iga1_display_queue_expire_num =
    926 			    CN900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
    927 		/* XXX } */
    928 
    929 		/* set display FIFO depth select */
    930 		val = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
    931 		regnum =
    932 		    display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
    933 		reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
    934 		uni_load_reg(sc, val, regnum, reg, VIASR);
    935 
    936 		/* set display FIFO threshold select */
    937 		val = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
    938 		regnum = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg_num;
    939 		reg = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg;
    940 		uni_load_reg(sc, val, regnum, reg, VIASR);
    941 
    942 		/* set display FIFO high threshold select */
    943 		val = IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
    944 		regnum = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg_num;
    945 		reg = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg;
    946 		uni_load_reg(sc, val, regnum, reg, VIASR);
    947 
    948 		/* set display queue expire num */
    949 		val = IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(iga1_display_queue_expire_num);
    950 		regnum = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg_num;
    951 		reg = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg;
    952 		uni_load_reg(sc, val, regnum, reg, VIASR);
    953 
    954 		break;
    955 	default:
    956 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    957 		    __func__);
    958 		break;
    959 	}
    960 
    961 	return;
    962 }
    963 
    964 static void
    965 uni_set_depth(struct unichromefb_softc *sc, int bpp, int iga)
    966 {
    967 	switch (iga) {
    968 	case IGA1:
    969 		switch (bpp) {
    970 		case MODE_32BPP:
    971 			uni_wr_mask(sc, VIASR, SR15, 0xae, 0xfe);
    972 			break;
    973 		case MODE_16BPP:
    974 			uni_wr_mask(sc, VIASR, SR15, 0xb6, 0xfe);
    975 			break;
    976 		case MODE_8BPP:
    977 			uni_wr_mask(sc, VIASR, SR15, 0x22, 0xfe);
    978 			break;
    979 		default:
    980 			printf("%s: %s: mode (%d) unsupported\n",
    981 			    sc->sc_dev.dv_xname, __func__, bpp);
    982 		}
    983 		break;
    984 	default:
    985 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    986 		    __func__);
    987 		break;
    988 	}
    989 }
    990 
    991 static uint32_t
    992 uni_get_clkval(struct unichromefb_softc *sc, int clk)
    993 {
    994 	int i;
    995 
    996 	for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
    997 		if (clk == pll_value[i].clk) {
    998 			/* XXX only CN900 supported for now */
    999 			return pll_value[i].k800_pll;
   1000 		}
   1001 	}
   1002 
   1003 	aprint_error("%s: can't find matching PLL value\n",
   1004 	    sc->sc_dev.dv_xname);
   1005 
   1006 	return 0;
   1007 }
   1008 
   1009 static void
   1010 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga)
   1011 {
   1012 	uint8_t val;
   1013 
   1014 	/* hardware reset on */
   1015 	uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
   1016 
   1017 	switch (iga) {
   1018 	case IGA1:
   1019 		/* XXX only CN900 is supported */
   1020 		uni_wr(sc, VIASR, SR44, clk / 0x10000);
   1021 		uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100);
   1022 		uni_wr(sc, VIASR, SR46, clk % 0x100);
   1023 		break;
   1024 	default:
   1025 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
   1026 		    __func__);
   1027 		break;
   1028 	}
   1029 
   1030 	/* hardware reset off */
   1031 	uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
   1032 
   1033 	/* reset pll */
   1034 	switch (iga) {
   1035 	case IGA1:
   1036 		uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1);
   1037 		uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1);
   1038 		break;
   1039 	}
   1040 
   1041 	/* good to go */
   1042 	val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
   1043 	val |= (BIT2+BIT3);
   1044 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val);
   1045 
   1046 	return;
   1047 }
   1048 
   1049 static void
   1050 uni_init_dac(struct unichromefb_softc *sc, int iga)
   1051 {
   1052 	int i;
   1053 
   1054 	/* XXX only IGA1 for now */
   1055 	uni_wr_mask(sc, VIASR, SR1A, 0x00, BIT0);
   1056 	uni_wr_mask(sc, VIASR, SR18, 0x00, BIT7+BIT6);
   1057 	for (i = 0; i < 256; i++)
   1058 		uni_wr_dac(sc, i,
   1059 		    palLUT_table[i].red, palLUT_table[i].green, palLUT_table[i].blue);
   1060 
   1061 	uni_wr_mask(sc, VIASR, SR18, 0xc0, BIT7+BIT6);
   1062 
   1063 	return;
   1064 }
   1065 
   1066 static void
   1067 uni_init_accel(struct unichromefb_softc *sc)
   1068 {
   1069 
   1070 	/* init 2D engine regs to reset 2D engine */
   1071 	MMIO_OUT32(VIA_REG_GEMODE, 0);
   1072 	MMIO_OUT32(VIA_REG_SRCPOS, 0);
   1073 	MMIO_OUT32(VIA_REG_DSTPOS, 0);
   1074 	MMIO_OUT32(VIA_REG_DIMENSION, 0);
   1075 	MMIO_OUT32(VIA_REG_PATADDR, 0);
   1076 	MMIO_OUT32(VIA_REG_FGCOLOR, 0);
   1077 	MMIO_OUT32(VIA_REG_BGCOLOR, 0);
   1078 	MMIO_OUT32(VIA_REG_CLIPTL, 0);
   1079 	MMIO_OUT32(VIA_REG_CLIPBR, 0);
   1080 	MMIO_OUT32(VIA_REG_OFFSET, 0);
   1081 	MMIO_OUT32(VIA_REG_KEYCONTROL, 0);
   1082 	MMIO_OUT32(VIA_REG_SRCBASE, 0);
   1083 	MMIO_OUT32(VIA_REG_DSTBASE, 0);
   1084 	MMIO_OUT32(VIA_REG_PITCH, 0);
   1085 	MMIO_OUT32(VIA_REG_MONOPAT1, 0);
   1086 
   1087 	/* init AGP and VQ registers */
   1088 	MMIO_OUT32(VIA_REG_TRANSET, 0x00100000);
   1089 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000);
   1090 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x00333004);
   1091 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x60000000);
   1092 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x61000000);
   1093 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x62000000);
   1094 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x63000000);
   1095 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x64000000);
   1096 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x7d000000);
   1097 
   1098 	MMIO_OUT32(VIA_REG_TRANSET, 0xfe020000);
   1099 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000);
   1100 
   1101 	/* disable VQ */
   1102 	MMIO_OUT32(VIA_REG_TRANSET, 0x00fe0000);
   1103 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000004);
   1104 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x40008c0f);
   1105 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x44000000);
   1106 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x45080c04);
   1107 	MMIO_OUT32(VIA_REG_TRANSPACE, 0x46800408);
   1108 
   1109 	uni_set_accel_depth(sc);
   1110 
   1111 	MMIO_OUT32(VIA_REG_SRCBASE, 0);
   1112 	MMIO_OUT32(VIA_REG_DSTBASE, 0);
   1113 
   1114 	MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
   1115 	    (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
   1116 	    (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
   1117 
   1118 	return;
   1119 }
   1120 
   1121 static void
   1122 uni_set_accel_depth(struct unichromefb_softc *sc)
   1123 {
   1124 	uint32_t gemode;
   1125 
   1126 	gemode = MMIO_IN32(0x04) & 0xfffffcff;
   1127 
   1128 	switch (sc->sc_depth) {
   1129 	case 32:
   1130 		gemode |= VIA_GEM_32bpp;
   1131 		break;
   1132 	case 16:
   1133 		gemode |= VIA_GEM_16bpp;
   1134 		break;
   1135 	default:
   1136 		gemode |= VIA_GEM_8bpp;
   1137 		break;
   1138 	}
   1139 
   1140 	/* set colour depth and pitch */
   1141 	MMIO_OUT32(VIA_REG_GEMODE, gemode);
   1142 
   1143 	return;
   1144 }
   1145 
   1146 static void
   1147 uni_wait_idle(struct unichromefb_softc *sc)
   1148 {
   1149 	int loop = 0;
   1150 
   1151 	while (!(MMIO_IN32(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) &&
   1152 	    (loop++ < MAXLOOP))
   1153 		;
   1154 
   1155 	while ((MMIO_IN32(VIA_REG_STATUS) &
   1156 	    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
   1157 	    (loop++ < MAXLOOP))
   1158 		;
   1159 
   1160 	if (loop >= MAXLOOP)
   1161 		aprint_error("%s: engine stall\n", sc->sc_dev.dv_xname);
   1162 
   1163 	return;
   1164 }
   1165 
   1166 static void
   1167 uni_fillrect(struct unichromefb_softc *sc, int x, int y, int width,
   1168     int height, int colour)
   1169 {
   1170 
   1171 	MMIO_OUT32(VIA_REG_SRCPOS, 0);
   1172 	MMIO_OUT32(VIA_REG_SRCBASE, 0);
   1173 	MMIO_OUT32(VIA_REG_DSTBASE, 0);
   1174 	MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
   1175 	    (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
   1176 	    (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
   1177 	MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x));
   1178 	MMIO_OUT32(VIA_REG_DIMENSION,
   1179 	    (((height - 1) << 16) | (width - 1)));
   1180 	MMIO_OUT32(VIA_REG_FGCOLOR, colour);
   1181 	MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0xf0 << 24));
   1182 
   1183 	/* XXX */
   1184 	uni_wait_idle(sc);
   1185 
   1186 	return;
   1187 }
   1188 
   1189 static void
   1190 uni_bitblit(struct unichromefb_softc *sc, int xs, int ys, int xd, int yd, int width, int height)
   1191 {
   1192 	uint32_t dir;
   1193 
   1194 	dir = 0;
   1195 
   1196 	if (ys < yd) {
   1197 		yd += height - 1;
   1198 		ys += height - 1;
   1199 		dir |= 0x8000;
   1200 	}
   1201 
   1202 	if (xs < xd) {
   1203 		xd += width - 1;
   1204 		xs += width - 1;
   1205 		dir |= 0x4000;
   1206 	}
   1207 
   1208 	MMIO_OUT32(VIA_REG_SRCBASE, 0);
   1209 	MMIO_OUT32(VIA_REG_DSTBASE, 0);
   1210 	MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
   1211 	    (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
   1212 	    (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
   1213 	MMIO_OUT32(VIA_REG_SRCPOS, ys << 16 | xs);
   1214 	MMIO_OUT32(VIA_REG_DSTPOS, yd << 16 | xd);
   1215 	MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1));
   1216 	MMIO_OUT32(VIA_REG_GECMD, (0x01 | dir | (0xcc << 24)));
   1217 
   1218 	/* XXX */
   1219 	uni_wait_idle(sc);
   1220 
   1221 	return;
   1222 }
   1223 
   1224 /*
   1225  * rasops glue
   1226  */
   1227 static void
   1228 uni_copycols(void *opaque, int row, int srccol, int dstcol, int ncols)
   1229 {
   1230 	struct rasops_info *ri;
   1231 	struct vcons_screen *scr;
   1232 	struct unichromefb_softc *sc;
   1233 	int xs, xd, y, width, height;
   1234 
   1235 	ri = (struct rasops_info *)opaque;
   1236 	scr = (struct vcons_screen *)ri->ri_hw;
   1237 	sc = (struct unichromefb_softc *)scr->scr_cookie;
   1238 
   1239 	if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
   1240 		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
   1241 		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
   1242 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
   1243 		width = ri->ri_font->fontwidth * ncols;
   1244 		height = ri->ri_font->fontheight;
   1245 		uni_bitblit(sc, xs, y, xd, y, width, height);
   1246 	}
   1247 
   1248 	return;
   1249 }
   1250 
   1251 static void
   1252 uni_copyrows(void *opaque, int srcrow, int dstrow, int nrows)
   1253 {
   1254 	struct rasops_info *ri;
   1255 	struct vcons_screen *scr;
   1256 	struct unichromefb_softc *sc;
   1257 	int x, ys, yd, width, height;
   1258 
   1259 	ri = (struct rasops_info *)opaque;
   1260 	scr = (struct vcons_screen *)ri->ri_hw;
   1261 	sc = (struct unichromefb_softc *)scr->scr_cookie;
   1262 
   1263 	if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
   1264 		x = ri->ri_xorigin;
   1265 		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
   1266 		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
   1267 		width = ri->ri_emuwidth;
   1268 		height = ri->ri_font->fontheight * nrows;
   1269 		uni_bitblit(sc, x, ys, x, yd, width, height);
   1270 	}
   1271 
   1272 	return;
   1273 }
   1274 
   1275 static void
   1276 uni_erasecols(void *opaque, int row, int startcol, int ncols, long fillattr)
   1277 {
   1278 	struct rasops_info *ri;
   1279 	struct vcons_screen *scr;
   1280 	struct unichromefb_softc *sc;
   1281 	int x, y, width, height, fg, bg, ul;
   1282 
   1283 	ri = (struct rasops_info *)opaque;
   1284 	scr = (struct vcons_screen *)ri->ri_hw;
   1285 	sc = (struct unichromefb_softc *)scr->scr_cookie;
   1286 
   1287 	if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
   1288 		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
   1289 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
   1290 		width = ri->ri_font->fontwidth * ncols;
   1291 		height = ri->ri_font->fontheight;
   1292 		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
   1293 		uni_fillrect(sc, x, y, width, height, ri->ri_devcmap[bg]);
   1294 	}
   1295 
   1296 	return;
   1297 }
   1298 
   1299 static void
   1300 uni_eraserows(void *opaque, int row, int nrows, long fillattr)
   1301 {
   1302 	struct rasops_info *ri;
   1303 	struct vcons_screen *scr;
   1304 	struct unichromefb_softc *sc;
   1305 	int x, y, width, height, fg, bg, ul;
   1306 
   1307 	ri = (struct rasops_info *)opaque;
   1308 	scr = (struct vcons_screen *)ri->ri_hw;
   1309 	sc = (struct unichromefb_softc *)scr->scr_cookie;
   1310 
   1311 	if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
   1312 		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
   1313 		if ((row == 0) && (nrows == ri->ri_rows)) {
   1314 			/* clear the whole screen */
   1315 			uni_fillrect(sc, 0, 0, ri->ri_width,
   1316 			    ri->ri_height, ri->ri_devcmap[bg]);
   1317 		} else {
   1318 			x = ri->ri_xorigin;
   1319 			y = ri->ri_yorigin + ri->ri_font->fontheight * row;
   1320 			width = ri->ri_emuwidth;
   1321 			height = ri->ri_font->fontheight * nrows;
   1322 			uni_fillrect(sc, x, y, width, height,
   1323 			    ri->ri_devcmap[bg]);
   1324 		}
   1325 	}
   1326 
   1327 	return;
   1328 }
   1329 
   1330 #if notyet
   1331 static void
   1332 uni_cursor(void *opaque, int on, int row, int col)
   1333 {
   1334 	struct rasops_info *ri;
   1335 	struct vcons_screen *scr;
   1336 	struct unichromefb_softc *sc;
   1337 
   1338 	ri = (struct rasops_info *)opaque;
   1339 	scr = (struct vcons_screen *)ri->ri_hw;
   1340 	sc = (struct unichromefb_softc *)scr->scr_cookie;
   1341 
   1342 	uni_wait_idle(sc);
   1343 
   1344 	if (sc->sc_cursor)
   1345 		sc->sc_cursor(opaque, on, row, col);
   1346 
   1347 	return;
   1348 }
   1349 
   1350 static void
   1351 uni_putchar(void *opaque, int row, int col, u_int c, long fillattr)
   1352 {
   1353 	struct rasops_info *ri;
   1354 	struct vcons_screen *scr;
   1355 	struct unichromefb_softc *sc;
   1356 
   1357 	ri = (struct rasops_info *)opaque;
   1358 	scr = (struct vcons_screen *)ri->ri_hw;
   1359 	sc = (struct unichromefb_softc *)scr->scr_cookie;
   1360 
   1361 	uni_wait_idle(sc);
   1362 
   1363 	if (sc->sc_putchar)
   1364 		sc->sc_putchar(opaque, row, col, c, fillattr);
   1365 
   1366 	return;
   1367 }
   1368 #endif
   1369 
   1370 /* XXX TODO */
   1371 int
   1372 unichromefb_cnattach(void)
   1373 {
   1374 	return 0;
   1375 }
   1376