voyagerfb.c revision 1.21 1 /* $NetBSD: voyagerfb.c,v 1.21 2012/05/23 18:39:30 macallan 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.21 2012/05/23 18:39:30 macallan 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 /* there are probably 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 weirdnesses 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 passthrough. */
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 superuser privileges
508 * or the kernel itself
509 */
510 if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
511 NULL, NULL, NULL, NULL) != 0) {
512 aprint_normal("%s: mmap() rejected.\n",
513 device_xname(sc->sc_dev));
514 return -1;
515 }
516
517 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
518 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
519 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
520 return pa;
521 }
522
523 if ((offset >= sc->sc_reg) &&
524 (offset < (sc->sc_reg + sc->sc_regsize))) {
525 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 0);
526 return pa;
527 }
528
529 return -1;
530 }
531
532 static void
533 voyagerfb_init_screen(void *cookie, struct vcons_screen *scr,
534 int existing, long *defattr)
535 {
536 struct voyagerfb_softc *sc = cookie;
537 struct rasops_info *ri = &scr->scr_ri;
538
539 ri->ri_depth = sc->sc_depth;
540 ri->ri_width = sc->sc_width;
541 ri->ri_height = sc->sc_height;
542 ri->ri_stride = sc->sc_stride;
543 ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
544
545 ri->ri_bits = (char *)sc->sc_fbaddr;
546
547 if (existing) {
548 ri->ri_flg |= RI_CLEAR;
549 }
550
551 if (sc->sc_depth == 32) {
552 #ifdef VOYAGERFB_ANTIALIAS
553 ri->ri_flg |= RI_ENABLE_ALPHA;
554 #endif
555 /* we always run in RGB */
556 ri->ri_rnum = 8;
557 ri->ri_gnum = 8;
558 ri->ri_bnum = 8;
559 ri->ri_rpos = 16;
560 ri->ri_gpos = 8;
561 ri->ri_bpos = 0;
562 }
563
564 rasops_init(ri, 0, 0);
565 ri->ri_caps = WSSCREEN_WSCOLORS;
566
567 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
568 sc->sc_width / ri->ri_font->fontwidth);
569
570 ri->ri_hw = scr;
571 ri->ri_ops.copyrows = voyagerfb_copyrows;
572 ri->ri_ops.copycols = voyagerfb_copycols;
573 ri->ri_ops.eraserows = voyagerfb_eraserows;
574 ri->ri_ops.erasecols = voyagerfb_erasecols;
575 ri->ri_ops.cursor = voyagerfb_cursor;
576 if (FONT_IS_ALPHA(ri->ri_font)) {
577 ri->ri_ops.putchar = voyagerfb_putchar_aa32;
578 } else
579 ri->ri_ops.putchar = voyagerfb_putchar_mono;
580 }
581
582 static int
583 voyagerfb_putcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
584 {
585 u_char *r, *g, *b;
586 u_int index = cm->index;
587 u_int count = cm->count;
588 int i, error;
589 u_char rbuf[256], gbuf[256], bbuf[256];
590
591 #ifdef VOYAGERFB_DEBUG
592 aprint_debug("putcmap: %d %d\n",index, count);
593 #endif
594 if (cm->index >= 256 || cm->count > 256 ||
595 (cm->index + cm->count) > 256)
596 return EINVAL;
597 error = copyin(cm->red, &rbuf[index], count);
598 if (error)
599 return error;
600 error = copyin(cm->green, &gbuf[index], count);
601 if (error)
602 return error;
603 error = copyin(cm->blue, &bbuf[index], count);
604 if (error)
605 return error;
606
607 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
608 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
609 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
610
611 r = &sc->sc_cmap_red[index];
612 g = &sc->sc_cmap_green[index];
613 b = &sc->sc_cmap_blue[index];
614
615 for (i = 0; i < count; i++) {
616 voyagerfb_putpalreg(sc, index, *r, *g, *b);
617 index++;
618 r++, g++, b++;
619 }
620 return 0;
621 }
622
623 static int
624 voyagerfb_getcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
625 {
626 u_int index = cm->index;
627 u_int count = cm->count;
628 int error;
629
630 if (index >= 255 || count > 256 || index + count > 256)
631 return EINVAL;
632
633 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
634 if (error)
635 return error;
636 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
637 if (error)
638 return error;
639 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
640 if (error)
641 return error;
642
643 return 0;
644 }
645
646 static void
647 voyagerfb_restore_palette(struct voyagerfb_softc *sc)
648 {
649 int i;
650
651 for (i = 0; i < (1 << sc->sc_depth); i++) {
652 voyagerfb_putpalreg(sc, i, sc->sc_cmap_red[i],
653 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
654 }
655 }
656
657 static int
658 voyagerfb_putpalreg(struct voyagerfb_softc *sc, int idx, uint8_t r,
659 uint8_t g, uint8_t b)
660 {
661 uint32_t reg;
662
663 reg = (r << 16) | (g << 8) | b;
664 /* XXX we should probably write the CRT palette too */
665 bus_space_write_4(sc->sc_memt, sc->sc_regh,
666 SM502_PALETTE_PANEL + (idx << 2), reg);
667 return 0;
668 }
669
670 static void
671 voyagerfb_init(struct voyagerfb_softc *sc)
672 {
673 int reg;
674
675 voyagerfb_wait(sc);
676 /* disable colour compare */
677 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_COLOR_COMP_MASK, 0);
678 /* allow writes to all planes */
679 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PLANEMASK,
680 0xffffffff);
681 /* disable clipping */
682 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CLIP_TOP_LEFT, 0);
683 /* source and destination in local memory, no offset */
684 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC_BASE, 0);
685 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST_BASE, 0);
686 /* pitch is screen stride */
687 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PITCH,
688 sc->sc_width | (sc->sc_width << 16));
689 /* window is screen width */
690 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_WINDOW_WIDTH,
691 sc->sc_width | (sc->sc_width << 16));
692 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL);
693 reg &= ~SM502_PDC_DEPTH_MASK;
694
695 switch (sc->sc_depth) {
696 case 8:
697 bus_space_write_4(sc->sc_memt, sc->sc_regh,
698 SM502_STRETCH, SM502_STRETCH_8BIT);
699 sc->sc_stride = sc->sc_width;
700 reg |= SM502_PDC_8BIT;
701 break;
702 case 16:
703 bus_space_write_4(sc->sc_memt, sc->sc_regh,
704 SM502_STRETCH, SM502_STRETCH_16BIT);
705 sc->sc_stride = sc->sc_width << 1;
706 reg |= SM502_PDC_16BIT;
707 break;
708 case 24:
709 case 32:
710 bus_space_write_4(sc->sc_memt, sc->sc_regh,
711 SM502_STRETCH, SM502_STRETCH_32BIT);
712 sc->sc_stride = sc->sc_width << 2;
713 reg |= SM502_PDC_32BIT;
714 break;
715 }
716 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_FB_OFFSET,
717 (sc->sc_stride << 16) | sc->sc_stride);
718 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL,
719 reg);
720
721 /* put the cursor at the end of video memory */
722 sc->sc_cursor_addr = 16 * 1024 * 1024 - 16 * 64; /* XXX */
723 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr);
724 sc->sc_cursor = (uint32_t *)((uint8_t *)bus_space_vaddr(sc->sc_memt, sc->sc_fbh)
725 + sc->sc_cursor_addr);
726 #ifdef VOYAGERFB_DEBUG
727 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, 0x00100010);
728 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL12, 0x0000ffff);
729 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL3, 0x0000f800);
730 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR,
731 SM502_CRSR_ENABLE | sc->sc_cursor_addr);
732 sc->sc_cursor[0] = 0x00000000;
733 sc->sc_cursor[1] = 0x00000000;
734 sc->sc_cursor[2] = 0xffffffff;
735 sc->sc_cursor[3] = 0xffffffff;
736 sc->sc_cursor[4] = 0xaaaaaaaa;
737 sc->sc_cursor[5] = 0xaaaaaaaa;
738 sc->sc_cursor[6] = 0xffffffff;
739 sc->sc_cursor[7] = 0x00000000;
740 #else
741 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR,
742 sc->sc_cursor_addr);
743 #endif
744 }
745
746 static void
747 voyagerfb_rectfill(struct voyagerfb_softc *sc, int x, int y, int wi, int he,
748 uint32_t colour)
749 {
750
751 voyagerfb_ready(sc);
752 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL,
753 ROP_COPY |
754 SM502_CTRL_USE_ROP2 |
755 SM502_CTRL_CMD_RECTFILL |
756 SM502_CTRL_QUICKSTART_E);
757 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND,
758 colour);
759 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
760 (x << 16) | y);
761 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
762 (wi << 16) | he);
763 }
764
765 static void
766 voyagerfb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
767 int wi, int he, int rop)
768 {
769 struct voyagerfb_softc *sc = cookie;
770 uint32_t cmd;
771
772 cmd = (rop & 0xf) | SM502_CTRL_USE_ROP2 | SM502_CTRL_CMD_BITBLT |
773 SM502_CTRL_QUICKSTART_E;
774
775 voyagerfb_ready(sc);
776
777 if (xd <= xs) {
778 /* left to right */
779 } else {
780 /*
781 * According to the manual this flag reverses only the blitter's
782 * X direction. At least on my Gdium it also reverses the Y
783 * direction
784 */
785 cmd |= SM502_CTRL_R_TO_L;
786 xs += wi - 1;
787 xd += wi - 1;
788 ys += he - 1;
789 yd += he - 1;
790 }
791
792 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
793 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC,
794 (xs << 16) | ys);
795 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
796 (xd << 16) | yd);
797 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
798 (wi << 16) | he);
799 }
800
801 static void
802 voyagerfb_cursor(void *cookie, int on, int row, int col)
803 {
804 struct rasops_info *ri = cookie;
805 struct vcons_screen *scr = ri->ri_hw;
806 struct voyagerfb_softc *sc = scr->scr_cookie;
807 int x, y, wi, he;
808
809 wi = ri->ri_font->fontwidth;
810 he = ri->ri_font->fontheight;
811
812 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
813 x = ri->ri_ccol * wi + ri->ri_xorigin;
814 y = ri->ri_crow * he + ri->ri_yorigin;
815 if (ri->ri_flg & RI_CURSOR) {
816 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
817 ri->ri_flg &= ~RI_CURSOR;
818 }
819 ri->ri_crow = row;
820 ri->ri_ccol = col;
821 if (on) {
822 x = ri->ri_ccol * wi + ri->ri_xorigin;
823 y = ri->ri_crow * he + ri->ri_yorigin;
824 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
825 ri->ri_flg |= RI_CURSOR;
826 }
827 } else {
828 scr->scr_ri.ri_crow = row;
829 scr->scr_ri.ri_ccol = col;
830 scr->scr_ri.ri_flg &= ~RI_CURSOR;
831 }
832
833 }
834
835 static inline void
836 voyagerfb_feed8(struct voyagerfb_softc *sc, uint8_t *data, int len)
837 {
838 uint32_t *port = (uint32_t *)sc->sc_dataport;
839 int i;
840
841 for (i = 0; i < ((len + 3) & 0xfffc); i++) {
842 *port = *data;
843 data++;
844 }
845 }
846
847 static inline void
848 voyagerfb_feed16(struct voyagerfb_softc *sc, uint16_t *data, int len)
849 {
850 uint32_t *port = (uint32_t *)sc->sc_dataport;
851 int i;
852
853 len = len << 1;
854 for (i = 0; i < ((len + 1) & 0xfffe); i++) {
855 *port = *data;
856 data++;
857 }
858 }
859
860 static void
861 voyagerfb_putchar_mono(void *cookie, int row, int col, u_int c, long attr)
862 {
863 struct rasops_info *ri = cookie;
864 struct wsdisplay_font *font = PICK_FONT(ri, c);
865 struct vcons_screen *scr = ri->ri_hw;
866 struct voyagerfb_softc *sc = scr->scr_cookie;
867 uint32_t cmd;
868 int fg, bg;
869 uint8_t *data;
870 int x, y, wi, he;
871
872 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
873 return;
874
875 if (!CHAR_IN_FONT(c, font))
876 return;
877
878 wi = font->fontwidth;
879 he = font->fontheight;
880
881 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
882 fg = ri->ri_devcmap[(attr >> 24) & 0x0f];
883 x = ri->ri_xorigin + col * wi;
884 y = ri->ri_yorigin + row * he;
885 if (c == 0x20) {
886 voyagerfb_rectfill(sc, x, y, wi, he, bg);
887 return;
888 }
889
890 data = WSFONT_GLYPH(c, font);
891
892 cmd = ROP_COPY |
893 SM502_CTRL_USE_ROP2 |
894 SM502_CTRL_CMD_HOSTWRT |
895 SM502_CTRL_HOSTBLT_MONO |
896 SM502_CTRL_QUICKSTART_E |
897 SM502_CTRL_MONO_PACK_32BIT;
898 voyagerfb_ready(sc);
899 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
900 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND, fg);
901 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_BACKGROUND, bg);
902 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0);
903 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y);
904 bus_space_write_4(sc->sc_memt, sc->sc_regh,
905 SM502_DIMENSION, (wi << 16) | he);
906 /* now feed the data, padded to 32bit */
907 switch (ri->ri_font->stride) {
908 case 1:
909 voyagerfb_feed8(sc, data, ri->ri_fontscale);
910 break;
911 case 2:
912 voyagerfb_feed16(sc, (uint16_t *)data,
913 ri->ri_fontscale);
914 break;
915 }
916 }
917
918 static void
919 voyagerfb_putchar_aa32(void *cookie, int row, int col, u_int c, long attr)
920 {
921 struct rasops_info *ri = cookie;
922 struct wsdisplay_font *font = PICK_FONT(ri, c);
923 struct vcons_screen *scr = ri->ri_hw;
924 struct voyagerfb_softc *sc = scr->scr_cookie;
925 uint32_t cmd;
926 int fg, bg;
927 uint8_t *data;
928 int x, y, wi, he;
929 int i, j, r, g, b, aval, pad;
930 int rf, gf, bf, rb, gb, bb;
931 uint32_t pixel;
932 int rv;
933
934 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
935 return;
936
937 if (!CHAR_IN_FONT(c, font))
938 return;
939
940 wi = font->fontwidth;
941 he = font->fontheight;
942
943 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
944 fg = ri->ri_devcmap[(attr >> 24) & 0x0f];
945 x = ri->ri_xorigin + col * wi;
946 y = ri->ri_yorigin + row * he;
947 if (c == 0x20) {
948 voyagerfb_rectfill(sc, x, y, wi, he, bg);
949 return;
950 }
951
952 data = WSFONT_GLYPH(c, font);
953 /*
954 * we can't accelerate the actual alpha blending but
955 * we can at least use a host blit to go through the
956 * pipeline instead of having to sync the engine
957 */
958
959 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
960 if (rv == GC_OK)
961 return;
962
963 cmd = ROP_COPY |
964 SM502_CTRL_USE_ROP2 |
965 SM502_CTRL_CMD_HOSTWRT |
966 SM502_CTRL_QUICKSTART_E;
967 voyagerfb_ready(sc);
968 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
969 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0);
970 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y);
971 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION, (wi << 16) | he);
972 rf = (fg >> 16) & 0xff;
973 rb = (bg >> 16) & 0xff;
974 gf = (fg >> 8) & 0xff;
975 gb = (bg >> 8) & 0xff;
976 bf = fg & 0xff;
977 bb = bg & 0xff;
978 pad = wi & 1;
979 for (i = 0; i < he; i++) {
980 for (j = 0; j < wi; j++) {
981 aval = *data;
982 data++;
983 if (aval == 0) {
984 pixel = bg;
985 } else if (aval == 255) {
986 pixel = fg;
987 } else {
988 r = aval * rf + (255 - aval) * rb;
989 g = aval * gf + (255 - aval) * gb;
990 b = aval * bf + (255 - aval) * bb;
991 pixel = (r & 0xff00) << 8 |
992 (g & 0xff00) |
993 (b & 0xff00) >> 8;
994 }
995 bus_space_write_4(sc->sc_memt, sc->sc_regh,
996 SM502_DATAPORT, pixel);
997 }
998 if (pad)
999 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1000 SM502_DATAPORT, 0);
1001 }
1002 if (rv == GC_ADD) {
1003 glyphcache_add(&sc->sc_gc, c, x, y);
1004 }
1005 }
1006
1007 static void
1008 voyagerfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1009 {
1010 struct rasops_info *ri = cookie;
1011 struct vcons_screen *scr = ri->ri_hw;
1012 struct voyagerfb_softc *sc = scr->scr_cookie;
1013 int32_t xs, xd, y, width, height;
1014
1015 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1016 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1017 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1018 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1019 width = ri->ri_font->fontwidth * ncols;
1020 height = ri->ri_font->fontheight;
1021 voyagerfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY);
1022 }
1023 }
1024
1025 static void
1026 voyagerfb_erasecols(void *cookie, int row, int startcol, int ncols,
1027 long fillattr)
1028 {
1029 struct rasops_info *ri = cookie;
1030 struct vcons_screen *scr = ri->ri_hw;
1031 struct voyagerfb_softc *sc = scr->scr_cookie;
1032 int32_t x, y, width, height, fg, bg, ul;
1033
1034 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1035 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1036 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1037 width = ri->ri_font->fontwidth * ncols;
1038 height = ri->ri_font->fontheight;
1039 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1040
1041 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1042 }
1043 }
1044
1045 static void
1046 voyagerfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1047 {
1048 struct rasops_info *ri = cookie;
1049 struct vcons_screen *scr = ri->ri_hw;
1050 struct voyagerfb_softc *sc = scr->scr_cookie;
1051 int32_t x, ys, yd, width, height;
1052 int i;
1053
1054 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1055 x = ri->ri_xorigin;
1056 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1057 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1058 width = ri->ri_emuwidth;
1059 height = ri->ri_font->fontheight * nrows;
1060 if ((nrows > 1) && (dstrow > srcrow)) {
1061 /*
1062 * the blitter can't do bottom-up copies so we have
1063 * to copy line by line here
1064 * should probably use a command sequence
1065 */
1066 ys += (height - ri->ri_font->fontheight);
1067 yd += (height - ri->ri_font->fontheight);
1068 for (i = 0; i < nrows; i++) {
1069 voyagerfb_bitblt(sc, x, ys, x, yd, width,
1070 ri->ri_font->fontheight, ROP_COPY);
1071 ys -= ri->ri_font->fontheight;
1072 yd -= ri->ri_font->fontheight;
1073 }
1074 } else
1075 voyagerfb_bitblt(sc, x, ys, x, yd, width, height,
1076 ROP_COPY);
1077 }
1078 }
1079
1080 static void
1081 voyagerfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1082 {
1083 struct rasops_info *ri = cookie;
1084 struct vcons_screen *scr = ri->ri_hw;
1085 struct voyagerfb_softc *sc = scr->scr_cookie;
1086 int32_t x, y, width, height, fg, bg, ul;
1087
1088 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1089 x = ri->ri_xorigin;
1090 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1091 width = ri->ri_emuwidth;
1092 height = ri->ri_font->fontheight * nrows;
1093 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1094
1095 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1096 }
1097 }
1098
1099 /* backlight control */
1100 static void
1101 voyagerfb_setup_backlight(struct voyagerfb_softc *sc)
1102 {
1103 /* switch the pin to gpio mode if it isn't already */
1104 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1105 /* turn it on */
1106 voyager_write_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1107 sc->sc_bl_on = 1;
1108 sc->sc_bl_level = 255;
1109 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP,
1110 voyagerfb_brightness_up, TRUE);
1111 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN,
1112 voyagerfb_brightness_down, TRUE);
1113 }
1114
1115 static void
1116 voyagerfb_set_backlight(struct voyagerfb_softc *sc, int level)
1117 {
1118
1119 /*
1120 * should we do nothing when backlight is off, should we just store the
1121 * level and use it when turning back on or should we just flip sc_bl_on
1122 * and turn the backlight on?
1123 * For now turn it on so a crashed screensaver can't get the user stuck
1124 * with a dark screen as long as hotkeys work
1125 */
1126 if (level > 255) level = 255;
1127 if (level < 0) level = 0;
1128 if (level == sc->sc_bl_level)
1129 return;
1130 sc->sc_bl_level = level;
1131 if (sc->sc_bl_on == 0)
1132 sc->sc_bl_on = 1;
1133 /* and here we would actually muck with the hardware */
1134 if ((level == 0) || (level == 255)) {
1135 /* in these cases bypass the PWM and use the gpio */
1136 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1137 if (level == 0) {
1138 voyager_write_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1139 } else {
1140 voyager_write_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1141 }
1142 } else {
1143 uint32_t pwm;
1144
1145 pwm = voyager_set_pwm(20000, level * 1000 / 256);
1146 pwm |= SM502_PWM_ENABLE;
1147 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM0, pwm);
1148
1149 /* let the PWM take over */
1150 voyager_control_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1151 }
1152 }
1153
1154 static void
1155 voyagerfb_switch_backlight(struct voyagerfb_softc *sc, int on)
1156 {
1157
1158 if (on == sc->sc_bl_on)
1159 return;
1160 sc->sc_bl_on = on;
1161 if (on) {
1162 int level = sc->sc_bl_level;
1163
1164 sc->sc_bl_level = -1;
1165 voyagerfb_set_backlight(sc, level);
1166 } else {
1167 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1168 voyager_write_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1169 }
1170 }
1171
1172
1173 static void
1174 voyagerfb_brightness_up(device_t dev)
1175 {
1176 struct voyagerfb_softc *sc = device_private(dev);
1177
1178 voyagerfb_set_backlight(sc, sc->sc_bl_level + 8);
1179 }
1180
1181 static void
1182 voyagerfb_brightness_down(device_t dev)
1183 {
1184 struct voyagerfb_softc *sc = device_private(dev);
1185
1186 voyagerfb_set_backlight(sc, sc->sc_bl_level - 8);
1187 }
1188
1189 static int
1190 voyagerfb_set_curpos(struct voyagerfb_softc *sc, int x, int y)
1191 {
1192 uint32_t val;
1193 int xx, yy;
1194
1195 sc->sc_cur_x = x;
1196 sc->sc_cur_y = y;
1197
1198 xx = x - sc->sc_hot_x;
1199 yy = y - sc->sc_hot_y;
1200
1201 if (xx < 0) xx = abs(xx) | 0x800;
1202 if (yy < 0) yy = abs(yy) | 0x800;
1203
1204 val = (xx & 0xffff) | (yy << 16);
1205 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, val);
1206
1207 return 0;
1208 }
1209
1210 static int
1211 voyagerfb_gcursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur)
1212 {
1213 /* do nothing for now */
1214 return 0;
1215 }
1216
1217 static int
1218 voyagerfb_scursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur)
1219 {
1220 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1221
1222 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1223 SM502_PANEL_CRSR_ADDR,
1224 sc->sc_cursor_addr | (cur->enable ? SM502_CRSR_ENABLE : 0));
1225 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr);
1226 }
1227 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1228
1229 sc->sc_hot_x = cur->hot.x;
1230 sc->sc_hot_y = cur->hot.y;
1231 }
1232 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1233
1234 voyagerfb_set_curpos(sc, cur->pos.x, cur->pos.y);
1235 }
1236 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1237 int i, idx;
1238 uint32_t val;
1239
1240 for (i = 0; i < cur->cmap.count; i++) {
1241 val = ((cur->cmap.red[i] & 0xf8) << 8) |
1242 ((cur->cmap.green[i] & 0xfc) << 3) |
1243 ((cur->cmap.blue[i] & 0xf8) >> 3);
1244 idx = i + cur->cmap.index;
1245 bus_space_write_2(sc->sc_memt, sc->sc_regh,
1246 SM502_PANEL_CRSR_COL12 + (idx << 1),
1247 val);
1248 /*
1249 * if userland doesn't try to set the 3rd colour we
1250 * assume it expects an X11-style 2 colour cursor
1251 * X should be our main user anyway
1252 */
1253 if ((idx == 1) &&
1254 ((cur->cmap.count + cur->cmap.index) < 3)) {
1255 bus_space_write_2(sc->sc_memt, sc->sc_regh,
1256 SM502_PANEL_CRSR_COL3,
1257 val);
1258 }
1259 DPRINTF("%s: %d %04x\n", __func__, i + cur->cmap.index, val);
1260 }
1261 }
1262 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1263
1264 int i, j, cnt = 0;
1265 uint32_t latch = 0, omask;
1266 uint8_t imask;
1267 DPRINTF("%s: %d %d\n", __func__, cur->size.x, cur->size.y);
1268 for (i = 0; i < 256; i++) {
1269 omask = 0x00000001;
1270 imask = 0x01;
1271 cur->image[cnt] &= cur->mask[cnt];
1272 for (j = 0; j < 8; j++) {
1273 if (cur->mask[cnt] & imask)
1274 latch |= omask;
1275 omask <<= 1;
1276 if (cur->image[cnt] & imask)
1277 latch |= omask;
1278 omask <<= 1;
1279 imask <<= 1;
1280 }
1281 cnt++;
1282 imask = 0x01;
1283 cur->image[cnt] &= cur->mask[cnt];
1284 for (j = 0; j < 8; j++) {
1285 if (cur->mask[cnt] & imask)
1286 latch |= omask;
1287 omask <<= 1;
1288 if (cur->image[cnt] & imask)
1289 latch |= omask;
1290 omask <<= 1;
1291 imask <<= 1;
1292 }
1293 cnt++;
1294 sc->sc_cursor[i] = latch;
1295 latch = 0;
1296 }
1297 }
1298 return 0;
1299 }
1300