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