1 /* $NetBSD: voyagerfb.c,v 1.34 2023/12/20 05:08:34 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2009, 2011 Michael Lorenz
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 * A console driver for Silicon Motion SM502 / Voyager GX graphics controllers
30 * tested on GDIUM only so far
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: voyagerfb.c,v 1.34 2023/12/20 05:08:34 thorpej Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/lwp.h>
41 #include <sys/kauth.h>
42
43 #include <dev/videomode/videomode.h>
44
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcidevs.h>
48 #include <dev/pci/pciio.h>
49 #include <dev/ic/sm502reg.h>
50
51 #include <dev/wscons/wsdisplayvar.h>
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wsfont/wsfont.h>
54 #include <dev/rasops/rasops.h>
55 #include <dev/wscons/wsdisplay_vconsvar.h>
56 #include <dev/pci/wsdisplay_pci.h>
57
58 #include <dev/i2c/i2cvar.h>
59 #include <dev/pci/voyagervar.h>
60 #include <dev/wscons/wsdisplay_glyphcachevar.h>
61
62 #include "opt_voyagerfb.h"
63
64 #ifdef VOYAGERFB_DEBUG
65 #define DPRINTF aprint_error
66 #else
67 #define DPRINTF while (0) printf
68 #endif
69
70 /* XXX these are gdium-specific */
71 #define GPIO_BACKLIGHT 0x20000000
72
73 struct voyagerfb_softc {
74 device_t sc_dev;
75
76 pci_chipset_tag_t sc_pc;
77 pcitag_t sc_pcitag;
78 bus_space_tag_t sc_memt;
79
80 bus_space_handle_t sc_fbh;
81 bus_space_handle_t sc_regh;
82 bus_addr_t sc_fb, sc_reg;
83 bus_size_t sc_fbsize, sc_regsize;
84
85 int sc_width, sc_height, sc_depth, sc_stride;
86 int sc_locked;
87 void *sc_fbaddr;
88 struct vcons_screen sc_console_screen;
89 struct wsscreen_descr sc_defaultscreen_descr;
90 const struct wsscreen_descr *sc_screens[1];
91 struct wsscreen_list sc_screenlist;
92 struct vcons_data vd;
93 uint8_t *sc_dataport;
94 int sc_mode;
95 int sc_bl_on, sc_bl_level;
96 void *sc_gpio_cookie;
97
98 /* cursor stuff */
99 int sc_cur_x;
100 int sc_cur_y;
101 int sc_hot_x;
102 int sc_hot_y;
103 uint32_t sc_cursor_addr;
104 uint32_t *sc_cursor;
105
106 /* colour map */
107 u_char sc_cmap_red[256];
108 u_char sc_cmap_green[256];
109 u_char sc_cmap_blue[256];
110
111 glyphcache sc_gc;
112 };
113
114 static int voyagerfb_match(device_t, cfdata_t, void *);
115 static void voyagerfb_attach(device_t, device_t, void *);
116
117 CFATTACH_DECL_NEW(voyagerfb, sizeof(struct voyagerfb_softc),
118 voyagerfb_match, voyagerfb_attach, NULL, NULL);
119
120 extern const u_char rasops_cmap[768];
121
122 static int voyagerfb_ioctl(void *, void *, u_long, void *, int,
123 struct lwp *);
124 static paddr_t voyagerfb_mmap(void *, void *, off_t, int);
125 static void voyagerfb_init_screen(void *, struct vcons_screen *, int,
126 long *);
127
128 static int voyagerfb_putcmap(struct voyagerfb_softc *,
129 struct wsdisplay_cmap *);
130 static int voyagerfb_getcmap(struct voyagerfb_softc *,
131 struct wsdisplay_cmap *);
132 static void voyagerfb_restore_palette(struct voyagerfb_softc *);
133 static int voyagerfb_putpalreg(struct voyagerfb_softc *, int, uint8_t,
134 uint8_t, uint8_t);
135
136 static void voyagerfb_init(struct voyagerfb_softc *);
137
138 static void voyagerfb_rectfill(struct voyagerfb_softc *, int, int, int, int,
139 uint32_t);
140 static void voyagerfb_bitblt(void *, int, int, int, int,
141 int, int, int);
142
143 static void voyagerfb_cursor(void *, int, int, int);
144 static void voyagerfb_putchar_mono(void *, int, int, u_int, long);
145 static void voyagerfb_putchar_aa32(void *, int, int, u_int, long);
146 static void voyagerfb_putchar_aa8(void *, int, int, u_int, long);
147 static void voyagerfb_copycols(void *, int, int, int, int);
148 static void voyagerfb_erasecols(void *, int, int, int, long);
149 static void voyagerfb_copyrows(void *, int, int, int);
150 static void voyagerfb_eraserows(void *, int, int, long);
151
152 static int voyagerfb_set_curpos(struct voyagerfb_softc *, int, int);
153 static int voyagerfb_gcursor(struct voyagerfb_softc *,
154 struct wsdisplay_cursor *);
155 static int voyagerfb_scursor(struct voyagerfb_softc *,
156 struct wsdisplay_cursor *);
157
158 struct wsdisplay_accessops voyagerfb_accessops = {
159 voyagerfb_ioctl,
160 voyagerfb_mmap,
161 NULL, /* alloc_screen */
162 NULL, /* free_screen */
163 NULL, /* show_screen */
164 NULL, /* load_font */
165 NULL, /* pollc */
166 NULL /* scroll */
167 };
168
169 static void voyagerfb_setup_backlight(struct voyagerfb_softc *);
170 static void voyagerfb_brightness_up(device_t);
171 static void voyagerfb_brightness_down(device_t);
172 /* set backlight level */
173 static void voyagerfb_set_backlight(struct voyagerfb_softc *, int);
174 /* turn backlight on and off without messing with the level */
175 static void voyagerfb_switch_backlight(struct voyagerfb_softc *, int);
176
177 /* wait for FIFO empty so we can feed it another command */
178 static inline void
voyagerfb_ready(struct voyagerfb_softc * sc)179 voyagerfb_ready(struct voyagerfb_softc *sc)
180 {
181 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh,
182 SM502_SYSTEM_CTRL) & SM502_SYSCTL_FIFO_EMPTY) == 0);
183 }
184
185 /* wait for the drawing engine to be idle */
186 static inline void
voyagerfb_wait(struct voyagerfb_softc * sc)187 voyagerfb_wait(struct voyagerfb_softc *sc)
188 {
189 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh,
190 SM502_SYSTEM_CTRL) & SM502_SYSCTL_ENGINE_BUSY) != 0);
191 }
192
193 static int
voyagerfb_match(device_t parent,cfdata_t match,void * aux)194 voyagerfb_match(device_t parent, cfdata_t match, void *aux)
195 {
196 struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
197
198 if (strcmp(vaa->vaa_name, "voyagerfb") == 0) return 100;
199 return 0;
200 }
201
202 static void
voyagerfb_attach(device_t parent,device_t self,void * aux)203 voyagerfb_attach(device_t parent, device_t self, void *aux)
204 {
205 struct voyagerfb_softc *sc = device_private(self);
206 struct voyager_attach_args *vaa = aux;
207 struct rasops_info *ri;
208 struct wsemuldisplaydev_attach_args aa;
209 prop_dictionary_t dict;
210 unsigned long defattr;
211 uint32_t reg;
212 bool is_console;
213 int i, j;
214 uint8_t cmap[768];
215
216 sc->sc_pc = vaa->vaa_pc;
217 sc->sc_pcitag = vaa->vaa_pcitag;
218 sc->sc_memt = vaa->vaa_tag;
219 sc->sc_dev = self;
220
221 aprint_normal("\n");
222
223 dict = device_properties(self);
224 prop_dictionary_get_bool(dict, "is_console", &is_console);
225
226 sc->sc_fb = vaa->vaa_mem_pa;
227 sc->sc_fbh = vaa->vaa_memh;
228 sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh);
229
230 sc->sc_reg = vaa->vaa_reg_pa;
231 sc->sc_regh = vaa->vaa_regh;
232 sc->sc_regsize = 2 * 1024 * 1024;
233 sc->sc_dataport = bus_space_vaddr(sc->sc_memt, sc->sc_regh);
234 sc->sc_dataport += SM502_DATAPORT;
235
236 sc->sc_gpio_cookie = device_private(parent);
237
238 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_DRAM_CONTROL);
239 switch(reg & 0x0000e000) {
240 case SM502_MEM_2M:
241 sc->sc_fbsize = 2 * 1024 * 1024;
242 break;
243 case SM502_MEM_4M:
244 sc->sc_fbsize = 4 * 1024 * 1024;
245 break;
246 case SM502_MEM_8M:
247 sc->sc_fbsize = 8 * 1024 * 1024;
248 break;
249 case SM502_MEM_16M:
250 sc->sc_fbsize = 16 * 1024 * 1024;
251 break;
252 case SM502_MEM_32M:
253 sc->sc_fbsize = 32 * 1024 * 1024;
254 break;
255 case SM502_MEM_64M:
256 sc->sc_fbsize = 64 * 1024 * 1024;
257 break;
258 }
259
260 sc->sc_width = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
261 SM502_PANEL_FB_WIDTH) & SM502_FBW_WIN_WIDTH_MASK) >> 16;
262 sc->sc_height = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
263 SM502_PANEL_FB_HEIGHT) & SM502_FBH_WIN_HEIGHT_MASK) >> 16;
264
265 #ifdef VOYAGERFB_DEPTH_32
266 sc->sc_depth = 32;
267 #else
268 sc->sc_depth = 8;
269 #endif
270
271 /*
272 * XXX yeah, casting the fb address to uint32_t is formally wrong
273 * but as far as I know there are no SM502 with 64bit BARs
274 */
275 aprint_normal_dev(self, "%d MB video memory at 0x%08x\n",
276 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
277
278 /* init engine here */
279 voyagerfb_init(sc);
280
281 aprint_normal_dev(self, "%d x %d, %d bit, stride %d\n",
282 sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride);
283
284 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
285 "default",
286 0, 0,
287 NULL,
288 8, 16,
289 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
290 WSSCREEN_RESIZE,
291 NULL
292 };
293 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
294 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
295 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
296 sc->sc_locked = 0;
297
298 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
299 &voyagerfb_accessops);
300 sc->vd.init_screen = voyagerfb_init_screen;
301 sc->vd.show_screen_cookie = &sc->sc_gc;
302 sc->vd.show_screen_cb = glyphcache_adapt;
303
304 /* backlight control */
305 voyagerfb_setup_backlight(sc);
306
307 ri = &sc->sc_console_screen.scr_ri;
308
309 sc->sc_gc.gc_bitblt = voyagerfb_bitblt;
310 sc->sc_gc.gc_blitcookie = sc;
311 sc->sc_gc.gc_rop = ROP_COPY;
312 if (is_console) {
313 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
314 &defattr);
315 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
316
317 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
318 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
319 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
320 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
321 } else {
322 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
323 /* do some minimal setup to avoid weirdness later */
324 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
325 &defattr);
326 } else
327 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
328 }
329 glyphcache_init(&sc->sc_gc, sc->sc_height,
330 ((sc->sc_fbsize - 16 * 64) / sc->sc_stride) -
331 sc->sc_height,
332 sc->sc_width,
333 ri->ri_font->fontwidth,
334 ri->ri_font->fontheight,
335 defattr);
336 if (is_console)
337 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
338 defattr);
339
340 rasops_get_cmap(ri, cmap, sizeof(cmap));
341 j = 0;
342 if (sc->sc_depth <= 8) {
343 for (i = 0; i < 256; i++) {
344
345 sc->sc_cmap_red[i] = cmap[j];
346 sc->sc_cmap_green[i] = cmap[j + 1];
347 sc->sc_cmap_blue[i] = cmap[j + 2];
348 voyagerfb_putpalreg(sc, i, cmap[j], cmap[j + 1],
349 cmap[j + 2]);
350 j += 3;
351 }
352 }
353
354 voyagerfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
355 ri->ri_devcmap[(defattr >> 16) & 0xff]);
356
357 if (is_console)
358 vcons_replay_msgbuf(&sc->sc_console_screen);
359
360 aa.console = is_console;
361 aa.scrdata = &sc->sc_screenlist;
362 aa.accessops = &voyagerfb_accessops;
363 aa.accesscookie = &sc->vd;
364
365 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint,
366 CFARGS(.iattr = "wsemuldisplaydev"));
367 }
368
369 static int
voyagerfb_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)370 voyagerfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
371 struct lwp *l)
372 {
373 struct vcons_data *vd = v;
374 struct voyagerfb_softc *sc = vd->cookie;
375 struct wsdisplay_fbinfo *wdf;
376 struct vcons_screen *ms = vd->active;
377 struct wsdisplay_param *param;
378
379 switch (cmd) {
380 case WSDISPLAYIO_GTYPE:
381 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
382 return 0;
383
384 /* PCI config read/write pass through. */
385 case PCI_IOC_CFGREAD:
386 case PCI_IOC_CFGWRITE:
387 return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
388 cmd, data, flag, l);
389
390 case WSDISPLAYIO_GET_BUSID:
391 return wsdisplayio_busid_pci(device_parent(sc->sc_dev),
392 sc->sc_pc, sc->sc_pcitag, data);
393
394 case WSDISPLAYIO_GINFO:
395 if (ms == NULL)
396 return ENODEV;
397 wdf = (void *)data;
398 wdf->height = ms->scr_ri.ri_height;
399 wdf->width = ms->scr_ri.ri_width;
400 wdf->depth = 32;
401 wdf->cmsize = 256;
402 return 0;
403
404 case WSDISPLAYIO_GETCMAP:
405 return voyagerfb_getcmap(sc,
406 (struct wsdisplay_cmap *)data);
407
408 case WSDISPLAYIO_PUTCMAP:
409 return voyagerfb_putcmap(sc,
410 (struct wsdisplay_cmap *)data);
411
412 case WSDISPLAYIO_LINEBYTES:
413 *(u_int *)data = sc->sc_stride;
414 return 0;
415
416 case WSDISPLAYIO_SMODE: {
417 int new_mode = *(int*)data;
418 if (new_mode != sc->sc_mode) {
419 sc->sc_mode = new_mode;
420 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
421 #ifdef VOYAGERFB_DEPTH_32
422 sc->sc_depth = 32;
423 #else
424 sc->sc_depth = 8;
425 #endif
426 glyphcache_wipe(&sc->sc_gc);
427 voyagerfb_init(sc);
428 voyagerfb_restore_palette(sc);
429 vcons_redraw_screen(ms);
430 } else {
431 sc->sc_depth = 32;
432 voyagerfb_init(sc);
433 }
434 }
435 }
436 return 0;
437
438 case WSDISPLAYIO_GVIDEO:
439 *(int *)data = sc->sc_bl_on ? WSDISPLAYIO_VIDEO_ON :
440 WSDISPLAYIO_VIDEO_OFF;
441 return 0;
442
443 case WSDISPLAYIO_SVIDEO: {
444 int new_bl = *(int *)data;
445
446 voyagerfb_switch_backlight(sc, new_bl);
447 }
448 return 0;
449
450 case WSDISPLAYIO_GETPARAM:
451 param = (struct wsdisplay_param *)data;
452 switch (param->param) {
453 case WSDISPLAYIO_PARAM_BRIGHTNESS:
454 param->min = 0;
455 param->max = 255;
456 param->curval = sc->sc_bl_level;
457 return 0;
458 case WSDISPLAYIO_PARAM_BACKLIGHT:
459 param->min = 0;
460 param->max = 1;
461 param->curval = sc->sc_bl_on;
462 return 0;
463 }
464 return EPASSTHROUGH;
465
466 case WSDISPLAYIO_SETPARAM:
467 param = (struct wsdisplay_param *)data;
468 switch (param->param) {
469 case WSDISPLAYIO_PARAM_BRIGHTNESS:
470 voyagerfb_set_backlight(sc, param->curval);
471 return 0;
472 case WSDISPLAYIO_PARAM_BACKLIGHT:
473 voyagerfb_switch_backlight(sc, param->curval);
474 return 0;
475 }
476 return EPASSTHROUGH;
477
478 case WSDISPLAYIO_GCURPOS:
479 {
480 struct wsdisplay_curpos *pos;
481
482 pos = (struct wsdisplay_curpos *)data;
483 pos->x = sc->sc_cur_x;
484 pos->y = sc->sc_cur_y;
485 }
486 return 0;
487
488 case WSDISPLAYIO_SCURPOS:
489 {
490 struct wsdisplay_curpos *pos;
491
492 pos = (struct wsdisplay_curpos *)data;
493 voyagerfb_set_curpos(sc, pos->x, pos->y);
494 }
495 return 0;
496
497 case WSDISPLAYIO_GCURMAX:
498 {
499 struct wsdisplay_curpos *pos;
500
501 pos = (struct wsdisplay_curpos *)data;
502 pos->x = 64;
503 pos->y = 64;
504 }
505 return 0;
506
507 case WSDISPLAYIO_GCURSOR:
508 {
509 struct wsdisplay_cursor *cu;
510
511 cu = (struct wsdisplay_cursor *)data;
512 return voyagerfb_gcursor(sc, cu);
513 }
514
515 case WSDISPLAYIO_SCURSOR:
516 {
517 struct wsdisplay_cursor *cu;
518
519 cu = (struct wsdisplay_cursor *)data;
520 return voyagerfb_scursor(sc, cu);
521 }
522
523 case WSDISPLAYIO_GET_FBINFO:
524 {
525 struct wsdisplayio_fbinfo *fbi = data;
526 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
527 }
528 }
529 return EPASSTHROUGH;
530 }
531
532 static paddr_t
voyagerfb_mmap(void * v,void * vs,off_t offset,int prot)533 voyagerfb_mmap(void *v, void *vs, off_t offset, int prot)
534 {
535 struct vcons_data *vd = v;
536 struct voyagerfb_softc *sc = vd->cookie;
537 paddr_t pa;
538
539 /* 'regular' framebuffer mmap()ing */
540 if (offset < sc->sc_fbsize) {
541 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot,
542 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
543 return pa;
544 }
545
546 /*
547 * restrict all other mappings to processes with privileges
548 */
549 if (kauth_authorize_machdep(kauth_cred_get(),
550 KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) {
551 aprint_normal("%s: mmap() rejected.\n",
552 device_xname(sc->sc_dev));
553 return -1;
554 }
555
556 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
557 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
558 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
559 return pa;
560 }
561
562 if ((offset >= sc->sc_reg) &&
563 (offset < (sc->sc_reg + sc->sc_regsize))) {
564 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 0);
565 return pa;
566 }
567
568 return -1;
569 }
570
571 static void
voyagerfb_init_screen(void * cookie,struct vcons_screen * scr,int existing,long * defattr)572 voyagerfb_init_screen(void *cookie, struct vcons_screen *scr,
573 int existing, long *defattr)
574 {
575 struct voyagerfb_softc *sc = cookie;
576 struct rasops_info *ri = &scr->scr_ri;
577
578 ri->ri_depth = sc->sc_depth;
579 ri->ri_width = sc->sc_width;
580 ri->ri_height = sc->sc_height;
581 ri->ri_stride = sc->sc_stride;
582 ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
583
584 ri->ri_bits = (char *)sc->sc_fbaddr;
585
586 if (existing) {
587 ri->ri_flg |= RI_CLEAR;
588 }
589
590 if (sc->sc_depth == 8) {
591 ri->ri_flg |= RI_8BIT_IS_RGB;
592 #ifdef VOYAGERFB_ANTIALIAS
593 ri->ri_flg |= RI_ENABLE_ALPHA | RI_PREFER_ALPHA;
594 #endif
595 }
596 if (sc->sc_depth == 32) {
597 #ifdef VOYAGERFB_ANTIALIAS
598 ri->ri_flg |= RI_ENABLE_ALPHA;
599 #endif
600 /* we always run in RGB */
601 ri->ri_rnum = 8;
602 ri->ri_gnum = 8;
603 ri->ri_bnum = 8;
604 ri->ri_rpos = 16;
605 ri->ri_gpos = 8;
606 ri->ri_bpos = 0;
607 }
608
609 scr->scr_flags |= VCONS_LOADFONT;
610
611 rasops_init(ri, 0, 0);
612 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
613 WSSCREEN_RESIZE;
614
615 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
616 sc->sc_width / ri->ri_font->fontwidth);
617
618 ri->ri_hw = scr;
619 ri->ri_ops.copyrows = voyagerfb_copyrows;
620 ri->ri_ops.copycols = voyagerfb_copycols;
621 ri->ri_ops.eraserows = voyagerfb_eraserows;
622 ri->ri_ops.erasecols = voyagerfb_erasecols;
623 ri->ri_ops.cursor = voyagerfb_cursor;
624 if (FONT_IS_ALPHA(ri->ri_font)) {
625 switch (sc->sc_depth) {
626 case 32:
627 ri->ri_ops.putchar = voyagerfb_putchar_aa32;
628 break;
629 case 8:
630 ri->ri_ops.putchar = voyagerfb_putchar_aa8;
631 break;
632 default:
633 printf("alpha font at %d!?\n", sc->sc_depth);
634 }
635 } else
636 ri->ri_ops.putchar = voyagerfb_putchar_mono;
637 }
638
639 static int
voyagerfb_putcmap(struct voyagerfb_softc * sc,struct wsdisplay_cmap * cm)640 voyagerfb_putcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
641 {
642 u_char *r, *g, *b;
643 u_int index = cm->index;
644 u_int count = cm->count;
645 int i, error;
646 u_char rbuf[256], gbuf[256], bbuf[256];
647
648 #ifdef VOYAGERFB_DEBUG
649 aprint_debug("putcmap: %d %d\n",index, count);
650 #endif
651 if (cm->index >= 256 || cm->count > 256 ||
652 (cm->index + cm->count) > 256)
653 return EINVAL;
654 error = copyin(cm->red, &rbuf[index], count);
655 if (error)
656 return error;
657 error = copyin(cm->green, &gbuf[index], count);
658 if (error)
659 return error;
660 error = copyin(cm->blue, &bbuf[index], count);
661 if (error)
662 return error;
663
664 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
665 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
666 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
667
668 r = &sc->sc_cmap_red[index];
669 g = &sc->sc_cmap_green[index];
670 b = &sc->sc_cmap_blue[index];
671
672 for (i = 0; i < count; i++) {
673 voyagerfb_putpalreg(sc, index, *r, *g, *b);
674 index++;
675 r++, g++, b++;
676 }
677 return 0;
678 }
679
680 static int
voyagerfb_getcmap(struct voyagerfb_softc * sc,struct wsdisplay_cmap * cm)681 voyagerfb_getcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
682 {
683 u_int index = cm->index;
684 u_int count = cm->count;
685 int error;
686
687 if (index >= 255 || count > 256 || index + count > 256)
688 return EINVAL;
689
690 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
691 if (error)
692 return error;
693 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
694 if (error)
695 return error;
696 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
697 if (error)
698 return error;
699
700 return 0;
701 }
702
703 static void
voyagerfb_restore_palette(struct voyagerfb_softc * sc)704 voyagerfb_restore_palette(struct voyagerfb_softc *sc)
705 {
706 int i;
707
708 for (i = 0; i < 256; i++) {
709 voyagerfb_putpalreg(sc, i, sc->sc_cmap_red[i],
710 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
711 }
712 }
713
714 static int
voyagerfb_putpalreg(struct voyagerfb_softc * sc,int idx,uint8_t r,uint8_t g,uint8_t b)715 voyagerfb_putpalreg(struct voyagerfb_softc *sc, int idx, uint8_t r,
716 uint8_t g, uint8_t b)
717 {
718 uint32_t reg;
719
720 reg = (r << 16) | (g << 8) | b;
721 /* XXX we should probably write the CRT palette too */
722 bus_space_write_4(sc->sc_memt, sc->sc_regh,
723 SM502_PALETTE_PANEL + (idx << 2), reg);
724 return 0;
725 }
726
727 static void
voyagerfb_init(struct voyagerfb_softc * sc)728 voyagerfb_init(struct voyagerfb_softc *sc)
729 {
730 int reg;
731
732 voyagerfb_wait(sc);
733 /* disable colour compare */
734 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_COLOR_COMP_MASK, 0);
735 /* allow writes to all planes */
736 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PLANEMASK,
737 0xffffffff);
738 /* disable clipping */
739 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CLIP_TOP_LEFT, 0);
740 /* source and destination in local memory, no offset */
741 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC_BASE, 0);
742 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST_BASE, 0);
743 /* pitch is screen stride */
744 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PITCH,
745 sc->sc_width | (sc->sc_width << 16));
746 /* window is screen width */
747 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_WINDOW_WIDTH,
748 sc->sc_width | (sc->sc_width << 16));
749 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL);
750 reg &= ~SM502_PDC_DEPTH_MASK;
751
752 switch (sc->sc_depth) {
753 case 8:
754 bus_space_write_4(sc->sc_memt, sc->sc_regh,
755 SM502_STRETCH, SM502_STRETCH_8BIT);
756 sc->sc_stride = sc->sc_width;
757 reg |= SM502_PDC_8BIT;
758 break;
759 case 16:
760 bus_space_write_4(sc->sc_memt, sc->sc_regh,
761 SM502_STRETCH, SM502_STRETCH_16BIT);
762 sc->sc_stride = sc->sc_width << 1;
763 reg |= SM502_PDC_16BIT;
764 break;
765 case 24:
766 case 32:
767 bus_space_write_4(sc->sc_memt, sc->sc_regh,
768 SM502_STRETCH, SM502_STRETCH_32BIT);
769 sc->sc_stride = sc->sc_width << 2;
770 reg |= SM502_PDC_32BIT;
771 break;
772 }
773 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_FB_OFFSET,
774 (sc->sc_stride << 16) | sc->sc_stride);
775
776 /* clear the screen... */
777 voyagerfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
778
779 /* ...and then switch colour depth. For aesthetic reasons. */
780 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL,
781 reg);
782
783 /* put the cursor at the end of video memory */
784 sc->sc_cursor_addr = sc->sc_fbsize - 16 * 64; /* XXX */
785 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr);
786 sc->sc_cursor = (uint32_t *)((uint8_t *)bus_space_vaddr(sc->sc_memt,
787 sc->sc_fbh) + sc->sc_cursor_addr);
788 #ifdef VOYAGERFB_DEBUG
789 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY,
790 0x00100010);
791 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL12,
792 0x0000ffff);
793 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL3,
794 0x0000f800);
795 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR,
796 SM502_CRSR_ENABLE | sc->sc_cursor_addr);
797 sc->sc_cursor[0] = 0x00000000;
798 sc->sc_cursor[1] = 0x00000000;
799 sc->sc_cursor[2] = 0xffffffff;
800 sc->sc_cursor[3] = 0xffffffff;
801 sc->sc_cursor[4] = 0xaaaaaaaa;
802 sc->sc_cursor[5] = 0xaaaaaaaa;
803 sc->sc_cursor[6] = 0xffffffff;
804 sc->sc_cursor[7] = 0x00000000;
805 #else
806 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR,
807 sc->sc_cursor_addr);
808 #endif
809 }
810
811 static void
voyagerfb_rectfill(struct voyagerfb_softc * sc,int x,int y,int wi,int he,uint32_t colour)812 voyagerfb_rectfill(struct voyagerfb_softc *sc, int x, int y, int wi, int he,
813 uint32_t colour)
814 {
815
816 voyagerfb_ready(sc);
817 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL,
818 ROP_COPY |
819 SM502_CTRL_USE_ROP2 |
820 SM502_CTRL_CMD_RECTFILL |
821 SM502_CTRL_QUICKSTART_E);
822 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND,
823 colour);
824 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
825 (x << 16) | y);
826 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
827 (wi << 16) | he);
828 }
829
830 static void
voyagerfb_bitblt(void * cookie,int xs,int ys,int xd,int yd,int wi,int he,int rop)831 voyagerfb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
832 int wi, int he, int rop)
833 {
834 struct voyagerfb_softc *sc = cookie;
835 uint32_t cmd;
836
837 cmd = (rop & 0xf) | SM502_CTRL_USE_ROP2 | SM502_CTRL_CMD_BITBLT |
838 SM502_CTRL_QUICKSTART_E;
839
840 voyagerfb_ready(sc);
841
842 if (xd <= xs) {
843 /* left to right */
844 } else {
845 /*
846 * According to the manual this flag reverses only the blitter's
847 * X direction. At least on my Gdium it also reverses the Y
848 * direction
849 */
850 cmd |= SM502_CTRL_R_TO_L;
851 xs += wi - 1;
852 xd += wi - 1;
853 ys += he - 1;
854 yd += he - 1;
855 }
856
857 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
858 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC,
859 (xs << 16) | ys);
860 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
861 (xd << 16) | yd);
862 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
863 (wi << 16) | he);
864 }
865
866 static void
voyagerfb_cursor(void * cookie,int on,int row,int col)867 voyagerfb_cursor(void *cookie, int on, int row, int col)
868 {
869 struct rasops_info *ri = cookie;
870 struct vcons_screen *scr = ri->ri_hw;
871 struct voyagerfb_softc *sc = scr->scr_cookie;
872 int x, y, wi, he;
873
874 wi = ri->ri_font->fontwidth;
875 he = ri->ri_font->fontheight;
876
877 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
878 x = ri->ri_ccol * wi + ri->ri_xorigin;
879 y = ri->ri_crow * he + ri->ri_yorigin;
880 if (ri->ri_flg & RI_CURSOR) {
881 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
882 ri->ri_flg &= ~RI_CURSOR;
883 }
884 ri->ri_crow = row;
885 ri->ri_ccol = col;
886 if (on) {
887 x = ri->ri_ccol * wi + ri->ri_xorigin;
888 y = ri->ri_crow * he + ri->ri_yorigin;
889 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
890 ri->ri_flg |= RI_CURSOR;
891 }
892 } else {
893 scr->scr_ri.ri_crow = row;
894 scr->scr_ri.ri_ccol = col;
895 scr->scr_ri.ri_flg &= ~RI_CURSOR;
896 }
897
898 }
899
900 static inline void
voyagerfb_feed8(struct voyagerfb_softc * sc,uint8_t * data,int len)901 voyagerfb_feed8(struct voyagerfb_softc *sc, uint8_t *data, int len)
902 {
903 uint32_t *port = (uint32_t *)sc->sc_dataport;
904 int i;
905
906 for (i = 0; i < ((len + 3) & 0xfffc); i++) {
907 *port = *data;
908 data++;
909 }
910 }
911
912 static inline void
voyagerfb_feed16(struct voyagerfb_softc * sc,uint16_t * data,int len)913 voyagerfb_feed16(struct voyagerfb_softc *sc, uint16_t *data, int len)
914 {
915 uint32_t *port = (uint32_t *)sc->sc_dataport;
916 int i;
917
918 len = len << 1;
919 for (i = 0; i < ((len + 1) & 0xfffe); i++) {
920 *port = *data;
921 data++;
922 }
923 }
924
925 static void
voyagerfb_putchar_mono(void * cookie,int row,int col,u_int c,long attr)926 voyagerfb_putchar_mono(void *cookie, int row, int col, u_int c, long attr)
927 {
928 struct rasops_info *ri = cookie;
929 struct wsdisplay_font *font = PICK_FONT(ri, c);
930 struct vcons_screen *scr = ri->ri_hw;
931 struct voyagerfb_softc *sc = scr->scr_cookie;
932 uint32_t cmd;
933 int fg, bg;
934 uint8_t *data;
935 int x, y, wi, he;
936
937 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
938 return;
939
940 if (!CHAR_IN_FONT(c, font))
941 return;
942
943 wi = font->fontwidth;
944 he = font->fontheight;
945
946 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
947 fg = ri->ri_devcmap[(attr >> 24) & 0x0f];
948 x = ri->ri_xorigin + col * wi;
949 y = ri->ri_yorigin + row * he;
950 if (c == 0x20) {
951 voyagerfb_rectfill(sc, x, y, wi, he, bg);
952 return;
953 }
954
955 data = WSFONT_GLYPH(c, font);
956
957 cmd = ROP_COPY |
958 SM502_CTRL_USE_ROP2 |
959 SM502_CTRL_CMD_HOSTWRT |
960 SM502_CTRL_HOSTBLT_MONO |
961 SM502_CTRL_QUICKSTART_E |
962 SM502_CTRL_MONO_PACK_32BIT;
963 voyagerfb_ready(sc);
964 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
965 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND, fg);
966 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_BACKGROUND, bg);
967 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0);
968 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y);
969 bus_space_write_4(sc->sc_memt, sc->sc_regh,
970 SM502_DIMENSION, (wi << 16) | he);
971 /* now feed the data, padded to 32bit */
972 switch (ri->ri_font->stride) {
973 case 1:
974 voyagerfb_feed8(sc, data, ri->ri_fontscale);
975 break;
976 case 2:
977 voyagerfb_feed16(sc, (uint16_t *)data,
978 ri->ri_fontscale);
979 break;
980 }
981 }
982
983 static void
voyagerfb_putchar_aa32(void * cookie,int row,int col,u_int c,long attr)984 voyagerfb_putchar_aa32(void *cookie, int row, int col, u_int c, long attr)
985 {
986 struct rasops_info *ri = cookie;
987 struct wsdisplay_font *font = PICK_FONT(ri, c);
988 struct vcons_screen *scr = ri->ri_hw;
989 struct voyagerfb_softc *sc = scr->scr_cookie;
990 uint32_t cmd;
991 int fg, bg;
992 uint8_t *data;
993 int x, y, wi, he;
994 int i, j, r, g, b, aval, pad;
995 int rf, gf, bf, rb, gb, bb;
996 uint32_t pixel;
997 int rv;
998
999 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1000 return;
1001
1002 if (!CHAR_IN_FONT(c, font))
1003 return;
1004
1005 wi = font->fontwidth;
1006 he = font->fontheight;
1007
1008 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
1009 fg = ri->ri_devcmap[(attr >> 24) & 0x0f];
1010 x = ri->ri_xorigin + col * wi;
1011 y = ri->ri_yorigin + row * he;
1012 if (c == 0x20) {
1013 voyagerfb_rectfill(sc, x, y, wi, he, bg);
1014 return;
1015 }
1016
1017 data = WSFONT_GLYPH(c, font);
1018 /*
1019 * we can't accelerate the actual alpha blending but
1020 * we can at least use a host blit to go through the
1021 * pipeline instead of having to sync the engine
1022 */
1023
1024 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1025 if (rv == GC_OK)
1026 return;
1027
1028 cmd = ROP_COPY |
1029 SM502_CTRL_USE_ROP2 |
1030 SM502_CTRL_CMD_HOSTWRT |
1031 SM502_CTRL_QUICKSTART_E;
1032 voyagerfb_ready(sc);
1033 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
1034 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0);
1035 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y);
1036 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
1037 (wi << 16) | he);
1038 rf = (fg >> 16) & 0xff;
1039 rb = (bg >> 16) & 0xff;
1040 gf = (fg >> 8) & 0xff;
1041 gb = (bg >> 8) & 0xff;
1042 bf = fg & 0xff;
1043 bb = bg & 0xff;
1044 pad = wi & 1;
1045 for (i = 0; i < he; i++) {
1046 for (j = 0; j < wi; j++) {
1047 aval = *data;
1048 data++;
1049 if (aval == 0) {
1050 pixel = bg;
1051 } else if (aval == 255) {
1052 pixel = fg;
1053 } else {
1054 r = aval * rf + (255 - aval) * rb;
1055 g = aval * gf + (255 - aval) * gb;
1056 b = aval * bf + (255 - aval) * bb;
1057 pixel = (r & 0xff00) << 8 |
1058 (g & 0xff00) |
1059 (b & 0xff00) >> 8;
1060 }
1061 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1062 SM502_DATAPORT, pixel);
1063 }
1064 if (pad)
1065 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1066 SM502_DATAPORT, 0);
1067 }
1068 if (rv == GC_ADD) {
1069 glyphcache_add(&sc->sc_gc, c, x, y);
1070 }
1071 }
1072
1073 static void
voyagerfb_putchar_aa8(void * cookie,int row,int col,u_int c,long attr)1074 voyagerfb_putchar_aa8(void *cookie, int row, int col, u_int c, long attr)
1075 {
1076 struct rasops_info *ri = cookie;
1077 struct wsdisplay_font *font = PICK_FONT(ri, c);
1078 struct vcons_screen *scr = ri->ri_hw;
1079 struct voyagerfb_softc *sc = scr->scr_cookie;
1080 uint32_t cmd;
1081 int bg;
1082 uint8_t *data;
1083 int x, y, wi, he;
1084 int i, j, r, g, b, aval, pad;
1085 int r1, g1, b1, r0, g0, b0, fgo, bgo;
1086 uint32_t pixel = 0, latch = 0, bg8, fg8;
1087 int rv;
1088
1089 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1090 return;
1091
1092 if (!CHAR_IN_FONT(c, font))
1093 return;
1094
1095 wi = font->fontwidth;
1096 he = font->fontheight;
1097
1098 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
1099 x = ri->ri_xorigin + col * wi;
1100 y = ri->ri_yorigin + row * he;
1101 if (c == 0x20) {
1102 voyagerfb_rectfill(sc, x, y, wi, he, bg);
1103 return;
1104 }
1105
1106 data = WSFONT_GLYPH(c, font);
1107 /*
1108 * we can't accelerate the actual alpha blending but
1109 * we can at least use a host blit to go through the
1110 * pipeline instead of having to sync the engine
1111 */
1112
1113 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1114 if (rv == GC_OK)
1115 return;
1116
1117 cmd = ROP_COPY |
1118 SM502_CTRL_USE_ROP2 |
1119 SM502_CTRL_CMD_HOSTWRT |
1120 SM502_CTRL_QUICKSTART_E;
1121 voyagerfb_ready(sc);
1122 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
1123 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0);
1124 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y);
1125 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
1126 (wi << 16) | he);
1127
1128 /*
1129 * we need the RGB colours here, so get offsets into rasops_cmap
1130 */
1131 fgo = ((attr >> 24) & 0xf) * 3;
1132 bgo = ((attr >> 16) & 0xf) * 3;
1133
1134 r0 = rasops_cmap[bgo];
1135 r1 = rasops_cmap[fgo];
1136 g0 = rasops_cmap[bgo + 1];
1137 g1 = rasops_cmap[fgo + 1];
1138 b0 = rasops_cmap[bgo + 2];
1139 b1 = rasops_cmap[fgo + 2];
1140 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6))
1141 bg8 = R3G3B2(r0, g0, b0);
1142 fg8 = R3G3B2(r1, g1, b1);
1143
1144 pad = wi & 4;
1145 for (i = 0; i < he; i++) {
1146 for (j = 0; j < wi; j++) {
1147 aval = *data;
1148 data++;
1149 if (aval == 0) {
1150 pixel = bg8;
1151 } else if (aval == 255) {
1152 pixel = fg8;
1153 } else {
1154 r = aval * r1 + (255 - aval) * r0;
1155 g = aval * g1 + (255 - aval) * g0;
1156 b = aval * b1 + (255 - aval) * b0;
1157 pixel = ((r & 0xe000) >> 8) |
1158 ((g & 0xe000) >> 11) |
1159 ((b & 0xc000) >> 14);
1160 }
1161 latch = (latch << 8) | pixel;
1162 /* write in 32bit chunks */
1163 if ((j & 3) == 3) {
1164 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1165 SM502_DATAPORT, be32toh(latch));
1166 latch = 0;
1167 }
1168 }
1169 /* if we have pixels left in latch write them out */
1170 if ((j & 3) != 0) {
1171 latch = latch << ((4 - (i & 3)) << 3);
1172 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1173 SM502_DATAPORT, be32toh(latch));
1174 }
1175 if (pad)
1176 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1177 SM502_DATAPORT, 0);
1178 }
1179 if (rv == GC_ADD) {
1180 glyphcache_add(&sc->sc_gc, c, x, y);
1181 }
1182 }
1183
1184 static void
voyagerfb_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)1185 voyagerfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1186 {
1187 struct rasops_info *ri = cookie;
1188 struct vcons_screen *scr = ri->ri_hw;
1189 struct voyagerfb_softc *sc = scr->scr_cookie;
1190 int32_t xs, xd, y, width, height;
1191
1192 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1193 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1194 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1195 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1196 width = ri->ri_font->fontwidth * ncols;
1197 height = ri->ri_font->fontheight;
1198 voyagerfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY);
1199 }
1200 }
1201
1202 static void
voyagerfb_erasecols(void * cookie,int row,int startcol,int ncols,long fillattr)1203 voyagerfb_erasecols(void *cookie, int row, int startcol, int ncols,
1204 long fillattr)
1205 {
1206 struct rasops_info *ri = cookie;
1207 struct vcons_screen *scr = ri->ri_hw;
1208 struct voyagerfb_softc *sc = scr->scr_cookie;
1209 int32_t x, y, width, height, fg, bg, ul;
1210
1211 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1212 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1213 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1214 width = ri->ri_font->fontwidth * ncols;
1215 height = ri->ri_font->fontheight;
1216 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1217
1218 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1219 }
1220 }
1221
1222 static void
voyagerfb_copyrows(void * cookie,int srcrow,int dstrow,int nrows)1223 voyagerfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1224 {
1225 struct rasops_info *ri = cookie;
1226 struct vcons_screen *scr = ri->ri_hw;
1227 struct voyagerfb_softc *sc = scr->scr_cookie;
1228 int32_t x, ys, yd, width, height;
1229 int i;
1230
1231 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1232 x = ri->ri_xorigin;
1233 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1234 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1235 width = ri->ri_emuwidth;
1236 height = ri->ri_font->fontheight * nrows;
1237 if ((nrows > 1) && (dstrow > srcrow)) {
1238 /*
1239 * the blitter can't do bottom-up copies so we have
1240 * to copy line by line here
1241 * should probably use a command sequence
1242 */
1243 ys += (height - ri->ri_font->fontheight);
1244 yd += (height - ri->ri_font->fontheight);
1245 for (i = 0; i < nrows; i++) {
1246 voyagerfb_bitblt(sc, x, ys, x, yd, width,
1247 ri->ri_font->fontheight, ROP_COPY);
1248 ys -= ri->ri_font->fontheight;
1249 yd -= ri->ri_font->fontheight;
1250 }
1251 } else
1252 voyagerfb_bitblt(sc, x, ys, x, yd, width, height,
1253 ROP_COPY);
1254 }
1255 }
1256
1257 static void
voyagerfb_eraserows(void * cookie,int row,int nrows,long fillattr)1258 voyagerfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1259 {
1260 struct rasops_info *ri = cookie;
1261 struct vcons_screen *scr = ri->ri_hw;
1262 struct voyagerfb_softc *sc = scr->scr_cookie;
1263 int32_t x, y, width, height, fg, bg, ul;
1264
1265 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1266 x = ri->ri_xorigin;
1267 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1268 width = ri->ri_emuwidth;
1269 height = ri->ri_font->fontheight * nrows;
1270 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1271
1272 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1273 }
1274 }
1275
1276 /* backlight control */
1277 static void
voyagerfb_setup_backlight(struct voyagerfb_softc * sc)1278 voyagerfb_setup_backlight(struct voyagerfb_softc *sc)
1279 {
1280 /* switch the pin to gpio mode if it isn't already */
1281 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1282 /* turn it on */
1283 voyager_write_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1284 sc->sc_bl_on = 1;
1285 sc->sc_bl_level = 255;
1286 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP,
1287 voyagerfb_brightness_up, TRUE);
1288 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN,
1289 voyagerfb_brightness_down, TRUE);
1290 }
1291
1292 static void
voyagerfb_set_backlight(struct voyagerfb_softc * sc,int level)1293 voyagerfb_set_backlight(struct voyagerfb_softc *sc, int level)
1294 {
1295
1296 /*
1297 * should we do nothing when backlight is off, should we just store the
1298 * level and use it when turning back on or should we just flip sc_bl_on
1299 * and turn the backlight on?
1300 * For now turn it on so a crashed screensaver can't get the user stuck
1301 * with a dark screen as long as hotkeys work
1302 */
1303 if (level > 255) level = 255;
1304 if (level < 0) level = 0;
1305 if (level == sc->sc_bl_level)
1306 return;
1307 sc->sc_bl_level = level;
1308 if (sc->sc_bl_on == 0)
1309 sc->sc_bl_on = 1;
1310 /* and here we would actually muck with the hardware */
1311 if ((level == 0) || (level == 255)) {
1312 /* in these cases bypass the PWM and use the gpio */
1313 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1314 if (level == 0) {
1315 voyager_write_gpio(sc->sc_gpio_cookie,
1316 ~GPIO_BACKLIGHT, 0);
1317 } else {
1318 voyager_write_gpio(sc->sc_gpio_cookie,
1319 0xffffffff, GPIO_BACKLIGHT);
1320 }
1321 } else {
1322 uint32_t pwm;
1323
1324 pwm = voyager_set_pwm(20000, level * 1000 / 256);
1325 pwm |= SM502_PWM_ENABLE;
1326 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM0, pwm);
1327
1328 /* let the PWM take over */
1329 voyager_control_gpio(sc->sc_gpio_cookie,
1330 0xffffffff, GPIO_BACKLIGHT);
1331 }
1332 }
1333
1334 static void
voyagerfb_switch_backlight(struct voyagerfb_softc * sc,int on)1335 voyagerfb_switch_backlight(struct voyagerfb_softc *sc, int on)
1336 {
1337
1338 if (on == sc->sc_bl_on)
1339 return;
1340 sc->sc_bl_on = on;
1341 if (on) {
1342 int level = sc->sc_bl_level;
1343
1344 sc->sc_bl_level = -1;
1345 voyagerfb_set_backlight(sc, level);
1346 } else {
1347 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1348 voyager_write_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1349 }
1350 }
1351
1352
1353 static void
voyagerfb_brightness_up(device_t dev)1354 voyagerfb_brightness_up(device_t dev)
1355 {
1356 struct voyagerfb_softc *sc = device_private(dev);
1357
1358 voyagerfb_set_backlight(sc, sc->sc_bl_level + 8);
1359 }
1360
1361 static void
voyagerfb_brightness_down(device_t dev)1362 voyagerfb_brightness_down(device_t dev)
1363 {
1364 struct voyagerfb_softc *sc = device_private(dev);
1365
1366 voyagerfb_set_backlight(sc, sc->sc_bl_level - 8);
1367 }
1368
1369 static int
voyagerfb_set_curpos(struct voyagerfb_softc * sc,int x,int y)1370 voyagerfb_set_curpos(struct voyagerfb_softc *sc, int x, int y)
1371 {
1372 uint32_t val;
1373 int xx, yy;
1374
1375 sc->sc_cur_x = x;
1376 sc->sc_cur_y = y;
1377
1378 xx = x - sc->sc_hot_x;
1379 yy = y - sc->sc_hot_y;
1380
1381 if (xx < 0) xx = abs(xx) | 0x800;
1382 if (yy < 0) yy = abs(yy) | 0x800;
1383
1384 val = (xx & 0xffff) | (yy << 16);
1385 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, val);
1386
1387 return 0;
1388 }
1389
1390 static int
voyagerfb_gcursor(struct voyagerfb_softc * sc,struct wsdisplay_cursor * cur)1391 voyagerfb_gcursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur)
1392 {
1393 /* do nothing for now */
1394 return 0;
1395 }
1396
1397 static int
voyagerfb_scursor(struct voyagerfb_softc * sc,struct wsdisplay_cursor * cur)1398 voyagerfb_scursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur)
1399 {
1400 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1401
1402 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1403 SM502_PANEL_CRSR_ADDR,
1404 sc->sc_cursor_addr | (cur->enable ? SM502_CRSR_ENABLE : 0));
1405 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr);
1406 }
1407 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1408
1409 sc->sc_hot_x = cur->hot.x;
1410 sc->sc_hot_y = cur->hot.y;
1411 }
1412 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1413
1414 voyagerfb_set_curpos(sc, cur->pos.x, cur->pos.y);
1415 }
1416 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1417 int i, idx;
1418 uint32_t val;
1419
1420 for (i = 0; i < cur->cmap.count; i++) {
1421 val = ((cur->cmap.red[i] & 0xf8) << 8) |
1422 ((cur->cmap.green[i] & 0xfc) << 3) |
1423 ((cur->cmap.blue[i] & 0xf8) >> 3);
1424 idx = i + cur->cmap.index;
1425 bus_space_write_2(sc->sc_memt, sc->sc_regh,
1426 SM502_PANEL_CRSR_COL12 + (idx << 1),
1427 val);
1428 /*
1429 * if userland doesn't try to set the 3rd colour we
1430 * assume it expects an X11-style 2 colour cursor
1431 * X should be our main user anyway
1432 */
1433 if ((idx == 1) &&
1434 ((cur->cmap.count + cur->cmap.index) < 3)) {
1435 bus_space_write_2(sc->sc_memt, sc->sc_regh,
1436 SM502_PANEL_CRSR_COL3,
1437 val);
1438 }
1439 DPRINTF("%s: %d %04x\n", __func__, i + cur->cmap.index,
1440 val);
1441 }
1442 }
1443 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1444
1445 int i, j, cnt = 0;
1446 uint32_t latch = 0, omask;
1447 uint8_t imask;
1448 DPRINTF("%s: %d %d\n", __func__, cur->size.x, cur->size.y);
1449 for (i = 0; i < 256; i++) {
1450 omask = 0x00000001;
1451 imask = 0x01;
1452 cur->image[cnt] &= cur->mask[cnt];
1453 for (j = 0; j < 8; j++) {
1454 if (cur->mask[cnt] & imask)
1455 latch |= omask;
1456 omask <<= 1;
1457 if (cur->image[cnt] & imask)
1458 latch |= omask;
1459 omask <<= 1;
1460 imask <<= 1;
1461 }
1462 cnt++;
1463 imask = 0x01;
1464 cur->image[cnt] &= cur->mask[cnt];
1465 for (j = 0; j < 8; j++) {
1466 if (cur->mask[cnt] & imask)
1467 latch |= omask;
1468 omask <<= 1;
1469 if (cur->image[cnt] & imask)
1470 latch |= omask;
1471 omask <<= 1;
1472 imask <<= 1;
1473 }
1474 cnt++;
1475 sc->sc_cursor[i] = latch;
1476 latch = 0;
1477 }
1478 }
1479 return 0;
1480 }
1481