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