Home | History | Annotate | Line # | Download | only in pci
unichromefb.c revision 1.1
      1 /* $NetBSD: unichromefb.c,v 1.1 2006/08/02 01:44:09 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.1 2006/08/02 01:44:09 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 
     84 /* XXX */
     85 #define UNICHROMEFB_DEPTH	32
     86 
     87 struct unichromefb_softc {
     88 	struct device		sc_dev;
     89 	struct vcons_data	sc_vd;
     90 	void *			sc_fbbase;
     91 	unsigned int		sc_fbaddr;
     92 	unsigned int		sc_fbsize;
     93 
     94 	bus_space_tag_t		sc_iot;
     95 	bus_space_handle_t	sc_ioh;
     96 
     97 	bus_space_tag_t		sc_memt;
     98 	bus_space_handle_t	sc_memh;
     99 
    100 	int			sc_width;
    101 	int			sc_height;
    102 	int			sc_depth;
    103 	int			sc_stride;
    104 
    105 	int			sc_wsmode;
    106 };
    107 
    108 static int unichromefb_match(struct device *, struct cfdata *, void *);
    109 static void unichromefb_attach(struct device *, struct device *, void *);
    110 
    111 /* XXX */
    112 int unichromefb_cnattach(void);
    113 
    114 struct wsscreen_descr unichromefb_stdscreen = {
    115 	"fb",
    116 	0, 0,
    117 	NULL,
    118 	8, 16,
    119 };
    120 
    121 static int	unichromefb_ioctl(void *, void *, u_long, caddr_t, int,
    122 				  struct lwp *);
    123 static paddr_t	unichromefb_mmap(void *, void *, off_t, int);
    124 
    125 static void	unichromefb_init_screen(void *, struct vcons_screen *,
    126 					int, long *);
    127 
    128 /* hardware access */
    129 static uint8_t	uni_rd(struct unichromefb_softc *, int, uint8_t);
    130 static void	uni_wr(struct unichromefb_softc *, int, uint8_t, uint8_t);
    131 static void	uni_wr_mask(struct unichromefb_softc *, int, uint8_t,
    132 			    uint8_t, uint8_t);
    133 static void	uni_wr_x(struct unichromefb_softc *, struct io_reg *, int);
    134 #if notyet
    135 static void	uni_wr_dac(struct unichromefb_softc *, uint8_t, uint8_t,
    136 			   uint8_t, uint8_t);
    137 #endif
    138 
    139 /* helpers */
    140 static struct VideoModeTable *	uni_getmode(int);
    141 static void	uni_setmode(struct unichromefb_softc *, int, int);
    142 static void	uni_crt_lock(struct unichromefb_softc *);
    143 static void	uni_crt_unlock(struct unichromefb_softc *);
    144 static void	uni_crt_enable(struct unichromefb_softc *);
    145 static void	uni_screen_enable(struct unichromefb_softc *);
    146 static void	uni_set_start(struct unichromefb_softc *);
    147 static void	uni_set_crtc(struct unichromefb_softc *,
    148 			     struct crt_mode_table *, int, int, int);
    149 static void	uni_load_crtc(struct unichromefb_softc *, struct display_timing,
    150 			      int);
    151 static void	uni_load_reg(struct unichromefb_softc *, int, int,
    152 			     struct io_register *, int);
    153 static void	uni_fix_crtc(struct unichromefb_softc *);
    154 static void	uni_load_offset(struct unichromefb_softc *, int, int, int);
    155 static void	uni_load_fetchcnt(struct unichromefb_softc *, int, int, int);
    156 static void	uni_load_fifo(struct unichromefb_softc *, int, int, int);
    157 static void	uni_set_depth(struct unichromefb_softc *, int, int);
    158 static uint32_t	uni_get_clkval(struct unichromefb_softc *, int);
    159 static void	uni_set_vclk(struct unichromefb_softc *, uint32_t, int);
    160 
    161 struct wsdisplay_accessops unichromefb_accessops = {
    162 	unichromefb_ioctl,
    163 	unichromefb_mmap,
    164 	NULL,
    165 	NULL,
    166 	NULL,
    167 	NULL,
    168 };
    169 
    170 static struct vcons_screen unichromefb_console_screen;
    171 
    172 const struct wsscreen_descr *_unichromefb_scrlist[] = {
    173 	&unichromefb_stdscreen,
    174 };
    175 
    176 struct wsscreen_list unichromefb_screenlist = {
    177 	sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *),
    178 	_unichromefb_scrlist
    179 };
    180 
    181 CFATTACH_DECL(unichromefb, sizeof(struct unichromefb_softc),
    182     unichromefb_match, unichromefb_attach, NULL, NULL);
    183 
    184 static int
    185 unichromefb_match(struct device *parent, struct cfdata *match, void *opaque)
    186 {
    187 	struct pci_attach_args *pa;
    188 
    189 	pa = (struct pci_attach_args *)opaque;
    190 
    191 	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
    192 	    PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
    193 		return 0;
    194 
    195 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
    196 		return 0;
    197 
    198 	switch (PCI_PRODUCT(pa->pa_id)) {
    199 	case PCI_PRODUCT_VIATECH_VT3314_IG:
    200 		return 10;	/* beat vga(4) */
    201 	}
    202 
    203 	return 0;
    204 }
    205 
    206 static void
    207 unichromefb_attach(struct device *parent, struct device *self, void *opaque)
    208 {
    209 	struct unichromefb_softc *sc;
    210 	struct pci_attach_args *pa;
    211 	struct rasops_info *ri;
    212 	struct wsemuldisplaydev_attach_args aa;
    213 	uint8_t val;
    214 	long defattr;
    215 
    216 	sc = (struct unichromefb_softc *)self;
    217 	pa = (struct pci_attach_args *)opaque;
    218 
    219 	/* XXX */
    220 	sc->sc_width = 640;
    221 	sc->sc_height = 480;
    222 	sc->sc_depth = UNICHROMEFB_DEPTH;
    223 	sc->sc_stride = sc->sc_width * (sc->sc_depth / 8);
    224 
    225 	sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
    226 
    227 	sc->sc_iot = pa->pa_iot;
    228 	if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) {
    229 		aprint_error(": failed to map I/O registers\n");
    230 		return;
    231 	}
    232 
    233 	val = uni_rd(sc, VIASR, SR30);
    234 	sc->sc_fbaddr = val << 24;
    235 	sc->sc_fbsize = sc->sc_width * sc->sc_height * (sc->sc_depth / 8);
    236 	sc->sc_memt = pa->pa_memt;
    237 	if (bus_space_map(sc->sc_memt, sc->sc_fbaddr, sc->sc_fbsize,
    238 	    BUS_SPACE_MAP_LINEAR, &sc->sc_memh)) {
    239 		aprint_error(": failed to map aperture at 0x%08x/0x%x\n",
    240 		    sc->sc_fbaddr, sc->sc_fbsize);
    241 		return;
    242 	}
    243 	sc->sc_fbbase = (caddr_t)bus_space_vaddr(sc->sc_memt, sc->sc_memh);
    244 	/*memset(sc->sc_fbbase, 0, sc->sc_fbsize);*/
    245 
    246 	aprint_naive("\n");
    247 	aprint_normal(": VIA UniChrome frame buffer\n");
    248 
    249 	ri = &unichromefb_console_screen.scr_ri;
    250 	memset(ri, 0, sizeof(struct rasops_info));
    251 
    252 	vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen,
    253 	    &unichromefb_accessops);
    254 	sc->sc_vd.init_screen = unichromefb_init_screen;
    255 
    256 	uni_setmode(sc, VIA_RES_640X480, sc->sc_depth);
    257 
    258 	aprint_normal("%s: fb %dx%dx%d @%p\n", sc->sc_dev.dv_xname,
    259 	       sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_fbbase);
    260 	delay(5*1000*1000);
    261 
    262 	unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    263 	vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr);
    264 
    265 	unichromefb_stdscreen.ncols = ri->ri_cols;
    266 	unichromefb_stdscreen.nrows = ri->ri_rows;
    267 	unichromefb_stdscreen.textops = &ri->ri_ops;
    268 	unichromefb_stdscreen.capabilities = ri->ri_caps;
    269 	unichromefb_stdscreen.modecookie = NULL;
    270 
    271 	wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr);
    272 
    273 	aa.console = 1; /* XXX */
    274 	aa.scrdata = &unichromefb_screenlist;
    275 	aa.accessops = &unichromefb_accessops;
    276 	aa.accesscookie = &sc->sc_vd;
    277 
    278 	config_found(self, &aa, wsemuldisplaydevprint);
    279 
    280 	return;
    281 }
    282 
    283 static int
    284 unichromefb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
    285 		  struct lwp *l)
    286 {
    287 	struct vcons_data *vd;
    288 	struct unichromefb_softc *sc;
    289 	struct wsdisplay_fbinfo *fb;
    290 
    291 	vd = (struct vcons_data *)v;
    292 	sc = (struct unichromefb_softc *)vd->cookie;
    293 
    294 	switch (cmd) {
    295 	case WSDISPLAYIO_GTYPE:
    296 		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
    297 		return 0;
    298 	case WSDISPLAYIO_GINFO:
    299 		if (vd->active != NULL) {
    300 			fb = (struct wsdisplay_fbinfo *)data;
    301 			fb->width = sc->sc_width;
    302 			fb->height = sc->sc_height;
    303 			fb->depth = sc->sc_depth;
    304 			fb->cmsize = 256;
    305 			return 0;
    306 		} else
    307 			return ENODEV;
    308 	case WSDISPLAYIO_GVIDEO:
    309 			return ENODEV;
    310 	case WSDISPLAYIO_SVIDEO:
    311 			return ENODEV;
    312 	case WSDISPLAYIO_GETCMAP:
    313 			return EINVAL;
    314 	case WSDISPLAYIO_PUTCMAP:
    315 			return EINVAL;
    316 	case WSDISPLAYIO_LINEBYTES:
    317 		*(u_int *)data = sc->sc_stride;
    318 		return 0;
    319 	case WSDISPLAYIO_SMODE:
    320 		{
    321 			int new_mode = *(int *)data;
    322 			if (new_mode != sc->sc_wsmode) {
    323 				sc->sc_wsmode = new_mode;
    324 				if (new_mode == WSDISPLAYIO_MODE_EMUL)
    325 					vcons_redraw_screen(vd->active);
    326 			}
    327 		}
    328 		return 0;
    329 	case WSDISPLAYIO_SSPLASH:
    330 		return ENODEV;
    331 	case WSDISPLAYIO_SPROGRESS:
    332 		return ENODEV;
    333 	}
    334 
    335 	return EPASSTHROUGH;
    336 }
    337 
    338 static paddr_t
    339 unichromefb_mmap(void *v, void *vs, off_t offset, int prot)
    340 {
    341 	return -1;
    342 }
    343 
    344 static void
    345 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing,
    346 			long *defattr)
    347 {
    348 	struct unichromefb_softc *sc;
    349 	struct rasops_info *ri;
    350 
    351 	sc = (struct unichromefb_softc *)c;
    352 	ri = &scr->scr_ri;
    353 	ri->ri_flg = RI_CENTER;
    354 	ri->ri_depth = sc->sc_depth;
    355 	ri->ri_width = sc->sc_width;
    356 	ri->ri_height = sc->sc_height;
    357 	ri->ri_stride = sc->sc_stride;
    358 	ri->ri_bits = sc->sc_fbbase;
    359 
    360 	ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
    361 	ri->ri_rpos = 16;
    362 	ri->ri_gpos = 8;
    363 	ri->ri_bpos = 0;
    364 
    365 	rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8);
    366 	ri->ri_caps = WSSCREEN_WSCOLORS;
    367 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
    368 	    sc->sc_width / ri->ri_font->fontwidth);
    369 
    370 	return;
    371 }
    372 
    373 /*
    374  * hardware access
    375  */
    376 static uint8_t
    377 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx)
    378 {
    379 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
    380 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
    381 }
    382 
    383 static void
    384 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val)
    385 {
    386 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
    387 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val);
    388 }
    389 
    390 static void
    391 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx,
    392     uint8_t val, uint8_t mask)
    393 {
    394 	uint8_t tmp;
    395 
    396 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
    397 	tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
    398 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1,
    399 	    ((val & mask) | (tmp & ~mask)));
    400 }
    401 
    402 #if notyet
    403 static void
    404 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx,
    405     uint8_t r, uint8_t g, uint8_t b)
    406 {
    407 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx);
    408 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r);
    409 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g);
    410 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b);
    411 }
    412 #endif
    413 
    414 static void
    415 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num)
    416 {
    417 	int i;
    418 	uint8_t tmp;
    419 
    420 	for (i = 0; i < num; i++) {
    421 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port,
    422 		    tbl[i].index);
    423 		tmp = bus_space_read_1(sc->sc_iot, sc->sc_iot,
    424 		    tbl[i].port + 1);
    425 		tmp = (tmp & (~tbl[i].mask)) | tbl[i].value;
    426 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1,
    427 		    tmp);
    428 	}
    429 }
    430 
    431 /*
    432  * helpers
    433  */
    434 static struct VideoModeTable *
    435 uni_getmode(int mode)
    436 {
    437 	int i;
    438 
    439 	for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
    440 		if (CLE266Modes[i].ModeIndex == mode)
    441 			return &CLE266Modes[i];
    442 
    443 	return NULL;
    444 }
    445 
    446 static void
    447 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp)
    448 {
    449 	struct VideoModeTable *vtbl;
    450 	struct crt_mode_table *crt;
    451 	int i;
    452 
    453 	/* XXX */
    454 	vtbl = uni_getmode(idx);
    455 	if (vtbl == NULL)
    456 		panic("%s: unsupported mode: %d\n", sc->sc_dev.dv_xname, idx);
    457 
    458 	crt = vtbl->crtc;
    459 
    460 	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
    461 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0);
    462 
    463 	/* XXX assume CN900 for now */
    464 	uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs);
    465 
    466 	/* Fill VPIT params */
    467 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc);
    468 
    469 	/* Write sequencer */
    470 	for (i = 1; i <= StdSR; i++) {
    471 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i);
    472 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1,
    473 		    VPIT.SR[i - 1]);
    474 	}
    475 
    476 	uni_set_start(sc);
    477 
    478 	uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
    479 
    480 	for (i = 0; i < StdGR; i++) {
    481 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i);
    482 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1,
    483 		    VPIT.GR[i]);
    484 	}
    485 
    486 	for (i = 0; i < StdAR; i++) {
    487 		(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
    488 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i);
    489 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR + 1,
    490 		    VPIT.AR[i]);
    491 	}
    492 
    493 	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
    494 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20);
    495 
    496 	uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
    497 	/* set crt output path */
    498 	uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6);
    499 
    500 	uni_crt_enable(sc);
    501 	uni_screen_enable(sc);
    502 
    503 	return;
    504 }
    505 
    506 static void
    507 uni_crt_lock(struct unichromefb_softc *sc)
    508 {
    509 	uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7);
    510 }
    511 
    512 static void
    513 uni_crt_unlock(struct unichromefb_softc *sc)
    514 {
    515 	uni_wr_mask(sc, VIACR, CR11, 0, BIT7);
    516 	uni_wr_mask(sc, VIACR, CR47, 0, BIT0);
    517 }
    518 
    519 static void
    520 uni_crt_enable(struct unichromefb_softc *sc)
    521 {
    522 	uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4);
    523 }
    524 
    525 static void
    526 uni_screen_enable(struct unichromefb_softc *sc)
    527 {
    528 	uni_wr_mask(sc, VIASR, SR01, 0, BIT5);
    529 }
    530 
    531 static void
    532 uni_set_start(struct unichromefb_softc *sc)
    533 {
    534 	uni_crt_unlock(sc);
    535 
    536 	uni_wr(sc, VIACR, CR0C, 0x00);
    537 	uni_wr(sc, VIACR, CR0D, 0x00);
    538 	uni_wr(sc, VIACR, CR34, 0x00);
    539 	uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1);
    540 
    541 	uni_wr(sc, VIACR, CR62, 0x00);
    542 	uni_wr(sc, VIACR, CR63, 0x00);
    543 	uni_wr(sc, VIACR, CR64, 0x00);
    544 	uni_wr(sc, VIACR, CRA3, 0x00);
    545 
    546 	uni_crt_lock(sc);
    547 }
    548 
    549 static void
    550 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl,
    551     int mode, int bpp_byte, int iga)
    552 {
    553 	struct VideoModeTable *vtbl;
    554 	struct display_timing crtreg;
    555 	int i;
    556 	int index;
    557 	int haddr, vaddr;
    558 	uint8_t val;
    559 	uint32_t pll_d_n;
    560 
    561 	index = 0;
    562 
    563 	vtbl = uni_getmode(mode);
    564 	for (i = 0; i < vtbl->mode_array; i++) {
    565 		index = i;
    566 		if (ctbl[i].refresh_rate == 60)
    567 			break;
    568 	}
    569 
    570 	crtreg = ctbl[index].crtc;
    571 
    572 	haddr = crtreg.hor_addr;
    573 	vaddr = crtreg.ver_addr;
    574 
    575 	val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
    576 	if (ctbl[index].h_sync_polarity == NEGATIVE) {
    577 		if (ctbl[index].v_sync_polarity == NEGATIVE)
    578 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    579 			    (val & (~(BIT6+BIT7))) | (BIT6+BIT7));
    580 		else
    581 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    582 			    (val & (~(BIT6+BIT7))) | (BIT6));
    583 	} else {
    584 		if (ctbl[index].v_sync_polarity == NEGATIVE)
    585 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    586 			    (val & (~(BIT6+BIT7))) | (BIT7));
    587 		else
    588 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
    589 			    (val & (~(BIT6+BIT7))));
    590 	}
    591 
    592 	if (iga == IGA1) {
    593 		uni_crt_unlock(sc);
    594 		uni_wr(sc, VIACR, CR09, 0x00);
    595 		uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6);
    596 		uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
    597 	}
    598 
    599 	uni_load_crtc(sc, crtreg, iga);
    600 	uni_fix_crtc(sc);
    601 	uni_crt_lock(sc);
    602 	uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
    603 
    604 	uni_load_offset(sc, haddr, bpp_byte, iga);
    605 	uni_load_fetchcnt(sc, haddr, bpp_byte, iga);
    606 	uni_load_fifo(sc, iga, haddr, vaddr);
    607 
    608 	uni_set_depth(sc, bpp_byte, iga);
    609 	pll_d_n = uni_get_clkval(sc, ctbl[index].clk);
    610 	uni_set_vclk(sc, pll_d_n, iga);
    611 }
    612 
    613 static void
    614 uni_load_crtc(struct unichromefb_softc *sc,
    615     struct display_timing device_timing, int iga)
    616 {
    617 	int regnum, val;
    618 	struct io_register *reg;
    619 	int i;
    620 
    621 	regnum = val = 0;
    622 	reg = NULL;
    623 
    624 	uni_crt_unlock(sc);
    625 
    626 	for (i = 0; i < 12; i++) {
    627 		switch (iga) {
    628 		case IGA1:
    629 			switch (i) {
    630 			case H_TOTAL_INDEX:
    631 				val = IGA1_HOR_TOTAL_FORMULA(
    632 				    device_timing.hor_total);
    633 				regnum = iga1_crtc_reg.hor_total.reg_num;
    634 				reg = iga1_crtc_reg.hor_total.reg;
    635 				break;
    636 			case H_ADDR_INDEX:
    637 				val = IGA1_HOR_ADDR_FORMULA(
    638 				    device_timing.hor_addr);
    639 				regnum = iga1_crtc_reg.hor_addr.reg_num;
    640 				reg = iga1_crtc_reg.hor_addr.reg;
    641 				break;
    642 			case H_BLANK_START_INDEX:
    643 				val = IGA1_HOR_BLANK_START_FORMULA(
    644 				    device_timing.hor_blank_start);
    645 				regnum = iga1_crtc_reg.hor_blank_start.reg_num;
    646 				reg = iga1_crtc_reg.hor_blank_start.reg;
    647 				break;
    648 			case H_BLANK_END_INDEX:
    649 				val = IGA1_HOR_BLANK_END_FORMULA(
    650 				    device_timing.hor_blank_start,
    651 				    device_timing.hor_blank_end);
    652 				regnum = iga1_crtc_reg.hor_blank_end.reg_num;
    653 				reg = iga1_crtc_reg.hor_blank_end.reg;
    654 				break;
    655 			case H_SYNC_START_INDEX:
    656 				val = IGA1_HOR_SYNC_START_FORMULA(
    657 				    device_timing.hor_sync_start);
    658 				regnum = iga1_crtc_reg.hor_sync_start.reg_num;
    659 				reg = iga1_crtc_reg.hor_sync_start.reg;
    660 				break;
    661 			case H_SYNC_END_INDEX:
    662 				val = IGA1_HOR_SYNC_END_FORMULA(
    663 				    device_timing.hor_sync_start,
    664 				    device_timing.hor_sync_end);
    665 				regnum = iga1_crtc_reg.hor_sync_end.reg_num;
    666 				reg = iga1_crtc_reg.hor_sync_end.reg;
    667 				break;
    668 			case V_TOTAL_INDEX:
    669 				val = IGA1_VER_TOTAL_FORMULA(
    670 				    device_timing.ver_total);
    671 				regnum = iga1_crtc_reg.ver_total.reg_num;
    672 				reg = iga1_crtc_reg.ver_total.reg;
    673 				break;
    674 			case V_ADDR_INDEX:
    675 				val = IGA1_VER_ADDR_FORMULA(
    676 				    device_timing.ver_addr);
    677 				regnum = iga1_crtc_reg.ver_addr.reg_num;
    678 				reg = iga1_crtc_reg.ver_addr.reg;
    679 				break;
    680 			case V_BLANK_START_INDEX:
    681 				val = IGA1_VER_BLANK_START_FORMULA(
    682 				    device_timing.ver_blank_start);
    683 				regnum = iga1_crtc_reg.ver_blank_start.reg_num;
    684 				reg = iga1_crtc_reg.ver_blank_start.reg;
    685 				break;
    686 			case V_BLANK_END_INDEX:
    687 				val = IGA1_VER_BLANK_END_FORMULA(
    688 				    device_timing.ver_blank_start,
    689 				    device_timing.ver_blank_end);
    690 				regnum = iga1_crtc_reg.ver_blank_end.reg_num;
    691 				reg = iga1_crtc_reg.ver_blank_end.reg;
    692 				break;
    693 			case V_SYNC_START_INDEX:
    694 				val = IGA1_VER_SYNC_START_FORMULA(
    695 				    device_timing.ver_sync_start);
    696 				regnum = iga1_crtc_reg.ver_sync_start.reg_num;
    697 				reg = iga1_crtc_reg.ver_sync_start.reg;
    698 				break;
    699 			case V_SYNC_END_INDEX:
    700 				val = IGA1_VER_SYNC_END_FORMULA(
    701 				    device_timing.ver_sync_start,
    702 				    device_timing.ver_sync_end);
    703 				regnum = iga1_crtc_reg.ver_sync_end.reg_num;
    704 				reg = iga1_crtc_reg.ver_sync_end.reg;
    705 				break;
    706 			}
    707 			break;
    708 		case IGA2:
    709 			printf("%s: %s: IGA2 not supported\n",
    710 			    sc->sc_dev.dv_xname, __func__);
    711 			break;
    712 		}
    713 
    714 		uni_load_reg(sc, val, regnum, reg, VIACR);
    715 	}
    716 
    717 	uni_crt_lock(sc);
    718 }
    719 
    720 static void
    721 uni_load_reg(struct unichromefb_softc *sc, int timing, int regnum,
    722     struct io_register *reg, int type)
    723 {
    724 	int regmask, bitnum, data;
    725 	int i, j;
    726 	int shift_next_reg;
    727 	int startidx, endidx, cridx;
    728 	uint16_t getbit;
    729 
    730 	bitnum = 0;
    731 
    732 	for (i = 0; i < regnum; i++) {
    733 		regmask = data = 0;
    734 		startidx = reg[i].start_bit;
    735 		endidx = reg[i].end_bit;
    736 		cridx = reg[i].io_addr;
    737 
    738 		shift_next_reg = bitnum;
    739 
    740 		for (j = startidx; j <= endidx; j++) {
    741 			regmask = regmask | (BIT0 << j);
    742 			getbit = (timing & (BIT0 << bitnum));
    743 			data = data | ((getbit >> shift_next_reg) << startidx);
    744 			++bitnum;
    745 		}
    746 
    747 		if (type == VIACR)
    748 			uni_wr_mask(sc, VIACR, cridx, data, regmask);
    749 		else
    750 			uni_wr_mask(sc, VIASR, cridx, data, regmask);
    751 	}
    752 
    753 	return;
    754 }
    755 
    756 static void
    757 uni_fix_crtc(struct unichromefb_softc *sc)
    758 {
    759 	uni_wr_mask(sc, VIACR, CR03, 0x80, BIT7);
    760 	uni_wr(sc, VIACR, CR18, 0xff);
    761 	uni_wr_mask(sc, VIACR, CR07, 0x10, BIT4);
    762 	uni_wr_mask(sc, VIACR, CR09, 0x40, BIT6);
    763 	uni_wr_mask(sc, VIACR, CR35, 0x10, BIT4);
    764 	uni_wr_mask(sc, VIACR, CR33, 0x06, BIT0+BIT1+BIT2);
    765 	uni_wr(sc, VIACR, CR17, 0xe3);
    766 	uni_wr(sc, VIACR, CR08, 0x00);
    767 	uni_wr(sc, VIACR, CR14, 0x00);
    768 
    769 	return;
    770 }
    771 
    772 static void
    773 uni_load_offset(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
    774 {
    775 
    776 	switch (iga) {
    777 	case IGA1:
    778 		uni_load_reg(sc,
    779 		    IGA1_OFFSET_FORMULA(haddr, bpp),
    780 		    offset_reg.iga1_offset_reg.reg_num,
    781 		    offset_reg.iga1_offset_reg.reg,
    782 		    VIACR);
    783 		break;
    784 	default:
    785 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    786 		    __func__);
    787 		break;
    788 	}
    789 
    790 	return;
    791 }
    792 
    793 static void
    794 uni_load_fetchcnt(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
    795 {
    796 
    797 	switch (iga) {
    798 	case IGA1:
    799 		uni_load_reg(sc,
    800 		    IGA1_FETCH_COUNT_FORMULA(haddr, bpp),
    801 		    fetch_count_reg.iga1_fetch_count_reg.reg_num,
    802 		    fetch_count_reg.iga1_fetch_count_reg.reg,
    803 		    VIASR);
    804 		break;
    805 	default:
    806 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    807 		    __func__);
    808 		break;
    809 	}
    810 
    811 	return;
    812 }
    813 
    814 static void
    815 uni_load_fifo(struct unichromefb_softc *sc, int iga, int horact, int veract)
    816 {
    817 	int val, regnum;
    818 	struct io_register *reg;
    819 	int iga1_fifo_max_depth, iga1_fifo_threshold;
    820 	int iga1_fifo_high_threshold, iga1_display_queue_expire_num;
    821 
    822 	reg = NULL;
    823 	iga1_fifo_max_depth = iga1_fifo_threshold = 0;
    824 	iga1_fifo_high_threshold = iga1_display_queue_expire_num = 0;
    825 
    826 	switch (iga) {
    827 	case IGA1:
    828 		/* XXX if (type == CN900) { */
    829 		iga1_fifo_max_depth = CN900_IGA1_FIFO_MAX_DEPTH;
    830 		iga1_fifo_threshold = CN900_IGA1_FIFO_THRESHOLD;
    831 		iga1_fifo_high_threshold = CN900_IGA1_FIFO_HIGH_THRESHOLD;
    832 		if (horact > 1280 && veract > 1024)
    833 			iga1_display_queue_expire_num = 16;
    834 		else
    835 			iga1_display_queue_expire_num =
    836 			    CN900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
    837 		/* XXX } */
    838 
    839 		/* set display FIFO depth select */
    840 		val = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
    841 		regnum =
    842 		    display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
    843 		reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
    844 		uni_load_reg(sc, val, regnum, reg, VIASR);
    845 
    846 		/* set display FIFO threshold select */
    847 		val = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
    848 		regnum = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg_num;
    849 		reg = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg;
    850 		uni_load_reg(sc, val, regnum, reg, VIASR);
    851 
    852 		/* set display FIFO high threshold select */
    853 		val = IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
    854 		regnum = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg_num;
    855 		reg = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg;
    856 		uni_load_reg(sc, val, regnum, reg, VIASR);
    857 
    858 		/* set display queue expire num */
    859 		val = IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(iga1_display_queue_expire_num);
    860 		regnum = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg_num;
    861 		reg = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg;
    862 		uni_load_reg(sc, val, regnum, reg, VIASR);
    863 
    864 		break;
    865 	default:
    866 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    867 		    __func__);
    868 		break;
    869 	}
    870 
    871 	return;
    872 }
    873 
    874 static void
    875 uni_set_depth(struct unichromefb_softc *sc, int bpp, int iga)
    876 {
    877 	switch (iga) {
    878 	case IGA1:
    879 		switch (bpp) {
    880 		case MODE_32BPP:
    881 			uni_wr_mask(sc, VIASR, SR15, 0xae, 0xfe);
    882 			break;
    883 		case MODE_16BPP:
    884 			uni_wr_mask(sc, VIASR, SR15, 0xb6, 0xfe);
    885 			break;
    886 		case MODE_8BPP:
    887 			uni_wr_mask(sc, VIASR, SR15, 0x22, 0xfe);
    888 			break;
    889 		default:
    890 			printf("%s: %s: mode (%d) unsupported\n",
    891 			    sc->sc_dev.dv_xname, __func__, bpp);
    892 		}
    893 		break;
    894 	default:
    895 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    896 		    __func__);
    897 		break;
    898 	}
    899 }
    900 
    901 static uint32_t
    902 uni_get_clkval(struct unichromefb_softc *sc, int clk)
    903 {
    904 	int i;
    905 
    906 	for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
    907 		if (clk == pll_value[i].clk) {
    908 			/* XXX only CN900 supported for now */
    909 			return pll_value[i].k800_pll;
    910 		}
    911 	}
    912 
    913 	aprint_error("%s: can't find matching PLL value\n",
    914 	    sc->sc_dev.dv_xname);
    915 
    916 	return 0;
    917 }
    918 
    919 static void
    920 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga)
    921 {
    922 	uint8_t val;
    923 
    924 	/* hardware reset on */
    925 	uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
    926 
    927 	switch (iga) {
    928 	case IGA1:
    929 		/* XXX only CN900 is supported */
    930 		uni_wr(sc, VIASR, SR44, clk / 0x10000);
    931 		uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100);
    932 		uni_wr(sc, VIASR, SR46, clk % 0x100);
    933 		break;
    934 	default:
    935 		printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
    936 		    __func__);
    937 		break;
    938 	}
    939 
    940 	/* hardware reset off */
    941 	uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
    942 
    943 	/* reset pll */
    944 	switch (iga) {
    945 	case IGA1:
    946 		uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1);
    947 		uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1);
    948 		break;
    949 	}
    950 
    951 	/* good to go */
    952 	val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
    953 	val |= (BIT2+BIT3);
    954 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val);
    955 
    956 	return;
    957 }
    958 
    959 /* XXX */
    960 int
    961 unichromefb_cnattach(void)
    962 {
    963 	return 0;
    964 }
    965