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