tx3912video.c revision 1.6       1 /*	$NetBSD: tx3912video.c,v 1.6 2000/01/06 18:10:42 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 
    170 	/* Inquire bit depth */
    171 	fb_depth = tx3912video_fbdepth(tc, 0);
    172 	tx3912video_chip.vc_fbdepth = fb_depth;
    173 	tx3912video_chip.vc_fbwidth = fb_width;
    174 	tx3912video_chip.vc_fbheight= fb_height;
    175 
    176 	/* Allocate framebuffer area */
    177 	if (tx3912video_framebuffer_alloc(tc, fb_start, fb_width, fb_height,
    178 					 fb_depth, &addr, &size)) {
    179 		return 1;
    180 	}
    181 #if notyet
    182 	tx3912video_resolution_init(tc, fb_width, fb_height);
    183 #else
    184 	/* Use Windows CE setting. */
    185 #endif
    186 	/* Set DMA transfer address to VID module */
    187 	tx3912video_framebuffer_init(tc, addr, size);
    188 
    189 	/* Syncronize framebuffer addr to frame signal */
    190 	tx3912video_reset(tc);
    191 
    192 	*fb_line_bytes = (fb_width * fb_depth) / 8;
    193 	*fb_addr = addr; /* Phsical address */
    194 	*fb_size = size;
    195 
    196 	return 0;
    197 }
    198 
    199  int
    200 tx3912video_framebuffer_alloc(tc, start, h, v, depth, fb_addr, fb_size)
    201 	tx_chipset_tag_t tc;
    202 	u_int32_t start;
    203 	int h, v, depth;
    204 	u_int32_t *fb_addr, *fb_size;
    205 {
    206 	struct extent_fixed ex_fixed[2];
    207 	struct extent *ex;
    208 	u_long addr, size;
    209 	int err;
    210 
    211 	/* Calcurate frame buffer size */
    212 	size = (h * v * depth) / 8;
    213 
    214 	/* Allocate V-RAM area */
    215 	if (!(ex = extent_create("Frame buffer address", start,
    216 				 start + TX3912_FRAMEBUFFER_MAX,
    217 				 0, (caddr_t)ex_fixed, sizeof ex_fixed,
    218  				 EX_NOWAIT))) {
    219 		return 1;
    220 	}
    221 	if((err = extent_alloc_subregion(ex, start, start + size, size,
    222 					 TX3912_FRAMEBUFFER_ALIGNMENT,
    223 					 TX3912_FRAMEBUFFER_BOUNDARY,
    224 					 EX_FAST|EX_NOWAIT, &addr))) {
    225 		return 1;
    226 	}
    227 	tx3912video_chip.vc_fbaddr = addr;
    228 	tx3912video_chip.vc_fbsize = size;
    229 
    230 	*fb_addr = addr;
    231 	*fb_size = size;
    232 
    233 	return 0;
    234 }
    235 
    236  void
    237 tx3912video_framebuffer_init(tc, fb_addr, fb_size)
    238 	tx_chipset_tag_t tc;
    239 	u_int32_t fb_addr, fb_size;
    240 {
    241 	u_int32_t reg, vaddr, bank, base;
    242 
    243 	/*  XXX currently I don't set DFVAL, so force DF signal toggled on
    244          *  XXX each frame. */
    245 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    246 	reg &= ~TX3912_VIDEOCTRL1_DFMODE;
    247 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    248 
    249 	/* Set DMA transfer start and end address */
    250 
    251 	bank = TX3912_VIDEOCTRL3_VIDBANK(fb_addr);
    252 	base = TX3912_VIDEOCTRL3_VIDBASEHI(fb_addr);
    253 	reg = TX3912_VIDEOCTRL3_VIDBANK_SET(0, bank);
    254 	/* Upper address counter */
    255 	reg = TX3912_VIDEOCTRL3_VIDBASEHI_SET(reg, base);
    256 	tx_conf_write(tc, TX3912_VIDEOCTRL3_REG, reg);
    257 
    258 	/* Lower address counter  */
    259 	base = TX3912_VIDEOCTRL4_VIDBASELO(fb_addr + fb_size);
    260 	reg = TX3912_VIDEOCTRL4_VIDBASELO_SET(0, base);
    261 
    262 	/* Set DF-signal rate */
    263 	reg = TX3912_VIDEOCTRL4_DFVAL_SET(reg, 0); /* XXX not yet*/
    264 
    265 	/* Set VIDDONE signal delay after FRAME signal */
    266 	/* XXX not yet*/
    267 	tx_conf_write(tc, TX3912_VIDEOCTRL4_REG, reg);
    268 
    269 	/* Clear frame buffer */
    270 	vaddr = MIPS_PHYS_TO_KSEG1(fb_addr);
    271 	bzero((void*)vaddr, fb_size);
    272 }
    273 
    274  void
    275 tx3912video_resolution_init(tc, h, v)
    276 	tx_chipset_tag_t tc;
    277 	int h;
    278 	int v;
    279 {
    280 	u_int32_t reg, val;
    281 	int split, bit8, horzval, lineval;
    282 
    283 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    284 	split = reg & TX3912_VIDEOCTRL1_DISPSPLIT;
    285 	bit8  = (TX3912_VIDEOCTRL1_BITSEL(reg) ==
    286 		 TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR);
    287 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    288 
    289 	if ((val == TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR) &&
    290 	    !split) {
    291 		/* (LCD horizontal pixels / 8bit) * RGB - 1 */
    292 		horzval = (h / 8) * 3 - 1;
    293 	} else {
    294 		horzval = h / 4 - 1;
    295 	}
    296 	lineval = (split ? v / 2 : v) - 1;
    297 
    298 	/* Video rate */
    299 	/* XXX
    300 	 *  probably This value should be determined from DFINT and LCDINT
    301 	 */
    302 	reg = TX3912_VIDEOCTRL2_VIDRATE_SET(0, horzval + 1);
    303 	/* Horizontal size of LCD */
    304 	reg = TX3912_VIDEOCTRL2_HORZVAL_SET(reg, horzval);
    305 	/* # of lines for the LCD */
    306 	reg = TX3912_VIDEOCTRL2_LINEVAL_SET(reg, lineval);
    307 
    308 	tx_conf_write(tc, TX3912_VIDEOCTRL2_REG, reg);
    309 }
    310 
    311 int
    312 tx3912video_fbdepth(tc, verbose)
    313 	tx_chipset_tag_t tc;
    314 	int verbose;
    315 {
    316 	u_int32_t reg, val;
    317 
    318 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    319 	val = TX3912_VIDEOCTRL1_BITSEL(reg);
    320 	switch (val) {
    321 	case TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR:
    322 		if (verbose)
    323 			printf("8bit color");
    324 		return 8;
    325 	case TX3912_VIDEOCTRL1_BITSEL_4BITGREYSCALE:
    326 		if (verbose)
    327 			printf("4bit greyscale");
    328 		return 4;
    329 	case TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE:
    330 		if (verbose)
    331 			printf("2bit greyscale");
    332 		return 2;
    333 	case TX3912_VIDEOCTRL1_BITSEL_MONOCHROME:
    334 		if (verbose)
    335 			printf("monochrome");
    336 		return 1;
    337 	}
    338 	return 0;
    339 }
    340 
    341 void
    342 tx3912video_reset(tc)
    343 	tx_chipset_tag_t tc;
    344 {
    345 	u_int32_t reg;
    346 
    347 	reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG);
    348 
    349 	/* Disable video logic at end of this frame */
    350 	reg |= TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    351 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    352 
    353 	/* Wait for end of frame */
    354 	delay(300 * 1000);
    355 
    356 	/* Make sure to disable video logic */
    357 	reg &= ~TX3912_VIDEOCTRL1_ENVID;
    358 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    359 
    360 	delay(1000);
    361 
    362 	/* Enable video logic again */
    363 	reg &= ~TX3912_VIDEOCTRL1_ENFREEZEFRAME;
    364 	reg |= TX3912_VIDEOCTRL1_ENVID;
    365 	tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg);
    366 
    367 	delay(1000);
    368 }
    369 
    370 /*
    371  * Debug routines.
    372  */
    373 
    374 void
    375 tx3912video_calibration_pattern()
    376 {
    377 	struct tx3912video_chip *vc = &tx3912video_chip;
    378 	int x, y;
    379 
    380 	x = vc->vc_fbwidth - 40;
    381 	y = vc->vc_fbheight - 40;
    382 	tx3912video_line(40, 40, x , 40);
    383 	tx3912video_line(x , 40, x , y );
    384 	tx3912video_line(x , y , 40, y );
    385 	tx3912video_line(40, y , 40, 40);
    386 	tx3912video_line(40, 40, x , y );
    387 	tx3912video_line(x,  40, 40, y );
    388 }
    389 
    390 #define BPP2 ({ \
    391 	u_int8_t bitmap; \
    392 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    393 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    394 		(bitmap & ~(0x3 << ((3 - (x % 4)) * 2))); \
    395 })
    396 
    397 #define BPP4 ({ \
    398 	u_int8_t bitmap; \
    399 	bitmap = *(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr); \
    400 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = \
    401 		(bitmap & ~(0xf << ((1 - (x % 2)) * 4))); \
    402 })
    403 
    404 #define BPP8 ({ \
    405 	*(volatile u_int8_t*)MIPS_PHYS_TO_KSEG1(addr) = 0xff; \
    406 })
    407 
    408 #define BRESENHAM(a, b, c, d, func) ({ \
    409 	u_int32_t fbaddr = vc->vc_fbaddr; \
    410 	u_int32_t fbwidth = vc->vc_fbwidth; \
    411 	u_int32_t fbdepth = vc->vc_fbdepth; \
    412 	len = a, step = b -1; \
    413 	if (step == 0) \
    414 		return; \
    415 	kstep = len == 0 ? 0 : 1; \
    416 	for (i = k = 0, j = step / 2; i <= step; i++) { \
    417 		x = xbase c; \
    418 		y = ybase d; \
    419 		addr = fbaddr + (((y * fbwidth + x) * fbdepth) >> 3); \
    420 		func; \
    421 		j -= len; \
    422 		while (j < 0) { \
    423 			j += step; \
    424 			k += kstep; \
    425 		} \
    426 	} \
    427 })
    428 
    429 #define DRAWLINE(func) ({ \
    430 	if (x < 0) { \
    431 		if (y < 0) { \
    432 			if (_y < _x) { \
    433 				BRESENHAM(_y, _x, -i, -k, func); \
    434 			} else { \
    435 				BRESENHAM(_x, _y, -k, -i, func); \
    436 			} \
    437 		} else { \
    438 			if (_y < _x) { \
    439 				BRESENHAM(_y, _x, -i, +k, func); \
    440 			} else { \
    441 				BRESENHAM(_x, _y, -k, +i, func); \
    442 			} \
    443 		} \
    444 	} else { \
    445 		if (y < 0) { \
    446 			if (_y < _x) { \
    447 				BRESENHAM(_y, _x, +i, -k, func); \
    448 			} else { \
    449 				BRESENHAM(_x, _y, +k, -i, func); \
    450 			} \
    451 		} else { \
    452 			if (_y < _x) { \
    453 				BRESENHAM(_y, _x, +i, +k, func); \
    454 			} else { \
    455 				BRESENHAM(_x, _y, +k, +i, func); \
    456 			} \
    457 		} \
    458 	} \
    459 })
    460 
    461 #define LINEFUNC(b) \
    462 static void linebpp##b __P((int, int, int, int)); \
    463 static void \
    464 linebpp##b##(x0, y0, x1, y1) \
    465 	int x0, y0, x1, y1; \
    466 { \
    467 	struct tx3912video_chip *vc = &tx3912video_chip; \
    468 	u_int32_t addr; \
    469 	int i, j, k, len, step, kstep; \
    470 	int x, _x, y, _y; \
    471 	int xbase, ybase; \
    472 	x = x1 - x0; \
    473 	y = y1 - y0; \
    474 	_x = abs(x); \
    475 	_y = abs(y); \
    476 	xbase = x0; \
    477 	ybase = y0; \
    478 	DRAWLINE(BPP##b##); \
    479 }
    480 
    481 #define DOTFUNC(b) \
    482 static void dotbpp##b __P((int, int)); \
    483 static void \
    484 dotbpp##b##(x, y) \
    485 	int x, y; \
    486 { \
    487 	struct tx3912video_chip *vc = &tx3912video_chip; \
    488 	u_int32_t addr; \
    489 	addr = vc->vc_fbaddr + (((y * vc->vc_fbwidth + x) * \
    490 				 vc->vc_fbdepth) >> 3); \
    491 	BPP##b; \
    492 }
    493 
    494 static void linebpp_unimpl __P((int, int, int, int));
    495 static void dotbpp_unimpl __P((int, int));
    496 static
    497 void linebpp_unimpl(x0, y0, x1, y1)
    498 	int x0, y0, x1, y1;
    499 {
    500 	return;
    501 }
    502 static
    503 void dotbpp_unimpl(x, y)
    504 	int x, y;
    505 {
    506 	return;
    507 }
    508 
    509 LINEFUNC(2)
    510 LINEFUNC(4)
    511 LINEFUNC(8)
    512 DOTFUNC(2)
    513 DOTFUNC(4)
    514 DOTFUNC(8)
    515 
    516 void
    517 tx3912video_attach_drawfunc(vc)
    518 	struct tx3912video_chip *vc;
    519 {
    520 	switch (vc->vc_fbdepth) {
    521 	default:
    522 		vc->vc_drawline = linebpp_unimpl;
    523 		vc->vc_drawdot = dotbpp_unimpl;
    524 		break;
    525 	case 8:
    526 		vc->vc_drawline = linebpp8;
    527 		vc->vc_drawdot = dotbpp8;
    528 		break;
    529 	case 4:
    530 		vc->vc_drawline = linebpp4;
    531 		vc->vc_drawdot = dotbpp4;
    532 		break;
    533 	case 2:
    534 		vc->vc_drawline = linebpp2;
    535 		vc->vc_drawdot = dotbpp2;
    536 		break;
    537 	}
    538 }
    539 
    540 void
    541 tx3912video_line(x0, y0, x1, y1)
    542 	int x0, y0, x1, y1;
    543 {
    544 	struct tx3912video_chip *vc = &tx3912video_chip;
    545 	vc->vc_drawline(x0, y0, x1, y1);
    546 }
    547 
    548 void
    549 tx3912video_dot(x, y)
    550 	int x, y;
    551 {
    552 	struct tx3912video_chip *vc = &tx3912video_chip;
    553 	vc->vc_drawdot(x, y);
    554 }
    555