xref: /netbsd-src/sys/arch/hp300/dev/diofb.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: diofb.c,v 1.6 2021/04/24 23:36:37 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, CFARG_EOL);
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