tx3912video.c revision 1.12       1 /*	$NetBSD: tx3912video.c,v 1.12 2000/05/08 21:57:58 uch 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 static struct tx3912video_chip {
     59 	tx_chipset_tag_t vc_tc;
     60 
     61 	paddr_t vc_fbaddr;
     62 	size_t vc_fbsize;
     63 	int vc_fbdepth;
     64 	int vc_fbwidth;
     65 	int vc_fbheight;
     66 
     67 	void (*vc_drawline) __P((int, int, int, int)); /* for debug */
     68 	void (*vc_drawdot) __P((int, int)); /* for debug */
     69 } tx3912video_chip;
     70 
     71 struct tx3912video_softc {
     72 	struct device sc_dev;
     73 	struct hpcfb_fbconf sc_fbconf;
     74 	struct hpcfb_dspconf sc_dspconf;
     75 	struct tx3912video_chip *sc_chip;
     76 };
     77 
     78 void	tx3912video_framebuffer_init __P((struct tx3912video_chip *));
     79 int	tx3912video_framebuffer_alloc __P((struct tx3912video_chip *, paddr_t,
     80 					paddr_t *));
     81 void	tx3912video_reset __P((struct tx3912video_chip *));
     82 void	tx3912video_resolution_init __P((struct tx3912video_chip *));
     83 
     84 int	tx3912video_match __P((struct device *, struct cfdata *, void *));
     85 void	tx3912video_attach __P((struct device *, struct device *, void *));
     86 int	tx3912video_print __P((void *, const char *));
     87 
     88 void	tx3912video_hpcfbinit __P((struct tx3912video_softc *));
     89 int	tx3912video_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
     90 int	tx3912video_mmap __P((void *, off_t, int));
     91 
     92 void	tx3912video_clut_init __P((struct tx3912video_softc *));
     93 void	tx3912video_clut_install __P((void *, struct rasops_info *));
     94 void	tx3912video_clut_get __P((struct tx3912video_softc *,
     95 				u_int32_t *, int, int));
     96 static int __get_color8 __P((int));
     97 static int __get_color4 __P((int));
     98 
     99 struct cfattach tx3912video_ca = {
    100 	sizeof(struct tx3912video_softc), tx3912video_match,
    101 	tx3912video_attach
    102 };
    103 
    104 struct hpcfb_accessops tx3912video_ha = {
    105 	tx3912video_ioctl, tx3912video_mmap, 0, 0, 0, 0,
    106 	tx3912video_clut_install
    107 };
    108 
    109 void	__tx3912video_attach_drawfunc __P((struct tx3912video_chip*));
    110 
    111 int
    112 tx3912video_match(parent, cf, aux)
    113 	struct device *parent;
    114 	struct cfdata *cf;
    115 	void *aux;
    116 {
    117 	return (1);
    118 }
    119 
    120 void
    121 tx3912video_attach(parent, self, aux)
    122 	struct device *parent;
    123 	struct device *self;
    124 	void *aux;
    125 {
    126 	struct tx3912video_softc *sc = (void *)self;
    127 	struct tx3912video_chip *chip;
    128 	const char *depth_print[] = {
    129 		[TX3912_VIDEOCTRL1_BITSEL_MONOCHROME] = "monochrome",
    130 		[TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE] = "2bit greyscale",
    131 		[TX3912_VIDEOCTRL1_BITSEL_4BITGREYSCALE] = "4bit greyscale",
    132 		[TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR] = "8bit color"
    133 	};
    134 	struct hpcfb_attach_args ha;
    135 	tx_chipset_tag_t tc;
    136 	txreg_t val;
    137 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
    138 
    139 	sc->sc_chip = chip = &tx3912video_chip;
    140 
    141 	/* print video module information */
    142 	printf(": %s, frame buffer 0x%08x-0x%08x\n",
    143 	       depth_print[(ffs(chip->vc_fbdepth) - 1) & 0x3],
    144 	       (unsigned)chip->vc_fbaddr,
    145 	       (unsigned)(chip->vc_fbaddr + chip->vc_fbsize));
    146 
    147 	/* don't inverse VDAT[3:0] signal */
    148 	tc = chip->vc_tc;
    149 	val = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    150 	val &= ~TX3912_VIDEOCTRL1_INVVID;
    151 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, val);
    152 
    153 	/* install default CLUT */
    154 	tx3912video_clut_init(sc);
    155 
    156 	/* if serial console, power off video module */
    157 #ifndef TX3912VIDEO_DEBUG
    158 	if (!console) {
    159 		tx_chipset_tag_t tc = ta->ta_tc;
    160 		txreg_t reg;
    161 		printf("%s: power off\n", sc->sc_dev.dv_xname);
    162 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    163 		reg &= ~(TX3912_VIDEOCTRL1_DISPON |
    164 			 TX3912_VIDEOCTRL1_ENVID);
    165 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    166 	}
    167 #endif /* TX3912VIDEO_DEBUG */
    168 
    169 	/* attach debug draw routine (debugging use) */
    170 	__tx3912video_attach_drawfunc(sc->sc_chip);
    171 
    172 	/* Attach frame buffer device */
    173 	tx3912video_hpcfbinit(sc);
    174 
    175 	if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
    176 		panic("tx3912video_attach: can't init fb console");
    177 	}
    178 
    179 	ha.ha_console = console;
    180 	ha.ha_accessops = &tx3912video_ha;
    181 	ha.ha_accessctx = sc;
    182 	ha.ha_curfbconf = 0;
    183 	ha.ha_nfbconf = 1;
    184 	ha.ha_fbconflist = &sc->sc_fbconf;
    185 	ha.ha_curdspconf = 0;
    186 	ha.ha_ndspconf = 1;
    187 	ha.ha_dspconflist = &sc->sc_dspconf;
    188 
    189 	config_found(self, &ha, hpcfbprint);
    190 }
    191 
    192 void
    193 tx3912video_hpcfbinit(sc)
    194 	struct tx3912video_softc *sc;
    195 {
    196 	struct tx3912video_chip *chip = sc->sc_chip;
    197 	struct hpcfb_fbconf *fb = &sc->sc_fbconf;
    198 	caddr_t fbcaddr = (caddr_t)MIPS_PHYS_TO_KSEG1(chip->vc_fbaddr);
    199 
    200 	memset(fb, 0, sizeof(struct hpcfb_fbconf));
    201 
    202 	fb->hf_conf_index	= 0;	/* configuration index		*/
    203 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
    204 	strncpy(fb->hf_name, "TX3912 built-in video", HPCFB_MAXNAMELEN);
    205 					/* frame buffer name		*/
    206 	strncpy(fb->hf_conf_name, "LCD", HPCFB_MAXNAMELEN);
    207 					/* configuration name		*/
    208 	fb->hf_height		= chip->vc_fbheight;
    209 	fb->hf_width		= chip->vc_fbwidth;
    210 	fb->hf_baseaddr		= mips_ptob(mips_btop(fbcaddr));
    211 	fb->hf_offset		= (u_long)fbcaddr - fb->hf_baseaddr;
    212 					/* frame buffer start offset   	*/
    213 	fb->hf_bytes_per_line	= (chip->vc_fbwidth * chip->vc_fbdepth)
    214 		/ NBBY;
    215 	fb->hf_nplanes		= 1;
    216 	fb->hf_bytes_per_plane	= chip->vc_fbheight * fb->hf_bytes_per_line;
    217 
    218 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
    219 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
    220 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
    221 
    222 	switch (chip->vc_fbdepth) {
    223 	default:
    224 		panic("tx3912video_hpcfbinit: not supported color depth\n");
    225 		/* NOTREACHED */
    226 	case 2:
    227 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
    228 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
    229 		fb->hf_pack_width = 8;
    230 		fb->hf_pixels_per_pack = 4;
    231 		fb->hf_pixel_width = 2;
    232 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
    233 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
    234 		break;
    235 	case 8:
    236 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
    237 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
    238 		fb->hf_pack_width = 8;
    239 		fb->hf_pixels_per_pack = 1;
    240 		fb->hf_pixel_width = 8;
    241 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
    242 		fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
    243 		break;
    244 	}
    245 }
    246 
    247 int
    248 tx3912video_init(fb_start, fb_end)
    249 	paddr_t fb_start, *fb_end;
    250 {
    251 	struct tx3912video_chip *chip = &tx3912video_chip;
    252 	tx_chipset_tag_t tc;
    253 	txreg_t reg;
    254 	int fbdepth;
    255 	int error;
    256 
    257 	chip->vc_tc = tc = tx_conf_get_tag();
    258 
    259 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    260 	fbdepth = 1 << (TX3912_VIDEOCTRL1_BITSEL(reg));
    261 
    262 	switch (fbdepth) {
    263 	case 2:
    264 		bootinfo->fb_type = BIFB_D2_M2L_0;
    265 		break;
    266 	case 4:
    267 		/* XXX should implement rasops4.c */
    268 		fbdepth = 2;
    269 		bootinfo->fb_type = BIFB_D2_M2L_0;
    270 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    271 		TX3912_VIDEOCTRL1_BITSEL_CLR(reg);
    272 		reg = TX3912_VIDEOCTRL1_BITSEL_SET(
    273 			reg, TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE);
    274 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    275 		break;
    276 	case 8:
    277 		bootinfo->fb_type = BIFB_D8_FF;
    278 		break;
    279 	}
    280 
    281 	tx3912video_chip.vc_fbdepth = fbdepth;
    282 	tx3912video_chip.vc_fbwidth = bootinfo->fb_width;
    283 	tx3912video_chip.vc_fbheight= bootinfo->fb_height;
    284 
    285 	/* Allocate framebuffer area */
    286 	error = tx3912video_framebuffer_alloc(chip, fb_start, fb_end);
    287 	if (error != 0)
    288 		return (1);
    289 
    290 #if notyet
    291 	tx3912video_resolution_init(chip);
    292 #else
    293 	/* Use Windows CE setting. */
    294 #endif
    295 	/* Set DMA transfer address to VID module */
    296 	tx3912video_framebuffer_init(chip);
    297 
    298 	/* Syncronize framebuffer addr to frame signal */
    299 	tx3912video_reset(chip);
    300 
    301 	bootinfo->fb_line_bytes = (chip->vc_fbwidth * fbdepth) / NBBY;
    302 	bootinfo->fb_addr = (void *)MIPS_PHYS_TO_KSEG1(chip->vc_fbaddr);
    303 
    304 	return (0);
    305 }
    306 
    307  int
    308 tx3912video_framebuffer_alloc(chip, fb_start, fb_end)
    309 	struct tx3912video_chip *chip;
    310 	paddr_t fb_start, *fb_end; /* buffer allocation hint */
    311 {
    312 	struct extent_fixed ex_fixed[10];
    313 	struct extent *ex;
    314 	u_long addr, size;
    315 	int error;
    316 
    317 	/* calcurate frame buffer size */
    318 	size = (chip->vc_fbwidth * chip->vc_fbheight * chip->vc_fbdepth) /
    319 		NBBY;
    320 
    321 	/* extent V-RAM region */
    322 	ex = extent_create("Frame buffer address", fb_start, *fb_end,
    323 			   0, (caddr_t)ex_fixed, sizeof ex_fixed,
    324 			   EX_NOWAIT);
    325 	if (ex == 0)
    326 		return (1);
    327 
    328 	/* Allocate V-RAM area */
    329 	error = extent_alloc_subregion(ex, fb_start, fb_start + size, size,
    330 				       TX3912_FRAMEBUFFER_ALIGNMENT,
    331 				       TX3912_FRAMEBUFFER_BOUNDARY,
    332 				       EX_FAST|EX_NOWAIT, &addr);
    333 	extent_destroy(ex);
    334 
    335 	if (error != 0) {
    336 		return (1);
    337 	}
    338 
    339 	chip->vc_fbaddr = addr;
    340 	chip->vc_fbsize = size;
    341 
    342 	*fb_end = addr + size;
    343 
    344 	return (0);
    345 }
    346 
    347  void
    348 tx3912video_framebuffer_init(chip)
    349 	struct tx3912video_chip *chip;
    350 {
    351 	u_int32_t fb_addr, fb_size, vaddr, bank, base;
    352 	txreg_t reg;
    353 	tx_chipset_tag_t tc = chip->vc_tc;
    354 
    355 	fb_addr = chip->vc_fbaddr;
    356 	fb_size = chip->vc_fbsize;
    357 
    358 	/*  XXX currently I don't set DFVAL, so force DF signal toggled on
    359          *  XXX each frame. */
    360 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    361 	reg &= ~TX3912_VIDEOCTRL1_DFMODE;
    362 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    363 
    364 	/* Set DMA transfer start and end address */
    365 
    366 	bank = TX3912_VIDEOCTRL3_VIDBANK(fb_addr);
    367 	base = TX3912_VIDEOCTRL3_VIDBASEHI(fb_addr);
    368 	reg = TX3912_VIDEOCTRL3_VIDBANK_SET(0, bank);
    369 	/* Upper address counter */
    370 	reg = TX3912_VIDEOCTRL3_VIDBASEHI_SET(reg, base);
    371 	tx_conf_write(tc, TX3912_VIDEOCTRL3_REG, reg);
    372 
    373 	/* Lower address counter  */
    374 	base = TX3912_VIDEOCTRL4_VIDBASELO(fb_addr + fb_size);
    375 	reg = TX3912_VIDEOCTRL4_VIDBASELO_SET(0, base);
    376 
    377 	/* Set DF-signal rate */
    378 	reg = TX3912_VIDEOCTRL4_DFVAL_SET(reg, 0); /* XXX not yet*/
    379 
    380 	/* Set VIDDONE signal delay after FRAME signal */
    381 	/* XXX not yet*/
    382 	tx_conf_write(tc, TX3912_VIDEOCTRL4_REG, reg);
    383 
    384 	/* Clear frame buffer */
    385 	vaddr = MIPS_PHYS_TO_KSEG1(fb_addr);
    386 	memset((void*)vaddr, 0, fb_size);
    387 }
    388 
    389  void
    390 tx3912video_resolution_init(chip)
    391 	struct tx3912video_chip *chip;
    392 {
    393 	int h, v, split, bit8, horzval, lineval;
    394 	tx_chipset_tag_t tc = chip->vc_tc;
    395 	txreg_t reg;
    396 	u_int32_t val;
    397 
    398 	h = chip->vc_fbwidth;
    399 	v = chip->vc_fbheight;
    400 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    401 	split = reg & TX3912_VIDEOCTRL1_DISPSPLIT;
    402 	bit8  = (TX3912_VIDEOCTRL1_BITSEL(reg) ==
    403 		 TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR);
    404 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    405 
    406 	if ((val == TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR) &&
    407 	    !split) {
    408 		/* (LCD horizontal pixels / 8bit) * RGB - 1 */
    409 		horzval = (h / 8) * 3 - 1;
    410 	} else {
    411 		horzval = h / 4 - 1;
    412 	}
    413 	lineval = (split ? v / 2 : v) - 1;
    414 
    415 	/* Video rate */
    416 	/* XXX
    417 	 *  probably This value should be determined from DFINT and LCDINT
    418 	 */
    419 	reg = TX3912_VIDEOCTRL2_VIDRATE_SET(0, horzval + 1);
    420 	/* Horizontal size of LCD */
    421 	reg = TX3912_VIDEOCTRL2_HORZVAL_SET(reg, horzval);
    422 	/* # of lines for the LCD */
    423 	reg = TX3912_VIDEOCTRL2_LINEVAL_SET(reg, lineval);
    424 
    425 	tx_conf_write(tc, TX3912_VIDEOCTRL2_REG, reg);
    426 }
    427 
    428 void
    429 tx3912video_reset(chip)
    430 	struct tx3912video_chip *chip;
    431 {
    432 	tx_chipset_tag_t tc = chip->vc_tc;
    433 	txreg_t reg;
    434 
    435 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    436 
    437 	/* Disable video logic at end of this frame */
    438 	reg |= TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    439 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    440 
    441 	/* Wait for end of frame */
    442 	delay(30 * 1000);
    443 
    444 	/* Make sure to disable video logic */
    445 	reg &= ~TX3912_VIDEOCTRL1_ENVID;
    446 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    447 
    448 	delay(1000);
    449 
    450 	/* Enable video logic again */
    451 	reg &= ~TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    452 	reg |= TX3912_VIDEOCTRL1_ENVID;
    453 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    454 
    455 	delay(1000);
    456 }
    457 
    458 int
    459 tx3912video_ioctl(v, cmd, data, flag, p)
    460 	void *v;
    461 	u_long cmd;
    462 	caddr_t data;
    463 	int flag;
    464 	struct proc *p;
    465 {
    466 	struct tx3912video_softc *sc = (struct tx3912video_softc *)v;
    467 	struct hpcfb_fbconf *fbconf;
    468 	struct hpcfb_dspconf *dspconf;
    469 	struct wsdisplay_cmap *cmap;
    470 	u_int8_t *r, *g, *b;
    471 	u_int32_t *rgb;
    472 	int idx, cnt, error;
    473 
    474 	switch (cmd) {
    475 	case WSDISPLAYIO_GETCMAP:
    476 		cmap = (struct wsdisplay_cmap*)data;
    477 		cnt = cmap->count;
    478 		idx = cmap->index;
    479 
    480 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
    481 			sc->sc_fbconf.hf_pack_width != 8 ||
    482 			!LEGAL_CLUT_INDEX(idx) ||
    483 			!LEGAL_CLUT_INDEX(idx + cnt -1)) {
    484 			return (EINVAL);
    485 		}
    486 
    487 		if (!uvm_useracc(cmap->red, cnt, B_WRITE) ||
    488 		    !uvm_useracc(cmap->green, cnt, B_WRITE) ||
    489 		    !uvm_useracc(cmap->blue, cnt, B_WRITE)) {
    490 			return (EFAULT);
    491 		}
    492 
    493 		error = cmap_work_alloc(&r, &g, &b, &rgb, cnt);
    494 		if (error != 0) {
    495 			cmap_work_free(r, g, b, rgb);
    496 			return  (ENOMEM);
    497 		}
    498 		tx3912video_clut_get(sc, rgb, idx, cnt);
    499 		rgb24_decompose(rgb, r, g, b, cnt);
    500 
    501 		copyout(r, cmap->red, cnt);
    502 		copyout(g, cmap->green,cnt);
    503 		copyout(b, cmap->blue, cnt);
    504 
    505 		cmap_work_free(r, g, b, rgb);
    506 
    507 		return (0);
    508 
    509 	case WSDISPLAYIO_PUTCMAP:
    510 		/*
    511 		 * TX3912 can't change CLUT index. R:G:B = 3:3:2
    512 		 */
    513 		return (EINVAL);
    514 
    515 	case HPCFBIO_GCONF:
    516 		fbconf = (struct hpcfb_fbconf *)data;
    517 		if (fbconf->hf_conf_index != 0 &&
    518 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    519 			return (EINVAL);
    520 		}
    521 		*fbconf = sc->sc_fbconf;	/* structure assignment */
    522 		return (0);
    523 
    524 	case HPCFBIO_SCONF:
    525 		fbconf = (struct hpcfb_fbconf *)data;
    526 		if (fbconf->hf_conf_index != 0 &&
    527 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    528 			return (EINVAL);
    529 		}
    530 		/*
    531 		 * nothing to do because we have only one configration
    532 		 */
    533 		return (0);
    534 
    535 	case HPCFBIO_GDSPCONF:
    536 		dspconf = (struct hpcfb_dspconf *)data;
    537 		if ((dspconf->hd_unit_index != 0 &&
    538 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    539 		    (dspconf->hd_conf_index != 0 &&
    540 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    541 			return (EINVAL);
    542 		}
    543 		*dspconf = sc->sc_dspconf;	/* structure assignment */
    544 		return (0);
    545 
    546 	case HPCFBIO_SDSPCONF:
    547 		dspconf = (struct hpcfb_dspconf *)data;
    548 		if ((dspconf->hd_unit_index != 0 &&
    549 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    550 		    (dspconf->hd_conf_index != 0 &&
    551 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    552 			return (EINVAL);
    553 		}
    554 		/*
    555 		 * nothing to do
    556 		 * because we have only one unit and one configration
    557 		 */
    558 		return (0);
    559 
    560 	case HPCFBIO_GOP:
    561 	case HPCFBIO_SOP:
    562 		/* XXX not implemented yet */
    563 		return (EINVAL);
    564 	}
    565 
    566 	return (ENOTTY);
    567 }
    568 
    569 int
    570 tx3912video_mmap(ctx, offset, prot)
    571 	void *ctx;
    572 	off_t offset;
    573 	int prot;
    574 {
    575 	struct tx3912video_softc *sc = (struct tx3912video_softc *)ctx;
    576 
    577 	if (offset < 0 || (sc->sc_fbconf.hf_bytes_per_plane +
    578 			   sc->sc_fbconf.hf_offset) <  offset) {
    579 		return (-1);
    580 	}
    581 
    582 	return (mips_btop(sc->sc_chip->vc_fbaddr + offset));
    583 }
    584 
    585 /*
    586  * CLUT staff
    587  */
    588 static const struct {
    589 	int mul, div;
    590 } dither_list [] = {
    591 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1]	= { 1, 1 },
    592 	[TX3912_VIDEO_DITHER_DUTYCYCLE_6_7]	= { 6, 7 },
    593 	[TX3912_VIDEO_DITHER_DUTYCYCLE_4_5]	= { 4, 5 },
    594 	[TX3912_VIDEO_DITHER_DUTYCYCLE_3_4]	= { 3, 4 },
    595 	[TX3912_VIDEO_DITHER_DUTYCYCLE_5_7]	= { 5, 7 },
    596 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_3]	= { 2, 3 },
    597 	[TX3912_VIDEO_DITHER_DUTYCYCLE_3_5]	= { 3, 5 },
    598 	[TX3912_VIDEO_DITHER_DUTYCYCLE_4_7]	= { 4, 7 },
    599 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_4]	= { 2, 4 },
    600 	[TX3912_VIDEO_DITHER_DUTYCYCLE_3_7]	= { 3, 7 },
    601 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_5]	= { 2, 5 },
    602 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1_3]	= { 1, 3 },
    603 	[TX3912_VIDEO_DITHER_DUTYCYCLE_2_7]	= { 2, 7 },
    604 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1_5]	= { 1, 5 },
    605 	[TX3912_VIDEO_DITHER_DUTYCYCLE_1_7]	= { 1, 7 },
    606 	[TX3912_VIDEO_DITHER_DUTYCYCLE_0]	= { 0, 1 }
    607 }, *dlp;
    608 
    609 static const int dither_level8[8] = {
    610 	TX3912_VIDEO_DITHER_DUTYCYCLE_0,
    611 	TX3912_VIDEO_DITHER_DUTYCYCLE_2_7,
    612 	TX3912_VIDEO_DITHER_DUTYCYCLE_2_5,
    613 	TX3912_VIDEO_DITHER_DUTYCYCLE_2_4,
    614 	TX3912_VIDEO_DITHER_DUTYCYCLE_3_5,
    615 	TX3912_VIDEO_DITHER_DUTYCYCLE_5_7,
    616 	TX3912_VIDEO_DITHER_DUTYCYCLE_4_5,
    617 	TX3912_VIDEO_DITHER_DUTYCYCLE_1,
    618 };
    619 
    620 static const int dither_level4[4] = {
    621 	TX3912_VIDEO_DITHER_DUTYCYCLE_0,
    622 	TX3912_VIDEO_DITHER_DUTYCYCLE_1_3,
    623 	TX3912_VIDEO_DITHER_DUTYCYCLE_5_7,
    624 	TX3912_VIDEO_DITHER_DUTYCYCLE_1,
    625 };
    626 
    627 static int
    628 __get_color8(luti)
    629 	int luti;
    630 {
    631 	KASSERT(luti >=0 && luti < 8);
    632 	dlp = &dither_list[dither_level8[luti]];
    633 
    634 	return ((0xff * dlp->mul) / dlp->div);
    635 }
    636 
    637 static int
    638 __get_color4(luti)
    639 	int luti;
    640 {
    641 	KASSERT(luti >=0 && luti < 4);
    642 	dlp = &dither_list[dither_level4[luti]];
    643 
    644 	return ((0xff * dlp->mul) / dlp->div);
    645 }
    646 
    647 void
    648 tx3912video_clut_get(sc, rgb, beg, cnt)
    649 	struct tx3912video_softc *sc;
    650 	u_int32_t *rgb;
    651 	int beg, cnt;
    652 {
    653 	int i;
    654 
    655 	KASSERT(rgb);
    656 	KASSERT(LEGAL_CLUT_INDEX(beg));
    657 	KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1));
    658 
    659 	for (i = 0; i < cnt; i++) {
    660 		rgb[i] =  RGB24(__get_color8((i >> 5) & 0x7),
    661 				__get_color8((i >> 2) & 0x7),
    662 				__get_color4(i & 0x3));
    663 	}
    664 }
    665 
    666 void
    667 tx3912video_clut_install(ctx, ri)
    668 	void *ctx;
    669 	struct rasops_info *ri;
    670 {
    671 	struct tx3912video_softc *sc = ctx;
    672 	const int system_cmap[0x10] = {
    673 		TX3912VIDEO_BLACK,
    674 		TX3912VIDEO_RED,
    675 		TX3912VIDEO_GREEN,
    676 		TX3912VIDEO_YELLOW,
    677 		TX3912VIDEO_BLUE,
    678 		TX3912VIDEO_MAGENTA,
    679 		TX3912VIDEO_CYAN,
    680 		TX3912VIDEO_WHITE,
    681 		TX3912VIDEO_DARK_BLACK,
    682 		TX3912VIDEO_DARK_RED,
    683 		TX3912VIDEO_DARK_GREEN,
    684 		TX3912VIDEO_DARK_YELLOW,
    685 		TX3912VIDEO_DARK_BLUE,
    686 		TX3912VIDEO_DARK_MAGENTA,
    687 		TX3912VIDEO_DARK_CYAN,
    688 		TX3912VIDEO_DARK_WHITE,
    689 	};
    690 
    691 	KASSERT(ri);
    692 
    693 	if (sc->sc_chip->vc_fbdepth == 8) {
    694 		/* XXX 2bit gray scale LUT not supported */
    695 		memcpy(ri->ri_devcmap, system_cmap, sizeof system_cmap);
    696 	}
    697 }
    698 
    699 void
    700 tx3912video_clut_init(sc)
    701 	struct tx3912video_softc *sc;
    702 {
    703 	tx_chipset_tag_t tc = sc->sc_chip->vc_tc;
    704 
    705 	if (sc->sc_chip->vc_fbdepth != 8) {
    706 		return; /* XXX 2bit gray scale LUT not supported */
    707 	}
    708 
    709 	/*
    710 	 * time-based dithering pattern (TOSHIBA recommended pattern)
    711 	 */
    712 	/* 2/3, 1/3 */
    713 	tx_conf_write(tc, TX3912_VIDEOCTRL8_REG,
    714 		      TX3912_VIDEOCTRL8_PAT2_3_DEFAULT);
    715 	/* 3/4, 2/4 */
    716 	tx_conf_write(tc, TX3912_VIDEOCTRL9_REG,
    717 		      (TX3912_VIDEOCTRL9_PAT3_4_DEFAULT << 16) |
    718 		      TX3912_VIDEOCTRL9_PAT2_4_DEFAULT);
    719 	/* 4/5, 1/5 */
    720 	tx_conf_write(tc, TX3912_VIDEOCTRL10_REG,
    721 		      TX3912_VIDEOCTRL10_PAT4_5_DEFAULT);
    722 	/* 3/5, 2/5 */
    723 	tx_conf_write(tc, TX3912_VIDEOCTRL11_REG,
    724 		      TX3912_VIDEOCTRL11_PAT3_5_DEFAULT);
    725 	/* 6/7, 1/7 */
    726 	tx_conf_write(tc, TX3912_VIDEOCTRL12_REG,
    727 		      TX3912_VIDEOCTRL12_PAT6_7_DEFAULT);
    728 	/* 5/7, 2/7 */
    729 	tx_conf_write(tc, TX3912_VIDEOCTRL13_REG,
    730 		      TX3912_VIDEOCTRL13_PAT5_7_DEFAULT);
    731 	/* 4/7, 3/7 */
    732 	tx_conf_write(tc, TX3912_VIDEOCTRL14_REG,
    733 		      TX3912_VIDEOCTRL14_PAT4_7_DEFAULT);
    734 
    735 	/*
    736 	 * dither-pattern look-up table. (selected by uch)
    737 	 */
    738 	/* red */
    739 	tx_conf_write(tc, TX3912_VIDEOCTRL5_REG,
    740 		      (dither_level8[7] << 28) |
    741 		      (dither_level8[6] << 24) |
    742 		      (dither_level8[5] << 20) |
    743 		      (dither_level8[4] << 16) |
    744 		      (dither_level8[3] << 12) |
    745 		      (dither_level8[2] << 8) |
    746 		      (dither_level8[1] << 4) |
    747 		      (dither_level8[0] << 0));
    748 	/* green */
    749 	tx_conf_write(tc, TX3912_VIDEOCTRL6_REG,
    750 		      (dither_level8[7] << 28) |
    751 		      (dither_level8[6] << 24) |
    752 		      (dither_level8[5] << 20) |
    753 		      (dither_level8[4] << 16) |
    754 		      (dither_level8[3] << 12) |
    755 		      (dither_level8[2] << 8) |
    756 		      (dither_level8[1] << 4) |
    757 		      (dither_level8[0] << 0));
    758 	/* blue (2bit gray scale also use this look-up table) */
    759 	tx_conf_write(tc, TX3912_VIDEOCTRL7_REG,
    760 		      (dither_level4[3] << 12) |
    761 		      (dither_level4[2] << 8) |
    762 		      (dither_level4[1] << 4) |
    763 		      (dither_level4[0] << 0));
    764 }
    765 
    766 /*
    767  * Debug routines.
    768  */
    769 void
    770 tx3912video_calibration_pattern()
    771 {
    772 	struct tx3912video_chip *vc = &tx3912video_chip;
    773 	int x, y;
    774 
    775 	x = vc->vc_fbwidth - 40;
    776 	y = vc->vc_fbheight - 40;
    777 	tx3912video_line(40, 40, x , 40);
    778 	tx3912video_line(x , 40, x , y );
    779 	tx3912video_line(x , y , 40, y );
    780 	tx3912video_line(40, y , 40, 40);
    781 	tx3912video_line(40, 40, x , y );
    782 	tx3912video_line(x,  40, 40, y );
    783 }
    784 
    785 #define BPP2 ({ \
    786 	u_int8_t bitmap; \
    787 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    788 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    789 		(bitmap & ~(0x3 << ((3 - (x % 4)) * 2))); \
    790 })
    791 
    792 #define BPP4 ({ \
    793 	u_int8_t bitmap; \
    794 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    795 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    796 		(bitmap & ~(0xf << ((1 - (x % 2)) * 4))); \
    797 })
    798 
    799 #define BPP8 ({ \
    800 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = 0xff; \
    801 })
    802 
    803 #define BRESENHAM(a, b, c, d, func) ({ \
    804 	u_int32_t fbaddr = vc->vc_fbaddr; \
    805 	u_int32_t fbwidth = vc->vc_fbwidth; \
    806 	u_int32_t fbdepth = vc->vc_fbdepth; \
    807 	len = a, step = b -1; \
    808 	if (step == 0) \
    809 		return; \
    810 	kstep = len == 0 ? 0 : 1; \
    811 	for (i = k = 0, j = step / 2; i <= step; i++) { \
    812 		x = xbase c; \
    813 		y = ybase d; \
    814 		addr = fbaddr + (((y * fbwidth + x) * fbdepth) >> 3); \
    815 		func; \
    816 		j -= len; \
    817 		while (j < 0) { \
    818 			j += step; \
    819 			k += kstep; \
    820 		} \
    821 	} \
    822 })
    823 
    824 #define DRAWLINE(func) ({ \
    825 	if (x < 0) { \
    826 		if (y < 0) { \
    827 			if (_y < _x) { \
    828 				BRESENHAM(_y, _x, -i, -k, func); \
    829 			} else { \
    830 				BRESENHAM(_x, _y, -k, -i, func); \
    831 			} \
    832 		} else { \
    833 			if (_y < _x) { \
    834 				BRESENHAM(_y, _x, -i, +k, func); \
    835 			} else { \
    836 				BRESENHAM(_x, _y, -k, +i, func); \
    837 			} \
    838 		} \
    839 	} else { \
    840 		if (y < 0) { \
    841 			if (_y < _x) { \
    842 				BRESENHAM(_y, _x, +i, -k, func); \
    843 			} else { \
    844 				BRESENHAM(_x, _y, +k, -i, func); \
    845 			} \
    846 		} else { \
    847 			if (_y < _x) { \
    848 				BRESENHAM(_y, _x, +i, +k, func); \
    849 			} else { \
    850 				BRESENHAM(_x, _y, +k, +i, func); \
    851 			} \
    852 		} \
    853 	} \
    854 })
    855 
    856 #define LINEFUNC(b) \
    857 static void linebpp##b __P((int, int, int, int)); \
    858 static void \
    859 linebpp##b##(x0, y0, x1, y1) \
    860 	int x0, y0, x1, y1; \
    861 { \
    862 	struct tx3912video_chip *vc = &tx3912video_chip; \
    863 	u_int32_t addr; \
    864 	int i, j, k, len, step, kstep; \
    865 	int x, _x, y, _y; \
    866 	int xbase, ybase; \
    867 	x = x1 - x0; \
    868 	y = y1 - y0; \
    869 	_x = abs(x); \
    870 	_y = abs(y); \
    871 	xbase = x0; \
    872 	ybase = y0; \
    873 	DRAWLINE(BPP##b##); \
    874 }
    875 
    876 #define DOTFUNC(b) \
    877 static void dotbpp##b __P((int, int)); \
    878 static void \
    879 dotbpp##b##(x, y) \
    880 	int x, y; \
    881 { \
    882 	struct tx3912video_chip *vc = &tx3912video_chip; \
    883 	u_int32_t addr; \
    884 	addr = vc->vc_fbaddr + (((y * vc->vc_fbwidth + x) * \
    885 				 vc->vc_fbdepth) >> 3); \
    886 	BPP##b; \
    887 }
    888 
    889 static void linebpp_unimpl __P((int, int, int, int));
    890 static void dotbpp_unimpl __P((int, int));
    891 static
    892 void linebpp_unimpl(x0, y0, x1, y1)
    893 	int x0, y0, x1, y1;
    894 {
    895 	return;
    896 }
    897 static
    898 void dotbpp_unimpl(x, y)
    899 	int x, y;
    900 {
    901 	return;
    902 }
    903 
    904 LINEFUNC(2)
    905 LINEFUNC(4)
    906 LINEFUNC(8)
    907 DOTFUNC(2)
    908 DOTFUNC(4)
    909 DOTFUNC(8)
    910 
    911 void
    912 __tx3912video_attach_drawfunc(vc)
    913 	struct tx3912video_chip *vc;
    914 {
    915 	switch (vc->vc_fbdepth) {
    916 	default:
    917 		vc->vc_drawline = linebpp_unimpl;
    918 		vc->vc_drawdot = dotbpp_unimpl;
    919 		break;
    920 	case 8:
    921 		vc->vc_drawline = linebpp8;
    922 		vc->vc_drawdot = dotbpp8;
    923 		break;
    924 	case 4:
    925 		vc->vc_drawline = linebpp4;
    926 		vc->vc_drawdot = dotbpp4;
    927 		break;
    928 	case 2:
    929 		vc->vc_drawline = linebpp2;
    930 		vc->vc_drawdot = dotbpp2;
    931 		break;
    932 	}
    933 }
    934 
    935 void
    936 tx3912video_line(x0, y0, x1, y1)
    937 	int x0, y0, x1, y1;
    938 {
    939 	struct tx3912video_chip *vc = &tx3912video_chip;
    940 	vc->vc_drawline(x0, y0, x1, y1);
    941 }
    942 
    943 void
    944 tx3912video_dot(x, y)
    945 	int x, y;
    946 {
    947 	struct tx3912video_chip *vc = &tx3912video_chip;
    948 	vc->vc_drawdot(x, y);
    949 }
    950