Home | History | Annotate | Line # | Download | only in dev
diofb.c revision 1.7
      1 /*	$NetBSD: diofb.c,v 1.7 2021/08/07 16:18:53 thorpej Exp $	*/
      2 /*	$OpenBSD: diofb.c,v 1.18 2010/12/26 15:40:59 miod Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2005, Miodrag Vallat
      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
     18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 /*
     29  * Copyright (c) 1988 University of Utah.
     30  * Copyright (c) 1990, 1993
     31  *	The Regents of the University of California.  All rights reserved.
     32  *
     33  * This code is derived from software contributed to Berkeley by
     34  * the Systems Programming Group of the University of Utah Computer
     35  * Science Department.
     36  *
     37  * Redistribution and use in source and binary forms, with or without
     38  * modification, are permitted provided that the following conditions
     39  * are met:
     40  * 1. Redistributions of source code must retain the above copyright
     41  *    notice, this list of conditions and the following disclaimer.
     42  * 2. Redistributions in binary form must reproduce the above copyright
     43  *    notice, this list of conditions and the following disclaimer in the
     44  *    documentation and/or other materials provided with the distribution.
     45  * 3. Neither the name of the University nor the names of its contributors
     46  *    may be used to endorse or promote products derived from this software
     47  *    without specific prior written permission.
     48  *
     49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     59  * SUCH DAMAGE.
     60  */
     61 
     62 #include <sys/param.h>
     63 #include <sys/conf.h>
     64 #include <sys/proc.h>
     65 #include <sys/ioctl.h>
     66 #include <sys/tty.h>
     67 #include <sys/systm.h>
     68 #include <sys/device.h>
     69 #include <sys/bus.h>
     70 #include <sys/cpu.h>
     71 
     72 #include <machine/autoconf.h>
     73 
     74 #include <dev/wscons/wsconsio.h>
     75 #include <dev/wscons/wsdisplayvar.h>
     76 #include <dev/rasops/rasops.h>
     77 
     78 #include <hp300/dev/dioreg.h>
     79 #include <hp300/dev/diovar.h>
     80 #include <hp300/dev/diofbreg.h>
     81 #include <hp300/dev/diofbvar.h>
     82 
     83 static void	diofb_do_cursor(struct rasops_info *);
     84 static void	diofb_copycols(void *, int, int, int, int);
     85 static void	diofb_erasecols(void *, int, int, int, long);
     86 static void	diofb_copyrows(void *, int, int, int);
     87 static void	diofb_eraserows(void *, int, int, long);
     88 static int	diofb_allocattr(void *, int, int, int, long *);
     89 
     90 struct diofb diofb_cn;
     91 
     92 /*
     93  * Frame buffer geometry initialization
     94  */
     95 
     96 int
     97 diofb_fbinquire(struct diofb *fb, int scode, struct diofbreg *fbr)
     98 {
     99 	int fboff, regsize;
    100 
    101 	if (ISIIOVA(fbr))
    102 		fb->regaddr = (uint8_t *)IIOP(fbr);
    103 	else
    104 		fb->regaddr = dio_scodetopa(scode);
    105 
    106 	if (fb->fbwidth == 0 || fb->fbheight == 0) {
    107 		fb->fbwidth = (fbr->fbwmsb << 8) | fbr->fbwlsb;
    108 		fb->fbheight = (fbr->fbhmsb << 8) | fbr->fbhlsb;
    109 	}
    110 	fb->fbsize = fb->fbwidth * fb->fbheight;
    111 
    112 	fb->regkva = (uint8_t *)fbr;
    113 	fboff = (fbr->fbomsb << 8) | fbr->fbolsb;
    114 	fb->fbaddr = (uint8_t *) (*((uint8_t *)fbr + fboff) << 16);
    115 
    116 	if (fb->regaddr >= (uint8_t *)DIOII_BASE) {
    117 		/*
    118 		 * For DIO-II space the fbaddr just computed is
    119 		 * the offset from the select code base (regaddr)
    120 		 * of the framebuffer.  Hence it is also implicitly
    121 		 * the size of the set.
    122 		 */
    123 		regsize = (uintptr_t)fb->fbaddr;
    124 		fb->fbaddr = fb->regaddr + (uintptr_t)fb->fbaddr;
    125 		fb->fbkva = (uint8_t *)fbr + regsize;
    126 	} else {
    127 		/*
    128 		 * For internal or DIO-I space we need to map the separate
    129 		 * framebuffer.
    130 		 */
    131 		fb->fbkva = iomap(fb->fbaddr, fb->fbsize);
    132 		if (fb->fbkva == NULL)
    133 			return ENOMEM;
    134 	}
    135 	if (fb->dwidth == 0 || fb->dheight == 0) {
    136 		fb->dwidth = (fbr->dwmsb << 8) | fbr->dwlsb;
    137 		fb->dheight = (fbr->dhmsb << 8) | fbr->dhlsb;
    138 	}
    139 
    140 	/*
    141 	 * Some displays, such as the DaVinci, appear to return a display
    142 	 * height larger than the frame buffer height.
    143 	 */
    144 	if (fb->dwidth > fb->fbwidth)
    145 		fb->dwidth = fb->fbwidth;
    146 	if (fb->dheight > fb->fbheight)
    147 		fb->dheight = fb->fbheight;
    148 
    149 	/*
    150 	 * Some displays, such as the HP332 and HP340 internal video
    151 	 * appear to return a display width of 1024 instead of 512.
    152 	 */
    153 	if (fbr->num_planes == 1 || fbr->num_planes == 4) {
    154 		if (fb->dwidth == 1024 && fb->dheight == 400)
    155 			fb->dwidth = 512;
    156 	}
    157 
    158 	fb->planes = fbr->num_planes;
    159 	if (fb->planes > 8)
    160 		fb->planes = 8;
    161 	fb->planemask = (1 << fb->planes) - 1;
    162 
    163 	fb->mapmode = WSDISPLAYIO_MODE_DUMBFB;
    164 
    165 	return 0;
    166 }
    167 
    168 /*
    169  * Frame buffer rasops and colormap setup
    170  */
    171 
    172 void
    173 diofb_fbsetup(struct diofb *fb)
    174 {
    175 	struct rasops_info *ri = &fb->ri;
    176 
    177 	/*
    178 	 * Pretend we are an 8bpp frame buffer, unless ri_depth is already
    179 	 * initialized, since this is how it is supposed to be addressed.
    180 	 * (Hyperion forces 1bpp because it is really 1bpp addressed).
    181 	 */
    182 	if (ri->ri_depth == 0)
    183 		ri->ri_depth = 8;
    184 	ri->ri_stride = (fb->fbwidth * ri->ri_depth) / 8;
    185 
    186 	ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
    187 	/* We don't really support colors on less than 4bpp frame buffers */
    188 	if (fb->planes < 4)
    189 		ri->ri_flg |= RI_FORCEMONO;
    190 	if (fb == &diofb_cn)
    191 		ri->ri_flg |= RI_NO_AUTO;
    192 	ri->ri_bits = fb->fbkva;
    193 	ri->ri_width = fb->dwidth;
    194 	ri->ri_height = fb->dheight;
    195 	ri->ri_hw = fb;
    196 
    197 	/*
    198 	 * Ask for an unholy big display, rasops will trim this to more
    199 	 * reasonable values.
    200 	 */
    201 	rasops_init(ri, 160, 160);
    202 
    203 	diofb_resetcmap(fb);
    204 
    205 	/*
    206 	 * For low depth frame buffers, since we have faked a 8bpp frame buffer
    207 	 * to rasops, we actually have to remove capabilities.
    208 	 */
    209 	if (fb->planes == 4) {
    210 		ri->ri_ops.allocattr = diofb_allocattr;
    211 		ri->ri_caps &= ~WSSCREEN_HILIT;
    212 	}
    213 
    214 	ri->ri_ops.copycols = diofb_copycols;
    215 	ri->ri_ops.erasecols = diofb_erasecols;
    216 	if (ri->ri_depth != 1) {
    217 		ri->ri_ops.copyrows = diofb_copyrows;
    218 		ri->ri_ops.eraserows = diofb_eraserows;
    219 		ri->ri_do_cursor = diofb_do_cursor;
    220 	}
    221 
    222 	/* Clear entire display, including non visible areas */
    223 	(*fb->bmv)(fb, 0, 0, 0, 0, fb->fbwidth, fb->fbheight, RR_CLEAR, 0xff);
    224 
    225 	fb->wsd.name = fb->wsdname;
    226 	fb->wsd.ncols = ri->ri_cols;
    227 	fb->wsd.nrows = ri->ri_rows;
    228 	fb->wsd.textops = &ri->ri_ops;
    229 	fb->wsd.fontwidth = ri->ri_font->fontwidth;
    230 	fb->wsd.fontheight = ri->ri_font->fontheight;
    231 	fb->wsd.capabilities = ri->ri_caps;
    232 	strlcpy(fb->wsdname, "std", sizeof(fb->wsdname));
    233 }
    234 
    235 /*
    236  * Setup default emulation mode colormap
    237  */
    238 void
    239 diofb_resetcmap(struct diofb *fb)
    240 {
    241 	const u_char *color;
    242 	u_int i;
    243 
    244 	/* start with the rasops colormap */
    245 	color = (const u_char *)rasops_cmap;
    246 	for (i = 0; i < 256; i++) {
    247 		fb->cmap.r[i] = *color++;
    248 		fb->cmap.g[i] = *color++;
    249 		fb->cmap.b[i] = *color++;
    250 	}
    251 
    252 	/*
    253 	 * Tweak colormap
    254 	 *
    255 	 * Due to the way rasops cursor work, we need to provide
    256 	 * copies of the 8 or 16 basic colors at extra locations
    257 	 * in 4bpp and 6bpp mode. This is because missing planes
    258 	 * accept writes but read back as zero.
    259 	 *
    260 	 * So, in 6bpp mode:
    261 	 *   00 gets inverted to ff, read back as 3f
    262 	 *   3f gets inverted to c0, read back as 00
    263 	 * and in 4bpp mode:
    264 	 *   00 gets inverted to ff, read back as 0f
    265 	 *   0f gets inverted to f0, read back as 00
    266 	 */
    267 
    268 	switch (fb->planes) {
    269 	case 6:
    270 		/*
    271 		 * 00-0f normal colors
    272 		 * 30-3f inverted colors
    273 		 * c0-cf normal colors
    274 		 * f0-ff inverted colors
    275 		 */
    276 		memcpy(fb->cmap.r + 0xc0, fb->cmap.r + 0x00, 0x10);
    277 		memcpy(fb->cmap.g + 0xc0, fb->cmap.g + 0x00, 0x10);
    278 		memcpy(fb->cmap.b + 0xc0, fb->cmap.b + 0x00, 0x10);
    279 		memcpy(fb->cmap.r + 0x30, fb->cmap.r + 0xf0, 0x10);
    280 		memcpy(fb->cmap.g + 0x30, fb->cmap.g + 0xf0, 0x10);
    281 		memcpy(fb->cmap.b + 0x30, fb->cmap.b + 0xf0, 0x10);
    282 		break;
    283 	case 4:
    284 		/*
    285 		 * 00-07 normal colors
    286 		 * 08-0f inverted colors
    287 		 * highlighted colors are not available.
    288 		 */
    289 		memcpy(fb->cmap.r + 0x08, fb->cmap.r + 0xf8, 0x08);
    290 		memcpy(fb->cmap.g + 0x08, fb->cmap.g + 0xf8, 0x08);
    291 		memcpy(fb->cmap.b + 0x08, fb->cmap.b + 0xf8, 0x08);
    292 		break;
    293 	}
    294 }
    295 
    296 /*
    297  * Attachment helpers
    298  */
    299 
    300 void
    301 diofb_cnattach(struct diofb *fb)
    302 {
    303 	long defattr;
    304 	struct rasops_info *ri;
    305 
    306 	ri = &fb->ri;
    307 	ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
    308 	wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr);
    309 }
    310 
    311 void
    312 diofb_end_attach(device_t self, struct wsdisplay_accessops *accessops,
    313     struct diofb *fb, int console, const char *descr)
    314 {
    315 	struct wsemuldisplaydev_attach_args waa;
    316 
    317 	aprint_normal(": %dx%d", fb->dwidth, fb->dheight);
    318 
    319 	if (fb->planes == 1)
    320 		aprint_normal(" monochrome");
    321 	else
    322 		aprint_normal("x%d", fb->planes);
    323 
    324 	if (descr != NULL)
    325 		aprint_normal(" %s", descr);
    326 	aprint_normal(" frame buffer\n");
    327 
    328 	fb->scrlist[0] = &fb->wsd;
    329 	fb->wsl.nscreens = 1;
    330 	fb->wsl.screens = (void *)fb->scrlist;
    331 
    332 	waa.console = console;
    333 	waa.scrdata = &fb->wsl;
    334 	waa.accessops = accessops;
    335 	waa.accesscookie = fb;
    336 
    337 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
    338 }
    339 
    340 /*
    341  * Common wsdisplay emulops for DIO frame buffers
    342  */
    343 
    344 int
    345 diofb_allocattr(void *cookie, int fg, int bg, int flg, long *attr)
    346 {
    347 
    348 	if ((flg & (WSATTR_BLINK | WSATTR_HILIT)) != 0)
    349 		return EINVAL;
    350 
    351 	if ((flg & WSATTR_WSCOLORS) == 0) {
    352 		fg = WSCOL_WHITE;
    353 		bg = WSCOL_BLACK;
    354 	}
    355 
    356 	if ((flg & WSATTR_REVERSE) != 0) {
    357 		int swap;
    358 		swap = fg;
    359 		fg = bg;
    360 		bg = swap;
    361 	}
    362 
    363 	flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
    364 
    365 	*attr = (bg << 16) | (fg << 24) | flg;
    366 
    367 	return 0;
    368 }
    369 
    370 void
    371 diofb_copycols(void *cookie, int row, int src, int dst, int n)
    372 {
    373 	struct rasops_info *ri = cookie;
    374 	struct diofb *fb = ri->ri_hw;
    375 
    376 	n *= ri->ri_font->fontwidth;
    377 	src *= ri->ri_font->fontwidth;
    378 	dst *= ri->ri_font->fontwidth;
    379 	row *= ri->ri_font->fontheight;
    380 
    381 	(*fb->bmv)(fb, ri->ri_xorigin + src, ri->ri_yorigin + row,
    382 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
    383 	    n, ri->ri_font->fontheight, RR_COPY, 0xff);
    384 }
    385 
    386 void
    387 diofb_copyrows(void *cookie, int src, int dst, int n)
    388 {
    389 	struct rasops_info *ri = cookie;
    390 	struct diofb *fb = ri->ri_hw;
    391 
    392 	n *= ri->ri_font->fontheight;
    393 	src *= ri->ri_font->fontheight;
    394 	dst *= ri->ri_font->fontheight;
    395 
    396 	(*fb->bmv)(fb, ri->ri_xorigin, ri->ri_yorigin + src,
    397 	    ri->ri_xorigin, ri->ri_yorigin + dst,
    398 	    ri->ri_emuwidth, n, RR_COPY, 0xff);
    399 }
    400 
    401 void
    402 diofb_erasecols(void *cookie, int row, int col, int num, long attr)
    403 {
    404 	struct rasops_info *ri = cookie;
    405 	struct diofb *fb = ri->ri_hw;
    406 	int fg, bg;
    407 	int snum, scol, srow;
    408 
    409 	rasops_unpack_attr(attr, &fg, &bg, NULL);
    410 
    411 	snum = num * ri->ri_font->fontwidth;
    412 	scol = col * ri->ri_font->fontwidth + ri->ri_xorigin;
    413 	srow = row * ri->ri_font->fontheight + ri->ri_yorigin;
    414 
    415 	/*
    416 	 * If this is too tricky for the simple raster ops engine,
    417 	 * pass the fun to rasops.
    418 	 */
    419 	if ((*fb->bmv)(fb, scol, srow, scol, srow, snum,
    420 	    ri->ri_font->fontheight, RR_CLEAR, 0xff ^ bg) != 0)
    421 		rasops_erasecols(cookie, row, col, num, attr);
    422 }
    423 
    424 void
    425 diofb_eraserows(void *cookie, int row, int num, long attr)
    426 {
    427 	struct rasops_info *ri = cookie;
    428 	struct diofb *fb = ri->ri_hw;
    429 	int fg, bg;
    430 	int srow, snum;
    431 	int rc;
    432 
    433 	rasops_unpack_attr(attr, &fg, &bg, NULL);
    434 	bg ^= 0xff;
    435 
    436 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) {
    437 		rc = (*fb->bmv)(fb, 0, 0, 0, 0, ri->ri_width, ri->ri_height,
    438 		    RR_CLEAR, bg);
    439 	} else {
    440 		srow = row * ri->ri_font->fontheight + ri->ri_yorigin;
    441 		snum = num * ri->ri_font->fontheight;
    442 		rc = (*fb->bmv)(fb, ri->ri_xorigin, srow, ri->ri_xorigin,
    443 		    srow, ri->ri_emuwidth, snum, RR_CLEAR, bg);
    444 	}
    445 	if (rc != 0)
    446 		rasops_eraserows(cookie, row, num, attr);
    447 }
    448 
    449 void
    450 diofb_do_cursor(struct rasops_info *ri)
    451 {
    452 	struct diofb *fb = ri->ri_hw;
    453 	int x, y;
    454 
    455 	x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
    456 	y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
    457 	(*fb->bmv)(fb, x, y, x, y, ri->ri_font->fontwidth,
    458 	    ri->ri_font->fontheight, RR_INVERT, 0xff);
    459 }
    460 
    461 /*
    462  * Common wsdisplay accessops for DIO frame buffers
    463  */
    464 
    465 int
    466 diofb_alloc_screen(void *v, const struct wsscreen_descr *type,
    467     void **cookiep, int *curxp, int *curyp, long *attrp)
    468 {
    469 	struct diofb *fb = v;
    470 	struct rasops_info *ri = &fb->ri;
    471 
    472 	if (fb->nscreens > 0)
    473 		return ENOMEM;
    474 
    475 	*cookiep = ri;
    476 	*curxp = *curyp = 0;
    477 	ri->ri_ops.allocattr(ri, 0, 0, 0, attrp);
    478 	fb->nscreens++;
    479 
    480 	return 0;
    481 }
    482 
    483 void
    484 diofb_free_screen(void *v, void *cookie)
    485 {
    486 	struct diofb *fb = v;
    487 
    488 	fb->nscreens--;
    489 }
    490 
    491 int
    492 diofb_show_screen(void *v, void *cookie, int waitok,
    493     void (*cb)(void *, int, int), void *cbarg)
    494 {
    495 
    496 	return 0;
    497 }
    498 
    499 paddr_t
    500 diofb_mmap(void *v, void *vs, off_t offset, int prot)
    501 {
    502 	struct diofb *fb = v;
    503 
    504 	if ((offset & PAGE_MASK) != 0)
    505 		return -1;
    506 
    507 	switch (fb->mapmode) {
    508 	case WSDISPLAYIO_MODE_MAPPED:
    509 		if (offset >= 0 && offset < DIOFB_REGSPACE)
    510 			return m68k_btop(fb->regaddr + offset);
    511 		offset -= DIOFB_REGSPACE;
    512 		/* FALLTHROUGH */
    513 	case WSDISPLAYIO_MODE_DUMBFB:
    514 		if (offset >= 0 && offset < fb->fbsize)
    515 			return m68k_btop(fb->fbaddr + offset);
    516 		break;
    517 	}
    518 
    519 	return -1;
    520 }
    521 
    522 int
    523 diofb_getcmap(struct diofb *fb, struct wsdisplay_cmap *cm)
    524 {
    525 	u_int index = cm->index, count = cm->count;
    526 	u_int colcount = 1 << fb->planes;
    527 	int error;
    528 
    529 	if (index >= colcount || count > colcount - index)
    530 		return EINVAL;
    531 
    532 	if ((error = copyout(fb->cmap.r + index, cm->red, count)) != 0)
    533 		return error;
    534 	if ((error = copyout(fb->cmap.g + index, cm->green, count)) != 0)
    535 		return error;
    536 	if ((error = copyout(fb->cmap.b + index, cm->blue, count)) != 0)
    537 		return error;
    538 
    539 	return 0;
    540 }
    541