Home | History | Annotate | Line # | Download | only in tx
tx3912video.c revision 1.7
      1 /*	$NetBSD: tx3912video.c,v 1.7 2000/01/07 15:10:50 uch Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1999, 2000, by UCHIYAMA Yasushi
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. The name of the developer may NOT be used to endorse or promote products
     13  *    derived from this software without specific prior written permission.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  *
     27  */
     28 #include "opt_tx39_debug.h"
     29 #include "fb.h"
     30 
     31 #include <sys/param.h>
     32 #include <sys/systm.h>
     33 #include <sys/device.h>
     34 #include <sys/extent.h>
     35 
     36 #include <machine/bus.h>
     37 #include <machine/bootinfo.h> /* bootinfo */
     38 
     39 #include <hpcmips/tx/tx39var.h>
     40 #include <hpcmips/tx/tx3912videovar.h>
     41 #include <hpcmips/tx/tx3912videoreg.h>
     42 
     43 #if NFB > 0
     44 #include <dev/rcons/raster.h>
     45 #include <dev/wscons/wsdisplayvar.h>
     46 #include <arch/hpcmips/dev/fbvar.h>
     47 #endif
     48 
     49 #undef TX3912VIDEO_DEBUG
     50 
     51 void tx3912video_framebuffer_init __P((tx_chipset_tag_t, u_int32_t,
     52 				       u_int32_t));
     53 int  tx3912video_framebuffer_alloc __P((tx_chipset_tag_t, u_int32_t,
     54 					int, int, int, u_int32_t*,
     55 					u_int32_t*));
     56 void tx3912video_reset __P((tx_chipset_tag_t));
     57 void tx3912video_resolution_init __P((tx_chipset_tag_t, int, int));
     58 int  tx3912video_fbdepth __P((tx_chipset_tag_t, int));
     59 
     60 int	tx3912video_match __P((struct device*, struct cfdata*, void*));
     61 void	tx3912video_attach __P((struct device*, struct device*, void*));
     62 int	tx3912video_print __P((void*, const char*));
     63 
     64 struct tx3912video_chip {
     65 	u_int32_t vc_fbaddr;
     66 	u_int32_t vc_fbsize;
     67 	int	vc_fbdepth;
     68 	int	vc_fbwidth;
     69 	int	vc_fbheight;
     70 
     71 	void (*vc_drawline) __P((int, int, int, int));
     72 	void (*vc_drawdot) __P((int, int));
     73 };
     74 
     75 struct tx3912video_softc {
     76 	struct device sc_dev;
     77 
     78 	struct tx3912video_chip *sc_chip;
     79 };
     80 
     81 struct fb_attach_args {
     82 	const char *fba_name;
     83 };
     84 
     85 struct cfattach tx3912video_ca = {
     86 	sizeof(struct tx3912video_softc), tx3912video_match,
     87 	tx3912video_attach
     88 };
     89 
     90 /* console */
     91 struct tx3912video_chip tx3912video_chip;
     92 
     93 void	tx3912video_attach_drawfunc __P((struct tx3912video_chip*));
     94 
     95 int
     96 tx3912video_match(parent, cf, aux)
     97 	struct device *parent;
     98 	struct cfdata *cf;
     99 	void *aux;
    100 {
    101 	return 1;
    102 }
    103 
    104 void
    105 tx3912video_attach(parent, self, aux)
    106 	struct device *parent;
    107 	struct device *self;
    108 	void *aux;
    109 {
    110 	struct txsim_attach_args *ta = aux;
    111 	struct tx3912video_softc *sc = (void*)self;
    112 	tx_chipset_tag_t tc = ta->ta_tc;
    113 	struct fb_attach_args fba;
    114 	txreg_t reg;
    115 
    116 	sc->sc_chip = &tx3912video_chip;
    117 
    118 	printf(": ");
    119 	tx3912video_fbdepth(tc, 1);
    120 	printf(", frame buffer 0x%08x-0x%08x", sc->sc_chip->vc_fbaddr,
    121 	       sc->sc_chip->vc_fbaddr + sc->sc_chip->vc_fbsize);
    122 
    123 	printf("\n");
    124 
    125 #ifndef TX3912VIDEO_DEBUG
    126 	if (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) {
    127 		printf("%s: power off\n", sc->sc_dev.dv_xname);
    128 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    129 		reg &= ~(TX3912_VIDEOCTRL1_DISPON |
    130 			 TX3912_VIDEOCTRL1_ENVID);
    131 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    132 	}
    133 #endif /* TX3912VIDEO_DEBUG */
    134 
    135 	/* attach debug draw routine */
    136 	tx3912video_attach_drawfunc(sc->sc_chip);
    137 
    138 	/* Attach frame buffer device */
    139 #if NFB > 0
    140 	if (!(bootinfo->bi_cnuse & BI_CNUSE_SERIAL)) {
    141 		if (fb_cnattach(0, 0, 0, 0)) {
    142 			panic("tx3912video_attach: can't init fb console");
    143 		}
    144 	}
    145 	fba.fba_name = "fb";
    146 	config_found(self, &fba, tx3912video_print);
    147 #endif
    148 }
    149 
    150 int
    151 tx3912video_print(aux, pnp)
    152 	void *aux;
    153 	const char *pnp;
    154 {
    155 	return pnp ? QUIET : UNCONF;
    156 }
    157 
    158 int
    159 tx3912video_init(tc, fb_start, fb_width, fb_height, fb_addr, fb_size,
    160 		fb_line_bytes)
    161 	tx_chipset_tag_t tc;
    162 	u_int32_t fb_start; /* Physical address */
    163 	int fb_width, fb_height;
    164 	u_int32_t *fb_addr, *fb_size;
    165 	int *fb_line_bytes;
    166 {
    167  	u_int32_t addr, size;
    168 	int fb_depth;
    169 	txreg_t reg;
    170 
    171 	/* Inquire bit depth */
    172 	fb_depth = tx3912video_fbdepth(tc, 0);
    173 
    174 	switch (fb_depth) {
    175 	case 2:
    176 		bootinfo->fb_type = BIFB_D2_M2L_0;
    177 		break;
    178 	case 4:
    179 		/* XXX should implement rasops4.c */
    180 		fb_depth = 2;
    181 		bootinfo->fb_type = BIFB_D2_M2L_0;
    182 		reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    183 		TX3912_VIDEOCTRL1_BITSEL_CLR(reg);
    184 		reg = TX3912_VIDEOCTRL1_BITSEL_SET(
    185 			reg, TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE);
    186 		tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    187 		break;
    188 	case 8:
    189 		bootinfo->fb_type = BIFB_D8_FF;
    190 		break;
    191 	}
    192 
    193 	tx3912video_chip.vc_fbdepth = fb_depth;
    194 	tx3912video_chip.vc_fbwidth = fb_width;
    195 	tx3912video_chip.vc_fbheight= fb_height;
    196 
    197 
    198 	/* Allocate framebuffer area */
    199 	if (tx3912video_framebuffer_alloc(tc, fb_start, fb_width, fb_height,
    200 					 fb_depth, &addr, &size)) {
    201 		return 1;
    202 	}
    203 #if notyet
    204 	tx3912video_resolution_init(tc, fb_width, fb_height);
    205 #else
    206 	/* Use Windows CE setting. */
    207 #endif
    208 	/* Set DMA transfer address to VID module */
    209 	tx3912video_framebuffer_init(tc, addr, size);
    210 
    211 	/* Syncronize framebuffer addr to frame signal */
    212 	tx3912video_reset(tc);
    213 
    214 	*fb_line_bytes = (fb_width * fb_depth) / 8;
    215 	*fb_addr = addr; /* Phsical address */
    216 	*fb_size = size;
    217 
    218 	return 0;
    219 }
    220 
    221  int
    222 tx3912video_framebuffer_alloc(tc, start, h, v, depth, fb_addr, fb_size)
    223 	tx_chipset_tag_t tc;
    224 	u_int32_t start;
    225 	int h, v, depth;
    226 	u_int32_t *fb_addr, *fb_size;
    227 {
    228 	struct extent_fixed ex_fixed[2];
    229 	struct extent *ex;
    230 	u_long addr, size;
    231 	int err;
    232 
    233 	/* Calcurate frame buffer size */
    234 	size = (h * v * depth) / 8;
    235 
    236 	/* Allocate V-RAM area */
    237 	if (!(ex = extent_create("Frame buffer address", start,
    238 				 start + TX3912_FRAMEBUFFER_MAX,
    239 				 0, (caddr_t)ex_fixed, sizeof ex_fixed,
    240  				 EX_NOWAIT))) {
    241 		return 1;
    242 	}
    243 	if((err = extent_alloc_subregion(ex, start, start + size, size,
    244 					 TX3912_FRAMEBUFFER_ALIGNMENT,
    245 					 TX3912_FRAMEBUFFER_BOUNDARY,
    246 					 EX_FAST|EX_NOWAIT, &addr))) {
    247 		return 1;
    248 	}
    249 	tx3912video_chip.vc_fbaddr = addr;
    250 	tx3912video_chip.vc_fbsize = size;
    251 
    252 	*fb_addr = addr;
    253 	*fb_size = size;
    254 
    255 	return 0;
    256 }
    257 
    258  void
    259 tx3912video_framebuffer_init(tc, fb_addr, fb_size)
    260 	tx_chipset_tag_t tc;
    261 	u_int32_t fb_addr, fb_size;
    262 {
    263 	u_int32_t reg, vaddr, bank, base;
    264 
    265 	/*  XXX currently I don't set DFVAL, so force DF signal toggled on
    266          *  XXX each frame. */
    267 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    268 	reg &= ~TX3912_VIDEOCTRL1_DFMODE;
    269 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    270 
    271 	/* Set DMA transfer start and end address */
    272 
    273 	bank = TX3912_VIDEOCTRL3_VIDBANK(fb_addr);
    274 	base = TX3912_VIDEOCTRL3_VIDBASEHI(fb_addr);
    275 	reg = TX3912_VIDEOCTRL3_VIDBANK_SET(0, bank);
    276 	/* Upper address counter */
    277 	reg = TX3912_VIDEOCTRL3_VIDBASEHI_SET(reg, base);
    278 	tx_conf_write(tc, TX3912_VIDEOCTRL3_REG, reg);
    279 
    280 	/* Lower address counter  */
    281 	base = TX3912_VIDEOCTRL4_VIDBASELO(fb_addr + fb_size);
    282 	reg = TX3912_VIDEOCTRL4_VIDBASELO_SET(0, base);
    283 
    284 	/* Set DF-signal rate */
    285 	reg = TX3912_VIDEOCTRL4_DFVAL_SET(reg, 0); /* XXX not yet*/
    286 
    287 	/* Set VIDDONE signal delay after FRAME signal */
    288 	/* XXX not yet*/
    289 	tx_conf_write(tc, TX3912_VIDEOCTRL4_REG, reg);
    290 
    291 	/* Clear frame buffer */
    292 	vaddr = MIPS_PHYS_TO_KSEG1(fb_addr);
    293 	bzero((void*)vaddr, fb_size);
    294 }
    295 
    296  void
    297 tx3912video_resolution_init(tc, h, v)
    298 	tx_chipset_tag_t tc;
    299 	int h;
    300 	int v;
    301 {
    302 	u_int32_t reg, val;
    303 	int split, bit8, horzval, lineval;
    304 
    305 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    306 	split = reg & TX3912_VIDEOCTRL1_DISPSPLIT;
    307 	bit8  = (TX3912_VIDEOCTRL1_BITSEL(reg) ==
    308 		 TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR);
    309 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    310 
    311 	if ((val == TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR) &&
    312 	    !split) {
    313 		/* (LCD horizontal pixels / 8bit) * RGB - 1 */
    314 		horzval = (h / 8) * 3 - 1;
    315 	} else {
    316 		horzval = h / 4 - 1;
    317 	}
    318 	lineval = (split ? v / 2 : v) - 1;
    319 
    320 	/* Video rate */
    321 	/* XXX
    322 	 *  probably This value should be determined from DFINT and LCDINT
    323 	 */
    324 	reg = TX3912_VIDEOCTRL2_VIDRATE_SET(0, horzval + 1);
    325 	/* Horizontal size of LCD */
    326 	reg = TX3912_VIDEOCTRL2_HORZVAL_SET(reg, horzval);
    327 	/* # of lines for the LCD */
    328 	reg = TX3912_VIDEOCTRL2_LINEVAL_SET(reg, lineval);
    329 
    330 	tx_conf_write(tc, TX3912_VIDEOCTRL2_REG, reg);
    331 }
    332 
    333 int
    334 tx3912video_fbdepth(tc, verbose)
    335 	tx_chipset_tag_t tc;
    336 	int verbose;
    337 {
    338 	u_int32_t reg, val;
    339 
    340 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    341 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    342 	switch (val) {
    343 	case TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR:
    344 		if (verbose)
    345 			printf("8bit color");
    346 		return 8;
    347 	case TX3912_VIDEOCTRL1_BITSEL_4BITGREYSCALE:
    348 		if (verbose)
    349 			printf("4bit greyscale");
    350 		return 4;
    351 	case TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE:
    352 		if (verbose)
    353 			printf("2bit greyscale");
    354 		return 2;
    355 	case TX3912_VIDEOCTRL1_BITSEL_MONOCHROME:
    356 		if (verbose)
    357 			printf("monochrome");
    358 		return 1;
    359 	}
    360 	return 0;
    361 }
    362 
    363 void
    364 tx3912video_reset(tc)
    365 	tx_chipset_tag_t tc;
    366 {
    367 	u_int32_t reg;
    368 
    369 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    370 
    371 	/* Disable video logic at end of this frame */
    372 	reg |= TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    373 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    374 
    375 	/* Wait for end of frame */
    376 	delay(300 * 1000);
    377 
    378 	/* Make sure to disable video logic */
    379 	reg &= ~TX3912_VIDEOCTRL1_ENVID;
    380 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    381 
    382 	delay(1000);
    383 
    384 	/* Enable video logic again */
    385 	reg &= ~TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    386 	reg |= TX3912_VIDEOCTRL1_ENVID;
    387 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    388 
    389 	delay(1000);
    390 }
    391 
    392 /*
    393  * Debug routines.
    394  */
    395 
    396 void
    397 tx3912video_calibration_pattern()
    398 {
    399 	struct tx3912video_chip *vc = &tx3912video_chip;
    400 	int x, y;
    401 
    402 	x = vc->vc_fbwidth - 40;
    403 	y = vc->vc_fbheight - 40;
    404 	tx3912video_line(40, 40, x , 40);
    405 	tx3912video_line(x , 40, x , y );
    406 	tx3912video_line(x , y , 40, y );
    407 	tx3912video_line(40, y , 40, 40);
    408 	tx3912video_line(40, 40, x , y );
    409 	tx3912video_line(x,  40, 40, y );
    410 }
    411 
    412 #define BPP2 ({ \
    413 	u_int8_t bitmap; \
    414 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    415 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    416 		(bitmap & ~(0x3 << ((3 - (x % 4)) * 2))); \
    417 })
    418 
    419 #define BPP4 ({ \
    420 	u_int8_t bitmap; \
    421 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    422 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    423 		(bitmap & ~(0xf << ((1 - (x % 2)) * 4))); \
    424 })
    425 
    426 #define BPP8 ({ \
    427 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = 0xff; \
    428 })
    429 
    430 #define BRESENHAM(a, b, c, d, func) ({ \
    431 	u_int32_t fbaddr = vc->vc_fbaddr; \
    432 	u_int32_t fbwidth = vc->vc_fbwidth; \
    433 	u_int32_t fbdepth = vc->vc_fbdepth; \
    434 	len = a, step = b -1; \
    435 	if (step == 0) \
    436 		return; \
    437 	kstep = len == 0 ? 0 : 1; \
    438 	for (i = k = 0, j = step / 2; i <= step; i++) { \
    439 		x = xbase c; \
    440 		y = ybase d; \
    441 		addr = fbaddr + (((y * fbwidth + x) * fbdepth) >> 3); \
    442 		func; \
    443 		j -= len; \
    444 		while (j < 0) { \
    445 			j += step; \
    446 			k += kstep; \
    447 		} \
    448 	} \
    449 })
    450 
    451 #define DRAWLINE(func) ({ \
    452 	if (x < 0) { \
    453 		if (y < 0) { \
    454 			if (_y < _x) { \
    455 				BRESENHAM(_y, _x, -i, -k, func); \
    456 			} else { \
    457 				BRESENHAM(_x, _y, -k, -i, func); \
    458 			} \
    459 		} else { \
    460 			if (_y < _x) { \
    461 				BRESENHAM(_y, _x, -i, +k, func); \
    462 			} else { \
    463 				BRESENHAM(_x, _y, -k, +i, func); \
    464 			} \
    465 		} \
    466 	} else { \
    467 		if (y < 0) { \
    468 			if (_y < _x) { \
    469 				BRESENHAM(_y, _x, +i, -k, func); \
    470 			} else { \
    471 				BRESENHAM(_x, _y, +k, -i, func); \
    472 			} \
    473 		} else { \
    474 			if (_y < _x) { \
    475 				BRESENHAM(_y, _x, +i, +k, func); \
    476 			} else { \
    477 				BRESENHAM(_x, _y, +k, +i, func); \
    478 			} \
    479 		} \
    480 	} \
    481 })
    482 
    483 #define LINEFUNC(b) \
    484 static void linebpp##b __P((int, int, int, int)); \
    485 static void \
    486 linebpp##b##(x0, y0, x1, y1) \
    487 	int x0, y0, x1, y1; \
    488 { \
    489 	struct tx3912video_chip *vc = &tx3912video_chip; \
    490 	u_int32_t addr; \
    491 	int i, j, k, len, step, kstep; \
    492 	int x, _x, y, _y; \
    493 	int xbase, ybase; \
    494 	x = x1 - x0; \
    495 	y = y1 - y0; \
    496 	_x = abs(x); \
    497 	_y = abs(y); \
    498 	xbase = x0; \
    499 	ybase = y0; \
    500 	DRAWLINE(BPP##b##); \
    501 }
    502 
    503 #define DOTFUNC(b) \
    504 static void dotbpp##b __P((int, int)); \
    505 static void \
    506 dotbpp##b##(x, y) \
    507 	int x, y; \
    508 { \
    509 	struct tx3912video_chip *vc = &tx3912video_chip; \
    510 	u_int32_t addr; \
    511 	addr = vc->vc_fbaddr + (((y * vc->vc_fbwidth + x) * \
    512 				 vc->vc_fbdepth) >> 3); \
    513 	BPP##b; \
    514 }
    515 
    516 static void linebpp_unimpl __P((int, int, int, int));
    517 static void dotbpp_unimpl __P((int, int));
    518 static
    519 void linebpp_unimpl(x0, y0, x1, y1)
    520 	int x0, y0, x1, y1;
    521 {
    522 	return;
    523 }
    524 static
    525 void dotbpp_unimpl(x, y)
    526 	int x, y;
    527 {
    528 	return;
    529 }
    530 
    531 LINEFUNC(2)
    532 LINEFUNC(4)
    533 LINEFUNC(8)
    534 DOTFUNC(2)
    535 DOTFUNC(4)
    536 DOTFUNC(8)
    537 
    538 void
    539 tx3912video_attach_drawfunc(vc)
    540 	struct tx3912video_chip *vc;
    541 {
    542 	switch (vc->vc_fbdepth) {
    543 	default:
    544 		vc->vc_drawline = linebpp_unimpl;
    545 		vc->vc_drawdot = dotbpp_unimpl;
    546 		break;
    547 	case 8:
    548 		vc->vc_drawline = linebpp8;
    549 		vc->vc_drawdot = dotbpp8;
    550 		break;
    551 	case 4:
    552 		vc->vc_drawline = linebpp4;
    553 		vc->vc_drawdot = dotbpp4;
    554 		break;
    555 	case 2:
    556 		vc->vc_drawline = linebpp2;
    557 		vc->vc_drawdot = dotbpp2;
    558 		break;
    559 	}
    560 }
    561 
    562 void
    563 tx3912video_line(x0, y0, x1, y1)
    564 	int x0, y0, x1, y1;
    565 {
    566 	struct tx3912video_chip *vc = &tx3912video_chip;
    567 	vc->vc_drawline(x0, y0, x1, y1);
    568 }
    569 
    570 void
    571 tx3912video_dot(x, y)
    572 	int x, y;
    573 {
    574 	struct tx3912video_chip *vc = &tx3912video_chip;
    575 	vc->vc_drawdot(x, y);
    576 }
    577