Home | History | Annotate | Line # | Download | only in tx
tx3912video.c revision 1.11
      1 /*	$NetBSD: tx3912video.c,v 1.11 2000/05/02 17:50:52 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 
     29 #include "opt_tx39_debug.h"
     30 #include "hpcfb.h"
     31 
     32 #include <sys/param.h>
     33 #include <sys/systm.h>
     34 #include <sys/device.h>
     35 #include <sys/extent.h>
     36 
     37 #include <sys/ioctl.h>
     38 
     39 #include <machine/bus.h>
     40 #include <machine/bootinfo.h>
     41 
     42 #include <hpcmips/tx/tx39var.h>
     43 #include <hpcmips/tx/tx3912videovar.h>
     44 #include <hpcmips/tx/tx3912videoreg.h>
     45 
     46 #include <dev/wscons/wsconsio.h>
     47 #include <arch/hpcmips/dev/hpcfbvar.h>
     48 #include <arch/hpcmips/dev/hpcfbio.h>
     49 
     50 #define TX3912VIDEO_DEBUG
     51 
     52 static struct tx3912video_chip {
     53 	tx_chipset_tag_t vc_tc;
     54 
     55 	paddr_t vc_fbaddr;
     56 	size_t vc_fbsize;
     57 	int vc_fbdepth;
     58 	int vc_fbwidth;
     59 	int vc_fbheight;
     60 
     61 	void (*vc_drawline) __P((int, int, int, int)); /* for debug */
     62 	void (*vc_drawdot) __P((int, int)); /* for debug */
     63 } tx3912video_chip;
     64 
     65 struct tx3912video_softc {
     66 	struct device sc_dev;
     67 	struct hpcfb_fbconf sc_fbconf;
     68 	struct hpcfb_dspconf sc_dspconf;
     69 	struct tx3912video_chip *sc_chip;
     70 };
     71 
     72 void	tx3912video_framebuffer_init __P((struct tx3912video_chip *));
     73 int	tx3912video_framebuffer_alloc __P((struct tx3912video_chip *, paddr_t,
     74 					paddr_t *));
     75 void	tx3912video_reset __P((struct tx3912video_chip *));
     76 void	tx3912video_resolution_init __P((struct tx3912video_chip *));
     77 
     78 int	tx3912video_match __P((struct device *, struct cfdata *, void *));
     79 void	tx3912video_attach __P((struct device *, struct device *, void *));
     80 int	tx3912video_print __P((void *, const char *));
     81 
     82 void	tx3912video_hpcfbinit __P((struct tx3912video_softc *));
     83 int	tx3912video_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
     84 int	tx3912video_mmap __P((void *, off_t, int));
     85 
     86 struct cfattach tx3912video_ca = {
     87 	sizeof(struct tx3912video_softc), tx3912video_match,
     88 	tx3912video_attach
     89 };
     90 
     91 struct hpcfb_accessops tx3912video_ha = {
     92 	tx3912video_ioctl, tx3912video_mmap
     93 };
     94 
     95 void	__tx3912video_attach_drawfunc __P((struct tx3912video_chip*));
     96 
     97 int
     98 tx3912video_match(parent, cf, aux)
     99 	struct device *parent;
    100 	struct cfdata *cf;
    101 	void *aux;
    102 {
    103 	return (1);
    104 }
    105 
    106 void
    107 tx3912video_attach(parent, self, aux)
    108 	struct device *parent;
    109 	struct device *self;
    110 	void *aux;
    111 {
    112 	struct tx3912video_softc *sc = (void *)self;
    113 	struct tx3912video_chip *chip;
    114 	const char *depth_print[] = {
    115 		[TX3912_VIDEOCTRL1_BITSEL_MONOCHROME] = "monochrome",
    116 		[TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE] = "2bit greyscale",
    117 		[TX3912_VIDEOCTRL1_BITSEL_4BITGREYSCALE] = "4bit greyscale",
    118 		[TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR] = "8bit color"
    119 	};
    120 	struct hpcfb_attach_args ha;
    121 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
    122 
    123 	sc->sc_chip = chip = &tx3912video_chip;
    124 
    125 	/* print video module information */
    126 	printf(": %s, frame buffer 0x%08x-0x%08x\n",
    127 	       depth_print[(ffs(chip->vc_fbdepth) - 1) & 0x3],
    128 	       (unsigned)chip->vc_fbaddr,
    129 	       (unsigned)(chip->vc_fbaddr + chip->vc_fbsize));
    130 
    131 	/* if serial console, power off video module */
    132 #ifndef TX3912VIDEO_DEBUG
    133 	if (!console) {
    134 		tx_chipset_tag_t tc = ta->ta_tc;
    135 		txreg_t reg;
    136 		printf("%s: power off\n", sc->sc_dev.dv_xname);
    137 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    138 		reg &= ~(TX3912_VIDEOCTRL1_DISPON |
    139 			 TX3912_VIDEOCTRL1_ENVID);
    140 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    141 	}
    142 #endif /* TX3912VIDEO_DEBUG */
    143 
    144 	/* attach debug draw routine (debugging use) */
    145 	__tx3912video_attach_drawfunc(sc->sc_chip);
    146 
    147 	/* Attach frame buffer device */
    148 	tx3912video_hpcfbinit(sc);
    149 
    150 	if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
    151 		panic("tx3912video_attach: can't init fb console");
    152 	}
    153 
    154 	ha.ha_console = console;
    155 	ha.ha_accessops = &tx3912video_ha;
    156 	ha.ha_accessctx = sc;
    157 	ha.ha_curfbconf = 0;
    158 	ha.ha_nfbconf = 1;
    159 	ha.ha_fbconflist = &sc->sc_fbconf;
    160 	ha.ha_curdspconf = 0;
    161 	ha.ha_ndspconf = 1;
    162 	ha.ha_dspconflist = &sc->sc_dspconf;
    163 
    164 	config_found(self, &ha, hpcfbprint);
    165 }
    166 
    167 void
    168 tx3912video_hpcfbinit(sc)
    169 	struct tx3912video_softc *sc;
    170 {
    171 	struct tx3912video_chip *chip = sc->sc_chip;
    172 	struct hpcfb_fbconf *fb = &sc->sc_fbconf;
    173 	caddr_t fbcaddr = (caddr_t)MIPS_PHYS_TO_KSEG1(chip->vc_fbaddr);
    174 
    175 	memset(fb, 0, sizeof(struct hpcfb_fbconf));
    176 
    177 	fb->hf_conf_index	= 0;	/* configuration index		*/
    178 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
    179 	strcpy(fb->hf_name, "TX3912 built-in video");
    180 					/* frame buffer name		*/
    181 	strcpy(fb->hf_conf_name, "LCD");
    182 					/* configuration name		*/
    183 	fb->hf_height		= chip->vc_fbheight;
    184 	fb->hf_width		= chip->vc_fbwidth;
    185 	fb->hf_baseaddr		= mips_ptob(mips_btop(fbcaddr));
    186 	fb->hf_offset		= (u_long)fbcaddr - fb->hf_baseaddr;
    187 					/* frame buffer start offset   	*/
    188 	fb->hf_bytes_per_line	= (chip->vc_fbwidth * chip->vc_fbdepth) / NBBY;
    189 	fb->hf_nplanes		= 1;
    190 	fb->hf_bytes_per_plane	= chip->vc_fbheight * fb->hf_bytes_per_line;
    191 
    192 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
    193 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
    194 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
    195 
    196 	fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; /* XXX */
    197 	switch (chip->vc_fbdepth) {
    198 	default:
    199 		panic("tx3912video_hpcfbinit: not supported color depth\n");
    200 		/* NOTREACHED */
    201 	case 2:
    202 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
    203 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
    204 		fb->hf_pack_width = 8;
    205 		fb->hf_pixels_per_pack = 4;
    206 		fb->hf_pixel_width = 2;
    207 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
    208 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
    209 		break;
    210 	case 8:
    211 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR; /* XXX */
    212 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
    213 		fb->hf_pack_width = 8;
    214 		fb->hf_pixels_per_pack = 1;
    215 		fb->hf_pixel_width = 8;
    216 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
    217 		fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
    218 		break;
    219 	}
    220 }
    221 
    222 int
    223 tx3912video_init(fb_start, fb_end)
    224 	paddr_t fb_start, *fb_end;
    225 {
    226 	struct tx3912video_chip *chip = &tx3912video_chip;
    227 	tx_chipset_tag_t tc;
    228 	txreg_t reg;
    229 	int fbdepth;
    230 	int error;
    231 
    232 	chip->vc_tc = tc = tx_conf_get_tag();
    233 
    234 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    235 	fbdepth = 1 << (TX3912_VIDEOCTRL1_BITSEL(reg));
    236 
    237 	switch (fbdepth) {
    238 	case 2:
    239 		bootinfo->fb_type = BIFB_D2_M2L_0;
    240 		break;
    241 	case 4:
    242 		/* XXX should implement rasops4.c */
    243 		fbdepth = 2;
    244 		bootinfo->fb_type = BIFB_D2_M2L_0;
    245 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    246 		TX3912_VIDEOCTRL1_BITSEL_CLR(reg);
    247 		reg = TX3912_VIDEOCTRL1_BITSEL_SET(
    248 			reg, TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE);
    249 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    250 		break;
    251 	case 8:
    252 		bootinfo->fb_type = BIFB_D8_FF;
    253 		break;
    254 	}
    255 
    256 	tx3912video_chip.vc_fbdepth = fbdepth;
    257 	tx3912video_chip.vc_fbwidth = bootinfo->fb_width;
    258 	tx3912video_chip.vc_fbheight= bootinfo->fb_height;
    259 
    260 	/* Allocate framebuffer area */
    261 	error = tx3912video_framebuffer_alloc(chip, fb_start, fb_end);
    262 	if (error != 0)
    263 		return (1);
    264 
    265 #if notyet
    266 	tx3912video_resolution_init(chip);
    267 #else
    268 	/* Use Windows CE setting. */
    269 #endif
    270 	/* Set DMA transfer address to VID module */
    271 	tx3912video_framebuffer_init(chip);
    272 
    273 	/* Syncronize framebuffer addr to frame signal */
    274 	tx3912video_reset(chip);
    275 
    276 	bootinfo->fb_line_bytes = (chip->vc_fbwidth * fbdepth) / NBBY;
    277 	bootinfo->fb_addr = (void *)MIPS_PHYS_TO_KSEG1(chip->vc_fbaddr);
    278 
    279 	return (0);
    280 }
    281 
    282  int
    283 tx3912video_framebuffer_alloc(chip, fb_start, fb_end)
    284 	struct tx3912video_chip *chip;
    285 	paddr_t fb_start, *fb_end; /* buffer allocation hint */
    286 {
    287 	struct extent_fixed ex_fixed[10];
    288 	struct extent *ex;
    289 	u_long addr, size;
    290 	int error;
    291 
    292 	/* calcurate frame buffer size */
    293 	size = (chip->vc_fbwidth * chip->vc_fbheight * chip->vc_fbdepth) /
    294 		NBBY;
    295 
    296 	/* extent V-RAM region */
    297 	ex = extent_create("Frame buffer address", fb_start, *fb_end,
    298 			   0, (caddr_t)ex_fixed, sizeof ex_fixed,
    299 			   EX_NOWAIT);
    300 	if (ex == 0)
    301 		return (1);
    302 
    303 	/* Allocate V-RAM area */
    304 	error = extent_alloc_subregion(ex, fb_start, fb_start + size, size,
    305 				       TX3912_FRAMEBUFFER_ALIGNMENT,
    306 				       TX3912_FRAMEBUFFER_BOUNDARY,
    307 				       EX_FAST|EX_NOWAIT, &addr);
    308 	extent_destroy(ex);
    309 
    310 	if (error != 0) {
    311 		return (1);
    312 	}
    313 
    314 	chip->vc_fbaddr = addr;
    315 	chip->vc_fbsize = size;
    316 
    317 	*fb_end = addr + size;
    318 
    319 	return (0);
    320 }
    321 
    322  void
    323 tx3912video_framebuffer_init(chip)
    324 	struct tx3912video_chip *chip;
    325 {
    326 	u_int32_t fb_addr, fb_size, vaddr, bank, base;
    327 	txreg_t reg;
    328 	tx_chipset_tag_t tc = chip->vc_tc;
    329 
    330 	fb_addr = chip->vc_fbaddr;
    331 	fb_size = chip->vc_fbsize;
    332 
    333 	/*  XXX currently I don't set DFVAL, so force DF signal toggled on
    334          *  XXX each frame. */
    335 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    336 	reg &= ~TX3912_VIDEOCTRL1_DFMODE;
    337 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    338 
    339 	/* Set DMA transfer start and end address */
    340 
    341 	bank = TX3912_VIDEOCTRL3_VIDBANK(fb_addr);
    342 	base = TX3912_VIDEOCTRL3_VIDBASEHI(fb_addr);
    343 	reg = TX3912_VIDEOCTRL3_VIDBANK_SET(0, bank);
    344 	/* Upper address counter */
    345 	reg = TX3912_VIDEOCTRL3_VIDBASEHI_SET(reg, base);
    346 	tx_conf_write(tc, TX3912_VIDEOCTRL3_REG, reg);
    347 
    348 	/* Lower address counter  */
    349 	base = TX3912_VIDEOCTRL4_VIDBASELO(fb_addr + fb_size);
    350 	reg = TX3912_VIDEOCTRL4_VIDBASELO_SET(0, base);
    351 
    352 	/* Set DF-signal rate */
    353 	reg = TX3912_VIDEOCTRL4_DFVAL_SET(reg, 0); /* XXX not yet*/
    354 
    355 	/* Set VIDDONE signal delay after FRAME signal */
    356 	/* XXX not yet*/
    357 	tx_conf_write(tc, TX3912_VIDEOCTRL4_REG, reg);
    358 
    359 	/* Clear frame buffer */
    360 	vaddr = MIPS_PHYS_TO_KSEG1(fb_addr);
    361 	memset((void*)vaddr, 0, fb_size);
    362 }
    363 
    364  void
    365 tx3912video_resolution_init(chip)
    366 	struct tx3912video_chip *chip;
    367 {
    368 	int h, v, split, bit8, horzval, lineval;
    369 	tx_chipset_tag_t tc = chip->vc_tc;
    370 	txreg_t reg;
    371 	u_int32_t val;
    372 
    373 	h = chip->vc_fbwidth;
    374 	v = chip->vc_fbheight;
    375 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    376 	split = reg & TX3912_VIDEOCTRL1_DISPSPLIT;
    377 	bit8  = (TX3912_VIDEOCTRL1_BITSEL(reg) ==
    378 		 TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR);
    379 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    380 
    381 	if ((val == TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR) &&
    382 	    !split) {
    383 		/* (LCD horizontal pixels / 8bit) * RGB - 1 */
    384 		horzval = (h / 8) * 3 - 1;
    385 	} else {
    386 		horzval = h / 4 - 1;
    387 	}
    388 	lineval = (split ? v / 2 : v) - 1;
    389 
    390 	/* Video rate */
    391 	/* XXX
    392 	 *  probably This value should be determined from DFINT and LCDINT
    393 	 */
    394 	reg = TX3912_VIDEOCTRL2_VIDRATE_SET(0, horzval + 1);
    395 	/* Horizontal size of LCD */
    396 	reg = TX3912_VIDEOCTRL2_HORZVAL_SET(reg, horzval);
    397 	/* # of lines for the LCD */
    398 	reg = TX3912_VIDEOCTRL2_LINEVAL_SET(reg, lineval);
    399 
    400 	tx_conf_write(tc, TX3912_VIDEOCTRL2_REG, reg);
    401 }
    402 
    403 void
    404 tx3912video_reset(chip)
    405 	struct tx3912video_chip *chip;
    406 {
    407 	tx_chipset_tag_t tc = chip->vc_tc;
    408 	txreg_t reg;
    409 
    410 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    411 
    412 	/* Disable video logic at end of this frame */
    413 	reg |= TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    414 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    415 
    416 	/* Wait for end of frame */
    417 	delay(30 * 1000);
    418 
    419 	/* Make sure to disable video logic */
    420 	reg &= ~TX3912_VIDEOCTRL1_ENVID;
    421 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    422 
    423 	delay(1000);
    424 
    425 	/* Enable video logic again */
    426 	reg &= ~TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    427 	reg |= TX3912_VIDEOCTRL1_ENVID;
    428 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    429 
    430 	delay(1000);
    431 }
    432 
    433 int
    434 tx3912video_ioctl(v, cmd, data, flag, p)
    435 	void *v;
    436 	u_long cmd;
    437 	caddr_t data;
    438 	int flag;
    439 	struct proc *p;
    440 {
    441 	struct tx3912video_softc *sc = (struct tx3912video_softc *)v;
    442 	struct hpcfb_fbconf *fbconf;
    443 	struct hpcfb_dspconf *dspconf;
    444 
    445 	switch (cmd) {
    446 	case WSDISPLAYIO_GETCMAP:
    447 		/* XXX not implemented yet */
    448 		return (EINVAL);
    449 
    450 	case WSDISPLAYIO_PUTCMAP:
    451 		/* XXX not implemented yet */
    452 		return (EINVAL);
    453 
    454 	case HPCFBIO_GCONF:
    455 		fbconf = (struct hpcfb_fbconf *)data;
    456 		if (fbconf->hf_conf_index != 0 &&
    457 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    458 			return (EINVAL);
    459 		}
    460 		*fbconf = sc->sc_fbconf;	/* structure assignment */
    461 		return (0);
    462 
    463 	case HPCFBIO_SCONF:
    464 		fbconf = (struct hpcfb_fbconf *)data;
    465 		if (fbconf->hf_conf_index != 0 &&
    466 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    467 			return (EINVAL);
    468 		}
    469 		/*
    470 		 * nothing to do because we have only one configration
    471 		 */
    472 		return (0);
    473 
    474 	case HPCFBIO_GDSPCONF:
    475 		dspconf = (struct hpcfb_dspconf *)data;
    476 		if ((dspconf->hd_unit_index != 0 &&
    477 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    478 		    (dspconf->hd_conf_index != 0 &&
    479 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    480 			return (EINVAL);
    481 		}
    482 		*dspconf = sc->sc_dspconf;	/* structure assignment */
    483 		return (0);
    484 
    485 	case HPCFBIO_SDSPCONF:
    486 		dspconf = (struct hpcfb_dspconf *)data;
    487 		if ((dspconf->hd_unit_index != 0 &&
    488 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    489 		    (dspconf->hd_conf_index != 0 &&
    490 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    491 			return (EINVAL);
    492 		}
    493 		/*
    494 		 * nothing to do
    495 		 * because we have only one unit and one configration
    496 		 */
    497 		return (0);
    498 
    499 	case HPCFBIO_GOP:
    500 	case HPCFBIO_SOP:
    501 		/* XXX not implemented yet */
    502 		return (EINVAL);
    503 	}
    504 
    505 	return (ENOTTY);
    506 }
    507 
    508 int
    509 tx3912video_mmap(ctx, offset, prot)
    510 	void *ctx;
    511 	off_t offset;
    512 	int prot;
    513 {
    514 	struct tx3912video_softc *sc = (struct tx3912video_softc *)ctx;
    515 
    516 	if (offset < 0 || (sc->sc_fbconf.hf_bytes_per_plane +
    517 			   sc->sc_fbconf.hf_offset) <  offset) {
    518 		return (-1);
    519 	}
    520 
    521 	return (mips_btop(sc->sc_chip->vc_fbaddr + offset));
    522 }
    523 
    524 /*
    525  * Debug routines.
    526  */
    527 void
    528 tx3912video_calibration_pattern()
    529 {
    530 	struct tx3912video_chip *vc = &tx3912video_chip;
    531 	int x, y;
    532 
    533 	x = vc->vc_fbwidth - 40;
    534 	y = vc->vc_fbheight - 40;
    535 	tx3912video_line(40, 40, x , 40);
    536 	tx3912video_line(x , 40, x , y );
    537 	tx3912video_line(x , y , 40, y );
    538 	tx3912video_line(40, y , 40, 40);
    539 	tx3912video_line(40, 40, x , y );
    540 	tx3912video_line(x,  40, 40, y );
    541 }
    542 
    543 #define BPP2 ({ \
    544 	u_int8_t bitmap; \
    545 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    546 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    547 		(bitmap & ~(0x3 << ((3 - (x % 4)) * 2))); \
    548 })
    549 
    550 #define BPP4 ({ \
    551 	u_int8_t bitmap; \
    552 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    553 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    554 		(bitmap & ~(0xf << ((1 - (x % 2)) * 4))); \
    555 })
    556 
    557 #define BPP8 ({ \
    558 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = 0xff; \
    559 })
    560 
    561 #define BRESENHAM(a, b, c, d, func) ({ \
    562 	u_int32_t fbaddr = vc->vc_fbaddr; \
    563 	u_int32_t fbwidth = vc->vc_fbwidth; \
    564 	u_int32_t fbdepth = vc->vc_fbdepth; \
    565 	len = a, step = b -1; \
    566 	if (step == 0) \
    567 		return; \
    568 	kstep = len == 0 ? 0 : 1; \
    569 	for (i = k = 0, j = step / 2; i <= step; i++) { \
    570 		x = xbase c; \
    571 		y = ybase d; \
    572 		addr = fbaddr + (((y * fbwidth + x) * fbdepth) >> 3); \
    573 		func; \
    574 		j -= len; \
    575 		while (j < 0) { \
    576 			j += step; \
    577 			k += kstep; \
    578 		} \
    579 	} \
    580 })
    581 
    582 #define DRAWLINE(func) ({ \
    583 	if (x < 0) { \
    584 		if (y < 0) { \
    585 			if (_y < _x) { \
    586 				BRESENHAM(_y, _x, -i, -k, func); \
    587 			} else { \
    588 				BRESENHAM(_x, _y, -k, -i, func); \
    589 			} \
    590 		} else { \
    591 			if (_y < _x) { \
    592 				BRESENHAM(_y, _x, -i, +k, func); \
    593 			} else { \
    594 				BRESENHAM(_x, _y, -k, +i, func); \
    595 			} \
    596 		} \
    597 	} else { \
    598 		if (y < 0) { \
    599 			if (_y < _x) { \
    600 				BRESENHAM(_y, _x, +i, -k, func); \
    601 			} else { \
    602 				BRESENHAM(_x, _y, +k, -i, func); \
    603 			} \
    604 		} else { \
    605 			if (_y < _x) { \
    606 				BRESENHAM(_y, _x, +i, +k, func); \
    607 			} else { \
    608 				BRESENHAM(_x, _y, +k, +i, func); \
    609 			} \
    610 		} \
    611 	} \
    612 })
    613 
    614 #define LINEFUNC(b) \
    615 static void linebpp##b __P((int, int, int, int)); \
    616 static void \
    617 linebpp##b##(x0, y0, x1, y1) \
    618 	int x0, y0, x1, y1; \
    619 { \
    620 	struct tx3912video_chip *vc = &tx3912video_chip; \
    621 	u_int32_t addr; \
    622 	int i, j, k, len, step, kstep; \
    623 	int x, _x, y, _y; \
    624 	int xbase, ybase; \
    625 	x = x1 - x0; \
    626 	y = y1 - y0; \
    627 	_x = abs(x); \
    628 	_y = abs(y); \
    629 	xbase = x0; \
    630 	ybase = y0; \
    631 	DRAWLINE(BPP##b##); \
    632 }
    633 
    634 #define DOTFUNC(b) \
    635 static void dotbpp##b __P((int, int)); \
    636 static void \
    637 dotbpp##b##(x, y) \
    638 	int x, y; \
    639 { \
    640 	struct tx3912video_chip *vc = &tx3912video_chip; \
    641 	u_int32_t addr; \
    642 	addr = vc->vc_fbaddr + (((y * vc->vc_fbwidth + x) * \
    643 				 vc->vc_fbdepth) >> 3); \
    644 	BPP##b; \
    645 }
    646 
    647 static void linebpp_unimpl __P((int, int, int, int));
    648 static void dotbpp_unimpl __P((int, int));
    649 static
    650 void linebpp_unimpl(x0, y0, x1, y1)
    651 	int x0, y0, x1, y1;
    652 {
    653 	return;
    654 }
    655 static
    656 void dotbpp_unimpl(x, y)
    657 	int x, y;
    658 {
    659 	return;
    660 }
    661 
    662 LINEFUNC(2)
    663 LINEFUNC(4)
    664 LINEFUNC(8)
    665 DOTFUNC(2)
    666 DOTFUNC(4)
    667 DOTFUNC(8)
    668 
    669 void
    670 __tx3912video_attach_drawfunc(vc)
    671 	struct tx3912video_chip *vc;
    672 {
    673 	switch (vc->vc_fbdepth) {
    674 	default:
    675 		vc->vc_drawline = linebpp_unimpl;
    676 		vc->vc_drawdot = dotbpp_unimpl;
    677 		break;
    678 	case 8:
    679 		vc->vc_drawline = linebpp8;
    680 		vc->vc_drawdot = dotbpp8;
    681 		break;
    682 	case 4:
    683 		vc->vc_drawline = linebpp4;
    684 		vc->vc_drawdot = dotbpp4;
    685 		break;
    686 	case 2:
    687 		vc->vc_drawline = linebpp2;
    688 		vc->vc_drawdot = dotbpp2;
    689 		break;
    690 	}
    691 }
    692 
    693 void
    694 tx3912video_line(x0, y0, x1, y1)
    695 	int x0, y0, x1, y1;
    696 {
    697 	struct tx3912video_chip *vc = &tx3912video_chip;
    698 	vc->vc_drawline(x0, y0, x1, y1);
    699 }
    700 
    701 void
    702 tx3912video_dot(x, y)
    703 	int x, y;
    704 {
    705 	struct tx3912video_chip *vc = &tx3912video_chip;
    706 	vc->vc_drawdot(x, y);
    707 }
    708