Home | History | Annotate | Line # | Download | only in tx
tx3912video.c revision 1.16
      1 /*	$NetBSD: tx3912video.c,v 1.16 2000/06/26 04:55:43 simonb Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1999, 2000 UCHIYAMA Yasushi.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 #define TX3912VIDEO_DEBUG
     29 
     30 #include "opt_tx39_debug.h"
     31 #include "hpcfb.h"
     32 
     33 #include <sys/param.h>
     34 #include <sys/systm.h>
     35 #include <sys/device.h>
     36 #include <sys/extent.h>
     37 
     38 #include <sys/ioctl.h>
     39 #include <sys/buf.h>
     40 #include <vm/vm.h>
     41 
     42 #include <machine/bus.h>
     43 #include <machine/bootinfo.h>
     44 
     45 #include <hpcmips/tx/tx39var.h>
     46 #include <hpcmips/tx/tx3912videovar.h>
     47 #include <hpcmips/tx/tx3912videoreg.h>
     48 
     49 /* CLUT */
     50 #include <dev/wscons/wsdisplayvar.h>
     51 #include <dev/rasops/rasops.h>
     52 #include <arch/hpcmips/dev/video_subr.h>
     53 
     54 #include <dev/wscons/wsconsio.h>
     55 #include <arch/hpcmips/dev/hpcfbvar.h>
     56 #include <arch/hpcmips/dev/hpcfbio.h>
     57 
     58 struct tx3912video_softc {
     59 	struct device sc_dev;
     60 	struct hpcfb_fbconf sc_fbconf;
     61 	struct hpcfb_dspconf sc_dspconf;
     62 	struct video_chip *sc_chip;
     63 };
     64 
     65 /* TX3912 built-in video chip itself */
     66 static struct video_chip tx3912video_chip;
     67 
     68 void	tx3912video_framebuffer_init __P((struct video_chip *));
     69 int	tx3912video_framebuffer_alloc __P((struct video_chip *,
     70 					   paddr_t, paddr_t *));
     71 void	tx3912video_reset __P((struct video_chip *));
     72 void	tx3912video_resolution_init __P((struct video_chip *));
     73 
     74 int	tx3912video_match __P((struct device *, struct cfdata *, void *));
     75 void	tx3912video_attach __P((struct device *, struct device *, void *));
     76 int	tx3912video_print __P((void *, const char *));
     77 
     78 void	tx3912video_hpcfbinit __P((struct tx3912video_softc *));
     79 int	tx3912video_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
     80 paddr_t	tx3912video_mmap __P((void *, off_t, int));
     81 
     82 void	tx3912video_clut_init __P((struct tx3912video_softc *));
     83 void	tx3912video_clut_install __P((void *, struct rasops_info *));
     84 void	tx3912video_clut_get __P((struct tx3912video_softc *,
     85 				u_int32_t *, int, int));
     86 static int __get_color8 __P((int));
     87 static int __get_color4 __P((int));
     88 
     89 struct cfattach tx3912video_ca = {
     90 	sizeof(struct tx3912video_softc), tx3912video_match,
     91 	tx3912video_attach
     92 };
     93 
     94 struct hpcfb_accessops tx3912video_ha = {
     95 	tx3912video_ioctl, tx3912video_mmap, 0, 0, 0, 0,
     96 	tx3912video_clut_install
     97 };
     98 
     99 int
    100 tx3912video_match(parent, cf, aux)
    101 	struct device *parent;
    102 	struct cfdata *cf;
    103 	void *aux;
    104 {
    105 	return (1);
    106 }
    107 
    108 void
    109 tx3912video_attach(parent, self, aux)
    110 	struct device *parent;
    111 	struct device *self;
    112 	void *aux;
    113 {
    114 	struct tx3912video_softc *sc = (void *)self;
    115 	struct video_chip *chip;
    116 	const char *depth_print[] = {
    117 		[TX3912_VIDEOCTRL1_BITSEL_MONOCHROME] = "monochrome",
    118 		[TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE] = "2bit greyscale",
    119 		[TX3912_VIDEOCTRL1_BITSEL_4BITGREYSCALE] = "4bit greyscale",
    120 		[TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR] = "8bit color"
    121 	};
    122 	struct hpcfb_attach_args ha;
    123 	tx_chipset_tag_t tc;
    124 	txreg_t val;
    125 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
    126 
    127 	sc->sc_chip = chip = &tx3912video_chip;
    128 
    129 	/* print video module information */
    130 	printf(": %s, frame buffer 0x%08x-0x%08x\n",
    131 	       depth_print[(ffs(chip->vc_fbdepth) - 1) & 0x3],
    132 	       (unsigned)chip->vc_fbpaddr,
    133 	       (unsigned)(chip->vc_fbpaddr + chip->vc_fbsize));
    134 
    135 	/* don't inverse VDAT[3:0] signal */
    136 	tc = chip->vc_v;
    137 	val = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    138 	val &= ~TX3912_VIDEOCTRL1_INVVID;
    139 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, val);
    140 
    141 	/* install default CLUT */
    142 	tx3912video_clut_init(sc);
    143 
    144 	/* if serial console, power off video module */
    145 #ifndef TX3912VIDEO_DEBUG
    146 	if (!console) {
    147 		printf("%s: power off\n", sc->sc_dev.dv_xname);
    148 		val = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    149 		val &= ~(TX3912_VIDEOCTRL1_DISPON |
    150 			 TX3912_VIDEOCTRL1_ENVID);
    151 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, val);
    152 	}
    153 #endif /* TX3912VIDEO_DEBUG */
    154 
    155 #ifdef TX3912VIDEO_DEBUG
    156 	/* attach debug draw routine (debugging use) */
    157 	video_attach_drawfunc(sc->sc_chip);
    158 	tx_conf_register_video(tc, sc->sc_chip);
    159 #endif
    160 
    161 	/* Attach frame buffer device */
    162 	tx3912video_hpcfbinit(sc);
    163 
    164 	if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
    165 		panic("tx3912video_attach: can't init fb console");
    166 	}
    167 
    168 	ha.ha_console = console;
    169 	ha.ha_accessops = &tx3912video_ha;
    170 	ha.ha_accessctx = sc;
    171 	ha.ha_curfbconf = 0;
    172 	ha.ha_nfbconf = 1;
    173 	ha.ha_fbconflist = &sc->sc_fbconf;
    174 	ha.ha_curdspconf = 0;
    175 	ha.ha_ndspconf = 1;
    176 	ha.ha_dspconflist = &sc->sc_dspconf;
    177 
    178 	config_found(self, &ha, hpcfbprint);
    179 }
    180 
    181 void
    182 tx3912video_hpcfbinit(sc)
    183 	struct tx3912video_softc *sc;
    184 {
    185 	struct video_chip *chip = sc->sc_chip;
    186 	struct hpcfb_fbconf *fb = &sc->sc_fbconf;
    187 	vaddr_t fbvaddr = (vaddr_t)MIPS_PHYS_TO_KSEG1(chip->vc_fbpaddr);
    188 
    189 	memset(fb, 0, sizeof(struct hpcfb_fbconf));
    190 
    191 	fb->hf_conf_index	= 0;	/* configuration index		*/
    192 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
    193 	strncpy(fb->hf_name, "TX3912 built-in video", HPCFB_MAXNAMELEN);
    194 					/* frame buffer name		*/
    195 	strncpy(fb->hf_conf_name, "LCD", HPCFB_MAXNAMELEN);
    196 					/* configuration name		*/
    197 	fb->hf_height		= chip->vc_fbheight;
    198 	fb->hf_width		= chip->vc_fbwidth;
    199 	fb->hf_baseaddr		= mips_ptob(mips_btop(fbvaddr));
    200 	fb->hf_offset		= (u_long)fbvaddr - fb->hf_baseaddr;
    201 					/* frame buffer start offset   	*/
    202 	fb->hf_bytes_per_line	= (chip->vc_fbwidth * chip->vc_fbdepth)
    203 		/ NBBY;
    204 	fb->hf_nplanes		= 1;
    205 	fb->hf_bytes_per_plane	= chip->vc_fbheight * fb->hf_bytes_per_line;
    206 
    207 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
    208 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
    209 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
    210 
    211 	switch (chip->vc_fbdepth) {
    212 	default:
    213 		panic("tx3912video_hpcfbinit: not supported color depth\n");
    214 		/* NOTREACHED */
    215 	case 2:
    216 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
    217 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
    218 		fb->hf_pack_width = 8;
    219 		fb->hf_pixels_per_pack = 4;
    220 		fb->hf_pixel_width = 2;
    221 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
    222 		/* reserved for future use */
    223 		fb->hf_u.hf_gray.hf_flags = 0;
    224 		break;
    225 	case 8:
    226 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
    227 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
    228 		fb->hf_pack_width = 8;
    229 		fb->hf_pixels_per_pack = 1;
    230 		fb->hf_pixel_width = 8;
    231 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
    232 		/* reserved for future use */
    233 		fb->hf_u.hf_indexed.hf_flags = 0;
    234 		break;
    235 	}
    236 }
    237 
    238 int
    239 tx3912video_init(fb_start, fb_end)
    240 	paddr_t fb_start, *fb_end;
    241 {
    242 	struct video_chip *chip = &tx3912video_chip;
    243 	tx_chipset_tag_t tc;
    244 	txreg_t reg;
    245 	int fbdepth;
    246 	int error;
    247 
    248 	chip->vc_v = tc = tx_conf_get_tag();
    249 
    250 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    251 	fbdepth = 1 << (TX3912_VIDEOCTRL1_BITSEL(reg));
    252 
    253 	switch (fbdepth) {
    254 	case 2:
    255 		bootinfo->fb_type = BIFB_D2_M2L_0;
    256 		break;
    257 	case 4:
    258 		/* XXX should implement rasops4.c */
    259 		fbdepth = 2;
    260 		bootinfo->fb_type = BIFB_D2_M2L_0;
    261 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    262 		TX3912_VIDEOCTRL1_BITSEL_CLR(reg);
    263 		reg = TX3912_VIDEOCTRL1_BITSEL_SET(
    264 			reg, TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE);
    265 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    266 		break;
    267 	case 8:
    268 		bootinfo->fb_type = BIFB_D8_FF;
    269 		break;
    270 	}
    271 
    272 	chip->vc_fbdepth = fbdepth;
    273 	chip->vc_fbwidth = bootinfo->fb_width;
    274 	chip->vc_fbheight= bootinfo->fb_height;
    275 
    276 	/* Allocate framebuffer area */
    277 	error = tx3912video_framebuffer_alloc(chip, fb_start, fb_end);
    278 	if (error != 0)
    279 		return (1);
    280 
    281 #if notyet
    282 	tx3912video_resolution_init(chip);
    283 #else
    284 	/* Use Windows CE setting. */
    285 #endif
    286 	/* Set DMA transfer address to VID module */
    287 	tx3912video_framebuffer_init(chip);
    288 
    289 	/* Syncronize framebuffer addr to frame signal */
    290 	tx3912video_reset(chip);
    291 
    292 	bootinfo->fb_line_bytes = (chip->vc_fbwidth * fbdepth) / NBBY;
    293 	bootinfo->fb_addr = (void *)MIPS_PHYS_TO_KSEG1(chip->vc_fbpaddr);
    294 
    295 	return (0);
    296 }
    297 
    298  int
    299 tx3912video_framebuffer_alloc(chip, fb_start, fb_end)
    300 	struct video_chip *chip;
    301 	paddr_t fb_start, *fb_end; /* buffer allocation hint */
    302 {
    303 	struct extent_fixed ex_fixed[10];
    304 	struct extent *ex;
    305 	u_long addr, size;
    306 	int error;
    307 
    308 	/* calcurate frame buffer size */
    309 	size = (chip->vc_fbwidth * chip->vc_fbheight * chip->vc_fbdepth) /
    310 		NBBY;
    311 
    312 	/* extent V-RAM region */
    313 	ex = extent_create("Frame buffer address", fb_start, *fb_end,
    314 			   0, (caddr_t)ex_fixed, sizeof ex_fixed,
    315 			   EX_NOWAIT);
    316 	if (ex == 0)
    317 		return (1);
    318 
    319 	/* Allocate V-RAM area */
    320 	error = extent_alloc_subregion(ex, fb_start, fb_start + size - 1,
    321 				       size, TX3912_FRAMEBUFFER_ALIGNMENT,
    322 				       TX3912_FRAMEBUFFER_BOUNDARY,
    323 				       EX_FAST|EX_NOWAIT, &addr);
    324 	extent_destroy(ex);
    325 
    326 	if (error != 0) {
    327 		return (1);
    328 	}
    329 
    330 	chip->vc_fbpaddr = addr;
    331 	chip->vc_fbvaddr = MIPS_PHYS_TO_KSEG1(addr);
    332 	chip->vc_fbsize = size;
    333 
    334 	*fb_end = addr + size;
    335 
    336 	return (0);
    337 }
    338 
    339  void
    340 tx3912video_framebuffer_init(chip)
    341 	struct video_chip *chip;
    342 {
    343 	u_int32_t fb_addr, fb_size, vaddr, bank, base;
    344 	txreg_t reg;
    345 	tx_chipset_tag_t tc = chip->vc_v;
    346 
    347 	fb_addr = chip->vc_fbpaddr;
    348 	fb_size = chip->vc_fbsize;
    349 
    350 	/*  XXX currently I don't set DFVAL, so force DF signal toggled on
    351          *  XXX each frame. */
    352 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    353 	reg &= ~TX3912_VIDEOCTRL1_DFMODE;
    354 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    355 
    356 	/* Set DMA transfer start and end address */
    357 
    358 	bank = TX3912_VIDEOCTRL3_VIDBANK(fb_addr);
    359 	base = TX3912_VIDEOCTRL3_VIDBASEHI(fb_addr);
    360 	reg = TX3912_VIDEOCTRL3_VIDBANK_SET(0, bank);
    361 	/* Upper address counter */
    362 	reg = TX3912_VIDEOCTRL3_VIDBASEHI_SET(reg, base);
    363 	tx_conf_write(tc, TX3912_VIDEOCTRL3_REG, reg);
    364 
    365 	/* Lower address counter  */
    366 	base = TX3912_VIDEOCTRL4_VIDBASELO(fb_addr + fb_size);
    367 	reg = TX3912_VIDEOCTRL4_VIDBASELO_SET(0, base);
    368 
    369 	/* Set DF-signal rate */
    370 	reg = TX3912_VIDEOCTRL4_DFVAL_SET(reg, 0); /* XXX not yet*/
    371 
    372 	/* Set VIDDONE signal delay after FRAME signal */
    373 	/* XXX not yet*/
    374 	tx_conf_write(tc, TX3912_VIDEOCTRL4_REG, reg);
    375 
    376 	/* Clear frame buffer */
    377 	vaddr = MIPS_PHYS_TO_KSEG1(fb_addr);
    378 	memset((void*)vaddr, 0, fb_size);
    379 }
    380 
    381  void
    382 tx3912video_resolution_init(chip)
    383 	struct video_chip *chip;
    384 {
    385 	int h, v, split, bit8, horzval, lineval;
    386 	tx_chipset_tag_t tc = chip->vc_v;
    387 	txreg_t reg;
    388 	u_int32_t val;
    389 
    390 	h = chip->vc_fbwidth;
    391 	v = chip->vc_fbheight;
    392 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    393 	split = reg & TX3912_VIDEOCTRL1_DISPSPLIT;
    394 	bit8  = (TX3912_VIDEOCTRL1_BITSEL(reg) ==
    395 		 TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR);
    396 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    397 
    398 	if ((val == TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR) &&
    399 	    !split) {
    400 		/* (LCD horizontal pixels / 8bit) * RGB - 1 */
    401 		horzval = (h / 8) * 3 - 1;
    402 	} else {
    403 		horzval = h / 4 - 1;
    404 	}
    405 	lineval = (split ? v / 2 : v) - 1;
    406 
    407 	/* Video rate */
    408 	/* XXX
    409 	 *  probably This value should be determined from DFINT and LCDINT
    410 	 */
    411 	reg = TX3912_VIDEOCTRL2_VIDRATE_SET(0, horzval + 1);
    412 	/* Horizontal size of LCD */
    413 	reg = TX3912_VIDEOCTRL2_HORZVAL_SET(reg, horzval);
    414 	/* # of lines for the LCD */
    415 	reg = TX3912_VIDEOCTRL2_LINEVAL_SET(reg, lineval);
    416 
    417 	tx_conf_write(tc, TX3912_VIDEOCTRL2_REG, reg);
    418 }
    419 
    420 void
    421 tx3912video_reset(chip)
    422 	struct video_chip *chip;
    423 {
    424 	tx_chipset_tag_t tc = chip->vc_v;
    425 	txreg_t reg;
    426 
    427 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    428 
    429 	/* Disable video logic at end of this frame */
    430 	reg |= TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    431 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    432 
    433 	/* Wait for end of frame */
    434 	delay(30 * 1000);
    435 
    436 	/* Make sure to disable video logic */
    437 	reg &= ~TX3912_VIDEOCTRL1_ENVID;
    438 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    439 
    440 	delay(1000);
    441 
    442 	/* Enable video logic again */
    443 	reg &= ~TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    444 	reg |= TX3912_VIDEOCTRL1_ENVID;
    445 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    446 
    447 	delay(1000);
    448 }
    449 
    450 int
    451 tx3912video_ioctl(v, cmd, data, flag, p)
    452 	void *v;
    453 	u_long cmd;
    454 	caddr_t data;
    455 	int flag;
    456 	struct proc *p;
    457 {
    458 	struct tx3912video_softc *sc = (struct tx3912video_softc *)v;
    459 	struct hpcfb_fbconf *fbconf;
    460 	struct hpcfb_dspconf *dspconf;
    461 	struct wsdisplay_cmap *cmap;
    462 	u_int8_t *r, *g, *b;
    463 	u_int32_t *rgb;
    464 	int idx, cnt, error;
    465 
    466 	switch (cmd) {
    467 	case WSDISPLAYIO_GETCMAP:
    468 		cmap = (struct wsdisplay_cmap*)data;
    469 		cnt = cmap->count;
    470 		idx = cmap->index;
    471 
    472 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
    473 			sc->sc_fbconf.hf_pack_width != 8 ||
    474 			!LEGAL_CLUT_INDEX(idx) ||
    475 			!LEGAL_CLUT_INDEX(idx + cnt -1)) {
    476 			return (EINVAL);
    477 		}
    478 
    479 		if (!uvm_useracc(cmap->red, cnt, B_WRITE) ||
    480 		    !uvm_useracc(cmap->green, cnt, B_WRITE) ||
    481 		    !uvm_useracc(cmap->blue, cnt, B_WRITE)) {
    482 			return (EFAULT);
    483 		}
    484 
    485 		error = cmap_work_alloc(&r, &g, &b, &rgb, cnt);
    486 		if (error != 0) {
    487 			cmap_work_free(r, g, b, rgb);
    488 			return  (ENOMEM);
    489 		}
    490 		tx3912video_clut_get(sc, rgb, idx, cnt);
    491 		rgb24_decompose(rgb, r, g, b, cnt);
    492 
    493 		copyout(r, cmap->red, cnt);
    494 		copyout(g, cmap->green,cnt);
    495 		copyout(b, cmap->blue, cnt);
    496 
    497 		cmap_work_free(r, g, b, rgb);
    498 
    499 		return (0);
    500 
    501 	case WSDISPLAYIO_PUTCMAP:
    502 		/*
    503 		 * TX3912 can't change CLUT index. R:G:B = 3:3:2
    504 		 */
    505 		return (0);
    506 
    507 	case HPCFBIO_GCONF:
    508 		fbconf = (struct hpcfb_fbconf *)data;
    509 		if (fbconf->hf_conf_index != 0 &&
    510 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    511 			return (EINVAL);
    512 		}
    513 		*fbconf = sc->sc_fbconf;	/* structure assignment */
    514 		return (0);
    515 
    516 	case HPCFBIO_SCONF:
    517 		fbconf = (struct hpcfb_fbconf *)data;
    518 		if (fbconf->hf_conf_index != 0 &&
    519 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    520 			return (EINVAL);
    521 		}
    522 		/*
    523 		 * nothing to do because we have only one configration
    524 		 */
    525 		return (0);
    526 
    527 	case HPCFBIO_GDSPCONF:
    528 		dspconf = (struct hpcfb_dspconf *)data;
    529 		if ((dspconf->hd_unit_index != 0 &&
    530 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    531 		    (dspconf->hd_conf_index != 0 &&
    532 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    533 			return (EINVAL);
    534 		}
    535 		*dspconf = sc->sc_dspconf;	/* structure assignment */
    536 		return (0);
    537 
    538 	case HPCFBIO_SDSPCONF:
    539 		dspconf = (struct hpcfb_dspconf *)data;
    540 		if ((dspconf->hd_unit_index != 0 &&
    541 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    542 		    (dspconf->hd_conf_index != 0 &&
    543 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    544 			return (EINVAL);
    545 		}
    546 		/*
    547 		 * nothing to do
    548 		 * because we have only one unit and one configration
    549 		 */
    550 		return (0);
    551 
    552 	case HPCFBIO_GOP:
    553 	case HPCFBIO_SOP:
    554 		/* XXX not implemented yet */
    555 		return (EINVAL);
    556 	}
    557 
    558 	return (ENOTTY);
    559 }
    560 
    561 paddr_t
    562 tx3912video_mmap(ctx, offset, prot)
    563 	void *ctx;
    564 	off_t offset;
    565 	int prot;
    566 {
    567 	struct tx3912video_softc *sc = (struct tx3912video_softc *)ctx;
    568 
    569 	if (offset < 0 || (sc->sc_fbconf.hf_bytes_per_plane +
    570 			   sc->sc_fbconf.hf_offset) <  offset) {
    571 		return (-1);
    572 	}
    573 
    574 	return (mips_btop(sc->sc_chip->vc_fbpaddr + offset));
    575 }
    576 
    577 /*
    578  * CLUT staff
    579  */
    580 static const struct {
    581 	int mul, div;
    582 } dither_list [] = {
    583 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1]	= { 1, 1 },
    584 	[TX3912_VIDEO_DITHER_DUTYCYCLE_6_7]	= { 6, 7 },
    585 	[TX3912_VIDEO_DITHER_DUTYCYCLE_4_5]	= { 4, 5 },
    586 	[TX3912_VIDEO_DITHER_DUTYCYCLE_3_4]	= { 3, 4 },
    587 	[TX3912_VIDEO_DITHER_DUTYCYCLE_5_7]	= { 5, 7 },
    588 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_3]	= { 2, 3 },
    589 	[TX3912_VIDEO_DITHER_DUTYCYCLE_3_5]	= { 3, 5 },
    590 	[TX3912_VIDEO_DITHER_DUTYCYCLE_4_7]	= { 4, 7 },
    591 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_4]	= { 2, 4 },
    592 	[TX3912_VIDEO_DITHER_DUTYCYCLE_3_7]	= { 3, 7 },
    593 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_5]	= { 2, 5 },
    594 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1_3]	= { 1, 3 },
    595 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_7]	= { 2, 7 },
    596 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1_5]	= { 1, 5 },
    597 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1_7]	= { 1, 7 },
    598 	[TX3912_VIDEO_DITHER_DUTYCYCLE_0]	= { 0, 1 }
    599 }, *dlp;
    600 
    601 static const int dither_level8[8] = {
    602 	TX3912_VIDEO_DITHER_DUTYCYCLE_0,
    603 	TX3912_VIDEO_DITHER_DUTYCYCLE_2_7,
    604 	TX3912_VIDEO_DITHER_DUTYCYCLE_2_5,
    605 	TX3912_VIDEO_DITHER_DUTYCYCLE_2_4,
    606 	TX3912_VIDEO_DITHER_DUTYCYCLE_3_5,
    607 	TX3912_VIDEO_DITHER_DUTYCYCLE_5_7,
    608 	TX3912_VIDEO_DITHER_DUTYCYCLE_4_5,
    609 	TX3912_VIDEO_DITHER_DUTYCYCLE_1,
    610 };
    611 
    612 static const int dither_level4[4] = {
    613 	TX3912_VIDEO_DITHER_DUTYCYCLE_0,
    614 	TX3912_VIDEO_DITHER_DUTYCYCLE_1_3,
    615 	TX3912_VIDEO_DITHER_DUTYCYCLE_5_7,
    616 	TX3912_VIDEO_DITHER_DUTYCYCLE_1,
    617 };
    618 
    619 static int
    620 __get_color8(luti)
    621 	int luti;
    622 {
    623 	KASSERT(luti >=0 && luti < 8);
    624 	dlp = &dither_list[dither_level8[luti]];
    625 
    626 	return ((0xff * dlp->mul) / dlp->div);
    627 }
    628 
    629 static int
    630 __get_color4(luti)
    631 	int luti;
    632 {
    633 	KASSERT(luti >=0 && luti < 4);
    634 	dlp = &dither_list[dither_level4[luti]];
    635 
    636 	return ((0xff * dlp->mul) / dlp->div);
    637 }
    638 
    639 void
    640 tx3912video_clut_get(sc, rgb, beg, cnt)
    641 	struct tx3912video_softc *sc;
    642 	u_int32_t *rgb;
    643 	int beg, cnt;
    644 {
    645 	int i;
    646 
    647 	KASSERT(rgb);
    648 	KASSERT(LEGAL_CLUT_INDEX(beg));
    649 	KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1));
    650 
    651 	for (i = beg; i < beg + cnt; i++) {
    652 		*rgb++ =  RGB24(__get_color8((i >> 5) & 0x7),
    653 				__get_color8((i >> 2) & 0x7),
    654 				__get_color4(i & 0x3));
    655 	}
    656 }
    657 
    658 void
    659 tx3912video_clut_install(ctx, ri)
    660 	void *ctx;
    661 	struct rasops_info *ri;
    662 {
    663 	struct tx3912video_softc *sc = ctx;
    664 	const int system_cmap[0x10] = {
    665 		TX3912VIDEO_BLACK,
    666 		TX3912VIDEO_RED,
    667 		TX3912VIDEO_GREEN,
    668 		TX3912VIDEO_YELLOW,
    669 		TX3912VIDEO_BLUE,
    670 		TX3912VIDEO_MAGENTA,
    671 		TX3912VIDEO_CYAN,
    672 		TX3912VIDEO_WHITE,
    673 		TX3912VIDEO_DARK_BLACK,
    674 		TX3912VIDEO_DARK_RED,
    675 		TX3912VIDEO_DARK_GREEN,
    676 		TX3912VIDEO_DARK_YELLOW,
    677 		TX3912VIDEO_DARK_BLUE,
    678 		TX3912VIDEO_DARK_MAGENTA,
    679 		TX3912VIDEO_DARK_CYAN,
    680 		TX3912VIDEO_DARK_WHITE,
    681 	};
    682 
    683 	KASSERT(ri);
    684 
    685 	if (sc->sc_chip->vc_fbdepth == 8) {
    686 		/* XXX 2bit gray scale LUT not supported */
    687 		memcpy(ri->ri_devcmap, system_cmap, sizeof system_cmap);
    688 	}
    689 }
    690 
    691 void
    692 tx3912video_clut_init(sc)
    693 	struct tx3912video_softc *sc;
    694 {
    695 	tx_chipset_tag_t tc = sc->sc_chip->vc_v;
    696 
    697 	if (sc->sc_chip->vc_fbdepth != 8) {
    698 		return; /* XXX 2bit gray scale LUT not supported */
    699 	}
    700 
    701 	/*
    702 	 * time-based dithering pattern (TOSHIBA recommended pattern)
    703 	 */
    704 	/* 2/3, 1/3 */
    705 	tx_conf_write(tc, TX3912_VIDEOCTRL8_REG,
    706 		      TX3912_VIDEOCTRL8_PAT2_3_DEFAULT);
    707 	/* 3/4, 2/4 */
    708 	tx_conf_write(tc, TX3912_VIDEOCTRL9_REG,
    709 		      (TX3912_VIDEOCTRL9_PAT3_4_DEFAULT << 16) |
    710 		      TX3912_VIDEOCTRL9_PAT2_4_DEFAULT);
    711 	/* 4/5, 1/5 */
    712 	tx_conf_write(tc, TX3912_VIDEOCTRL10_REG,
    713 		      TX3912_VIDEOCTRL10_PAT4_5_DEFAULT);
    714 	/* 3/5, 2/5 */
    715 	tx_conf_write(tc, TX3912_VIDEOCTRL11_REG,
    716 		      TX3912_VIDEOCTRL11_PAT3_5_DEFAULT);
    717 	/* 6/7, 1/7 */
    718 	tx_conf_write(tc, TX3912_VIDEOCTRL12_REG,
    719 		      TX3912_VIDEOCTRL12_PAT6_7_DEFAULT);
    720 	/* 5/7, 2/7 */
    721 	tx_conf_write(tc, TX3912_VIDEOCTRL13_REG,
    722 		      TX3912_VIDEOCTRL13_PAT5_7_DEFAULT);
    723 	/* 4/7, 3/7 */
    724 	tx_conf_write(tc, TX3912_VIDEOCTRL14_REG,
    725 		      TX3912_VIDEOCTRL14_PAT4_7_DEFAULT);
    726 
    727 	/*
    728 	 * dither-pattern look-up table. (selected by uch)
    729 	 */
    730 	/* red */
    731 	tx_conf_write(tc, TX3912_VIDEOCTRL5_REG,
    732 		      (dither_level8[7] << 28) |
    733 		      (dither_level8[6] << 24) |
    734 		      (dither_level8[5] << 20) |
    735 		      (dither_level8[4] << 16) |
    736 		      (dither_level8[3] << 12) |
    737 		      (dither_level8[2] << 8) |
    738 		      (dither_level8[1] << 4) |
    739 		      (dither_level8[0] << 0));
    740 	/* green */
    741 	tx_conf_write(tc, TX3912_VIDEOCTRL6_REG,
    742 		      (dither_level8[7] << 28) |
    743 		      (dither_level8[6] << 24) |
    744 		      (dither_level8[5] << 20) |
    745 		      (dither_level8[4] << 16) |
    746 		      (dither_level8[3] << 12) |
    747 		      (dither_level8[2] << 8) |
    748 		      (dither_level8[1] << 4) |
    749 		      (dither_level8[0] << 0));
    750 	/* blue (2bit gray scale also use this look-up table) */
    751 	tx_conf_write(tc, TX3912_VIDEOCTRL7_REG,
    752 		      (dither_level4[3] << 12) |
    753 		      (dither_level4[2] << 8) |
    754 		      (dither_level4[1] << 4) |
    755 		      (dither_level4[0] << 0));
    756 
    757 	tx3912video_reset(sc->sc_chip);
    758 }
    759