1 /*        $NetBSD: diofb.c,v 1.10 2024/05/01 19:28:33 tsutsui 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
diofb_fbinquire(struct diofb * fb,int scode,struct diofbreg * fbr)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           fb->planes = fbr->num_planes;
150           if (fb->planes > 8)
151                     fb->planes = 8;
152           fb->planemask = (1 << fb->planes) - 1;
153 
154           fb->mapmode = WSDISPLAYIO_MODE_DUMBFB;
155 
156           return 0;
157 }
158 
159 /*
160  * Frame buffer rasops and colormap setup
161  */
162 
163 void
diofb_fbsetup(struct diofb * fb)164 diofb_fbsetup(struct diofb *fb)
165 {
166           struct rasops_info *ri = &fb->ri;
167 
168           /*
169            * Pretend we are an 8bpp frame buffer, unless ri_depth is already
170            * initialized, since this is how it is supposed to be addressed.
171            * (Hyperion forces 1bpp because it is really 1bpp addressed).
172            */
173           if (ri->ri_depth == 0)
174                     ri->ri_depth = 8;
175           ri->ri_stride = (fb->fbwidth * ri->ri_depth) / 8;
176 
177           ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
178           /* We don't really support colors on less than 4bpp frame buffers */
179           if (fb->planes < 4)
180                     ri->ri_flg |= RI_FORCEMONO;
181           if (fb == &diofb_cn)
182                     ri->ri_flg |= RI_NO_AUTO;
183           ri->ri_bits = fb->fbkva;
184           ri->ri_width = fb->dwidth;
185           ri->ri_height = fb->dheight;
186           ri->ri_hw = fb;
187 
188           /*
189            * Ask for an unholy big display, rasops will trim this to more
190            * reasonable values.
191            */
192           rasops_init(ri, 160, 160);
193 
194           diofb_resetcmap(fb);
195 
196           /*
197            * For low depth frame buffers, since we have faked a 8bpp frame buffer
198            * to rasops, we actually have to remove capabilities.
199            */
200           if (fb->planes == 4) {
201                     ri->ri_ops.allocattr = diofb_allocattr;
202                     ri->ri_caps &= ~WSSCREEN_HILIT;
203           }
204 
205           ri->ri_ops.copycols = diofb_copycols;
206           ri->ri_ops.erasecols = diofb_erasecols;
207           if (ri->ri_depth != 1) {
208                     ri->ri_ops.copyrows = diofb_copyrows;
209                     ri->ri_ops.eraserows = diofb_eraserows;
210                     ri->ri_do_cursor = diofb_do_cursor;
211           }
212 
213           /* Clear entire display, including non visible areas */
214           (*fb->bmv)(fb, 0, 0, 0, 0, fb->fbwidth, fb->fbheight, RR_CLEAR, 0xff);
215 
216           fb->wsd.name = fb->wsdname;
217           fb->wsd.ncols = ri->ri_cols;
218           fb->wsd.nrows = ri->ri_rows;
219           fb->wsd.textops = &ri->ri_ops;
220           fb->wsd.fontwidth = ri->ri_font->fontwidth;
221           fb->wsd.fontheight = ri->ri_font->fontheight;
222           fb->wsd.capabilities = ri->ri_caps;
223           strlcpy(fb->wsdname, "std", sizeof(fb->wsdname));
224 }
225 
226 /*
227  * Setup default emulation mode colormap
228  */
229 void
diofb_resetcmap(struct diofb * fb)230 diofb_resetcmap(struct diofb *fb)
231 {
232           const u_char *color;
233           u_int i;
234 
235           /* start with the rasops colormap */
236           color = (const u_char *)rasops_cmap;
237           for (i = 0; i < 256; i++) {
238                     fb->cmap.r[i] = *color++;
239                     fb->cmap.g[i] = *color++;
240                     fb->cmap.b[i] = *color++;
241           }
242 
243           /*
244            * Tweak colormap
245            *
246            * Due to the way rasops cursor work, we need to provide
247            * copies of the 8 or 16 basic colors at extra locations
248            * in 4bpp and 6bpp mode. This is because missing planes
249            * accept writes but read back as zero.
250            *
251            * So, in 6bpp mode:
252            *   00 gets inverted to ff, read back as 3f
253            *   3f gets inverted to c0, read back as 00
254            * and in 4bpp mode:
255            *   00 gets inverted to ff, read back as 0f
256            *   0f gets inverted to f0, read back as 00
257            */
258 
259           switch (fb->planes) {
260           case 6:
261                     /*
262                      * 00-0f normal colors
263                      * 30-3f inverted colors
264                      * c0-cf normal colors
265                      * f0-ff inverted colors
266                      */
267                     memcpy(fb->cmap.r + 0xc0, fb->cmap.r + 0x00, 0x10);
268                     memcpy(fb->cmap.g + 0xc0, fb->cmap.g + 0x00, 0x10);
269                     memcpy(fb->cmap.b + 0xc0, fb->cmap.b + 0x00, 0x10);
270                     memcpy(fb->cmap.r + 0x30, fb->cmap.r + 0xf0, 0x10);
271                     memcpy(fb->cmap.g + 0x30, fb->cmap.g + 0xf0, 0x10);
272                     memcpy(fb->cmap.b + 0x30, fb->cmap.b + 0xf0, 0x10);
273                     break;
274           case 4:
275                     /*
276                      * 00-07 normal colors
277                      * 08-0f inverted colors
278                      * highlighted colors are not available.
279                      */
280                     memcpy(fb->cmap.r + 0x08, fb->cmap.r + 0xf8, 0x08);
281                     memcpy(fb->cmap.g + 0x08, fb->cmap.g + 0xf8, 0x08);
282                     memcpy(fb->cmap.b + 0x08, fb->cmap.b + 0xf8, 0x08);
283                     break;
284           }
285 }
286 
287 /*
288  * Attachment helpers
289  */
290 
291 void
diofb_cnattach(struct diofb * fb)292 diofb_cnattach(struct diofb *fb)
293 {
294           long defattr;
295           struct rasops_info *ri;
296 
297           ri = &fb->ri;
298           ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
299           wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr);
300 }
301 
302 void
diofb_end_attach(device_t self,struct wsdisplay_accessops * accessops,struct diofb * fb,int console,const char * descr)303 diofb_end_attach(device_t self, struct wsdisplay_accessops *accessops,
304     struct diofb *fb, int console, const char *descr)
305 {
306           struct wsemuldisplaydev_attach_args waa;
307 
308           aprint_normal(": %dx%d", fb->dwidth, fb->dheight);
309 
310           if (fb->planes == 1)
311                     aprint_normal(" monochrome");
312           else
313                     aprint_normal("x%d", fb->planes);
314 
315           if (descr != NULL)
316                     aprint_normal(" %s", descr);
317           aprint_normal(" frame buffer\n");
318 
319           fb->scrlist[0] = &fb->wsd;
320           fb->wsl.nscreens = 1;
321           fb->wsl.screens = (void *)fb->scrlist;
322 
323           waa.console = console;
324           waa.scrdata = &fb->wsl;
325           waa.accessops = accessops;
326           waa.accesscookie = fb;
327 
328           config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
329 }
330 
331 /*
332  * Common wsdisplay emulops for DIO frame buffers
333  */
334 
335 int
diofb_allocattr(void * cookie,int fg,int bg,int flg,long * attr)336 diofb_allocattr(void *cookie, int fg, int bg, int flg, long *attr)
337 {
338 
339           if ((flg & (WSATTR_BLINK | WSATTR_HILIT)) != 0)
340                     return EINVAL;
341 
342           if ((flg & WSATTR_WSCOLORS) == 0) {
343                     fg = WSCOL_WHITE;
344                     bg = WSCOL_BLACK;
345           }
346 
347           if ((flg & WSATTR_REVERSE) != 0) {
348                     int swap;
349                     swap = fg;
350                     fg = bg;
351                     bg = swap;
352           }
353 
354           *attr = (bg << 16) | (fg << 24) | (flg & WSATTR_UNDERLINE);
355 
356           return 0;
357 }
358 
359 void
diofb_copycols(void * cookie,int row,int src,int dst,int n)360 diofb_copycols(void *cookie, int row, int src, int dst, int n)
361 {
362           struct rasops_info *ri = cookie;
363           struct diofb *fb = ri->ri_hw;
364           int fontwidth = fb->wsd.fontwidth;
365 
366           n *= fontwidth;
367           src *= fontwidth;
368           dst *= fontwidth;
369           row *= ri->ri_font->fontheight;
370 
371           (*fb->bmv)(fb, ri->ri_xorigin + src, ri->ri_yorigin + row,
372               ri->ri_xorigin + dst, ri->ri_yorigin + row,
373               n, ri->ri_font->fontheight, RR_COPY, 0xff);
374 }
375 
376 void
diofb_copyrows(void * cookie,int src,int dst,int n)377 diofb_copyrows(void *cookie, int src, int dst, int n)
378 {
379           struct rasops_info *ri = cookie;
380           struct diofb *fb = ri->ri_hw;
381 
382           n *= ri->ri_font->fontheight;
383           src *= ri->ri_font->fontheight;
384           dst *= ri->ri_font->fontheight;
385 
386           (*fb->bmv)(fb, ri->ri_xorigin, ri->ri_yorigin + src,
387               ri->ri_xorigin, ri->ri_yorigin + dst,
388               ri->ri_emuwidth, n, RR_COPY, 0xff);
389 }
390 
391 void
diofb_erasecols(void * cookie,int row,int col,int num,long attr)392 diofb_erasecols(void *cookie, int row, int col, int num, long attr)
393 {
394           struct rasops_info *ri = cookie;
395           struct diofb *fb = ri->ri_hw;
396           int fg, bg;
397           int snum, scol, srow;
398           int fontwidth = fb->wsd.fontwidth;
399 
400           rasops_unpack_attr(attr, &fg, &bg, NULL);
401 
402           snum = num * fontwidth;
403           scol = col * fontwidth + ri->ri_xorigin;
404           srow = row * ri->ri_font->fontheight + ri->ri_yorigin;
405 
406           /*
407            * If this is too tricky for the simple raster ops engine,
408            * pass the fun to rasops.
409            */
410           if ((*fb->bmv)(fb, scol, srow, scol, srow, snum,
411               ri->ri_font->fontheight, RR_CLEAR, 0xff ^ bg) != 0)
412                     rasops_erasecols(cookie, row, col, num, attr);
413 }
414 
415 void
diofb_eraserows(void * cookie,int row,int num,long attr)416 diofb_eraserows(void *cookie, int row, int num, long attr)
417 {
418           struct rasops_info *ri = cookie;
419           struct diofb *fb = ri->ri_hw;
420           int fg, bg;
421           int srow, snum;
422           int rc;
423 
424           rasops_unpack_attr(attr, &fg, &bg, NULL);
425           bg ^= 0xff;
426 
427           if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) {
428                     rc = (*fb->bmv)(fb, 0, 0, 0, 0, fb->fbwidth, ri->ri_height,
429                         RR_CLEAR, bg);
430           } else {
431                     srow = row * ri->ri_font->fontheight + ri->ri_yorigin;
432                     snum = num * ri->ri_font->fontheight;
433                     rc = (*fb->bmv)(fb, ri->ri_xorigin, srow, ri->ri_xorigin,
434                         srow, ri->ri_emuwidth, snum, RR_CLEAR, bg);
435           }
436           if (rc != 0)
437                     rasops_eraserows(cookie, row, num, attr);
438 }
439 
440 void
diofb_do_cursor(struct rasops_info * ri)441 diofb_do_cursor(struct rasops_info *ri)
442 {
443           struct diofb *fb = ri->ri_hw;
444           int x, y;
445           int fontwidth = fb->wsd.fontwidth;
446 
447           x = ri->ri_ccol * fontwidth + ri->ri_xorigin;
448           y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
449           (*fb->bmv)(fb, x, y, x, y, fontwidth,
450               ri->ri_font->fontheight, RR_INVERT, 0xff);
451 }
452 
453 /*
454  * Common wsdisplay accessops for DIO frame buffers
455  */
456 
457 int
diofb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)458 diofb_alloc_screen(void *v, const struct wsscreen_descr *type,
459     void **cookiep, int *curxp, int *curyp, long *attrp)
460 {
461           struct diofb *fb = v;
462           struct rasops_info *ri = &fb->ri;
463 
464           if (fb->nscreens > 0)
465                     return ENOMEM;
466 
467           *cookiep = ri;
468           *curxp = *curyp = 0;
469           ri->ri_ops.allocattr(ri, 0, 0, 0, attrp);
470           fb->nscreens++;
471 
472           return 0;
473 }
474 
475 void
diofb_free_screen(void * v,void * cookie)476 diofb_free_screen(void *v, void *cookie)
477 {
478           struct diofb *fb = v;
479 
480           fb->nscreens--;
481 }
482 
483 int
diofb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)484 diofb_show_screen(void *v, void *cookie, int waitok,
485     void (*cb)(void *, int, int), void *cbarg)
486 {
487 
488           return 0;
489 }
490 
491 paddr_t
diofb_mmap(void * v,void * vs,off_t offset,int prot)492 diofb_mmap(void *v, void *vs, off_t offset, int prot)
493 {
494           struct diofb *fb = v;
495 
496           if ((offset & PAGE_MASK) != 0)
497                     return -1;
498 
499           switch (fb->mapmode) {
500           case WSDISPLAYIO_MODE_MAPPED:
501                     if (offset >= 0 && offset < DIOFB_REGSPACE)
502                               return m68k_btop(fb->regaddr + offset);
503                     offset -= DIOFB_REGSPACE;
504                     /* FALLTHROUGH */
505           case WSDISPLAYIO_MODE_DUMBFB:
506                     if (offset >= 0 && offset < fb->fbsize)
507                               return m68k_btop(fb->fbaddr + offset);
508                     break;
509           }
510 
511           return -1;
512 }
513 
514 int
diofb_getcmap(struct diofb * fb,struct wsdisplay_cmap * cm)515 diofb_getcmap(struct diofb *fb, struct wsdisplay_cmap *cm)
516 {
517           u_int index = cm->index, count = cm->count;
518           u_int colcount = 1 << fb->planes;
519           int error;
520 
521           if (index >= colcount || count > colcount - index)
522                     return EINVAL;
523 
524           if ((error = copyout(fb->cmap.r + index, cm->red, count)) != 0)
525                     return error;
526           if ((error = copyout(fb->cmap.g + index, cm->green, count)) != 0)
527                     return error;
528           if ((error = copyout(fb->cmap.b + index, cm->blue, count)) != 0)
529                     return error;
530 
531           return 0;
532 }
533