voyagerfb.c revision 1.18 1 /* $NetBSD: voyagerfb.c,v 1.18 2012/03/13 18:40:34 elad 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.18 2012/03/13 18:40:34 elad 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(void *, int, int, u_int, long);
146 static void voyagerfb_copycols(void *, int, int, int, int);
147 static void voyagerfb_erasecols(void *, int, int, int, long);
148 static void voyagerfb_copyrows(void *, int, int, int);
149 static void voyagerfb_eraserows(void *, int, int, long);
150
151 static int voyagerfb_set_curpos(struct voyagerfb_softc *, int, int);
152 static int voyagerfb_gcursor(struct voyagerfb_softc *, struct wsdisplay_cursor *);
153 static int voyagerfb_scursor(struct voyagerfb_softc *, struct wsdisplay_cursor *);
154
155 struct wsdisplay_accessops voyagerfb_accessops = {
156 voyagerfb_ioctl,
157 voyagerfb_mmap,
158 NULL, /* alloc_screen */
159 NULL, /* free_screen */
160 NULL, /* show_screen */
161 NULL, /* load_font */
162 NULL, /* pollc */
163 NULL /* scroll */
164 };
165
166 static void voyagerfb_setup_backlight(struct voyagerfb_softc *);
167 static void voyagerfb_brightness_up(device_t);
168 static void voyagerfb_brightness_down(device_t);
169 /* set backlight level */
170 static void voyagerfb_set_backlight(struct voyagerfb_softc *, int);
171 /* turn backlight on and off without messing with the level */
172 static void voyagerfb_switch_backlight(struct voyagerfb_softc *, int);
173
174 /* wait for FIFO empty so we can feed it another command */
175 static inline void
176 voyagerfb_ready(struct voyagerfb_softc *sc)
177 {
178 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh,
179 SM502_SYSTEM_CTRL) & SM502_SYSCTL_FIFO_EMPTY) == 0);
180 }
181
182 /* wait for the drawing engine to be idle */
183 static inline void
184 voyagerfb_wait(struct voyagerfb_softc *sc)
185 {
186 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh,
187 SM502_SYSTEM_CTRL) & SM502_SYSCTL_ENGINE_BUSY) != 0);
188 }
189
190 static int
191 voyagerfb_match(device_t parent, cfdata_t match, void *aux)
192 {
193 struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
194
195 if (strcmp(vaa->vaa_name, "voyagerfb") == 0) return 100;
196 return 0;
197 }
198
199 static void
200 voyagerfb_attach(device_t parent, device_t self, void *aux)
201 {
202 struct voyagerfb_softc *sc = device_private(self);
203 struct voyager_attach_args *vaa = aux;
204 struct rasops_info *ri;
205 struct wsemuldisplaydev_attach_args aa;
206 prop_dictionary_t dict;
207 unsigned long defattr;
208 bool is_console;
209 int i, j;
210
211 sc->sc_pc = vaa->vaa_pc;
212 sc->sc_pcitag = vaa->vaa_pcitag;
213 sc->sc_memt = vaa->vaa_tag;
214 sc->sc_dev = self;
215
216 aprint_normal("\n");
217
218 dict = device_properties(self);
219 prop_dictionary_get_bool(dict, "is_console", &is_console);
220
221 sc->sc_fb = vaa->vaa_mem_pa;
222 sc->sc_fbh = vaa->vaa_memh;
223 sc->sc_fbsize = 16 * 1024 * 1024;
224 sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh);
225
226 sc->sc_reg = vaa->vaa_reg_pa;
227 sc->sc_regh = vaa->vaa_regh;
228 sc->sc_regsize = 2 * 1024 * 1024;
229 sc->sc_dataport = bus_space_vaddr(sc->sc_memt, sc->sc_regh);
230 sc->sc_dataport += SM502_DATAPORT;
231
232 sc->sc_width = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
233 SM502_PANEL_FB_WIDTH) & SM502_FBW_WIN_WIDTH_MASK) >> 16;
234 sc->sc_height = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
235 SM502_PANEL_FB_HEIGHT) & SM502_FBH_WIN_HEIGHT_MASK) >> 16;
236
237 #ifdef VOYAGERFB_ANTIALIAS
238 sc->sc_depth = 32;
239 #else
240 sc->sc_depth = 8;
241 #endif
242
243 /* init engine here */
244 voyagerfb_init(sc);
245
246 printf("%s: %d x %d, %d bit, stride %d\n", device_xname(self),
247 sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride);
248
249 /*
250 * XXX yeah, casting the fb address to uint32_t is formally wrong
251 * but as far as I know there are no SM502 with 64bit BARs
252 */
253 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
254 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
255
256 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
257 "default",
258 0, 0,
259 NULL,
260 8, 16,
261 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
262 NULL
263 };
264 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
265 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
266 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
267 sc->sc_locked = 0;
268
269 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
270 &voyagerfb_accessops);
271 sc->vd.init_screen = voyagerfb_init_screen;
272
273 /* backlight control */
274 sc->sc_gpio_cookie = device_private(parent);
275 voyagerfb_setup_backlight(sc);
276
277 ri = &sc->sc_console_screen.scr_ri;
278
279 sc->sc_gc.gc_bitblt = voyagerfb_bitblt;
280 sc->sc_gc.gc_blitcookie = sc;
281 sc->sc_gc.gc_rop = ROP_COPY;
282 if (is_console) {
283 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
284 &defattr);
285 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
286
287 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
288 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
289 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
290 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
291 } else {
292 /*
293 * since we're not the console we can postpone the rest
294 * until someone actually allocates a screen for us
295 */
296 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
297 }
298 glyphcache_init(&sc->sc_gc, sc->sc_height,
299 sc->sc_width,
300 (sc->sc_fbsize / sc->sc_stride) - sc->sc_height,
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 #ifdef VOYAGERFB_ANTIALIAS
551 ri->ri_flg |= RI_ENABLE_ALPHA;
552 #endif
553
554 rasops_init(ri, 0, 0);
555 ri->ri_caps = WSSCREEN_WSCOLORS;
556
557 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
558 sc->sc_width / ri->ri_font->fontwidth);
559
560 ri->ri_hw = scr;
561 ri->ri_ops.copyrows = voyagerfb_copyrows;
562 ri->ri_ops.copycols = voyagerfb_copycols;
563 ri->ri_ops.eraserows = voyagerfb_eraserows;
564 ri->ri_ops.erasecols = voyagerfb_erasecols;
565 ri->ri_ops.cursor = voyagerfb_cursor;
566 ri->ri_ops.putchar = voyagerfb_putchar;
567 }
568
569 static int
570 voyagerfb_putcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
571 {
572 u_char *r, *g, *b;
573 u_int index = cm->index;
574 u_int count = cm->count;
575 int i, error;
576 u_char rbuf[256], gbuf[256], bbuf[256];
577
578 #ifdef VOYAGERFB_DEBUG
579 aprint_debug("putcmap: %d %d\n",index, count);
580 #endif
581 if (cm->index >= 256 || cm->count > 256 ||
582 (cm->index + cm->count) > 256)
583 return EINVAL;
584 error = copyin(cm->red, &rbuf[index], count);
585 if (error)
586 return error;
587 error = copyin(cm->green, &gbuf[index], count);
588 if (error)
589 return error;
590 error = copyin(cm->blue, &bbuf[index], count);
591 if (error)
592 return error;
593
594 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
595 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
596 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
597
598 r = &sc->sc_cmap_red[index];
599 g = &sc->sc_cmap_green[index];
600 b = &sc->sc_cmap_blue[index];
601
602 for (i = 0; i < count; i++) {
603 voyagerfb_putpalreg(sc, index, *r, *g, *b);
604 index++;
605 r++, g++, b++;
606 }
607 return 0;
608 }
609
610 static int
611 voyagerfb_getcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
612 {
613 u_int index = cm->index;
614 u_int count = cm->count;
615 int error;
616
617 if (index >= 255 || count > 256 || index + count > 256)
618 return EINVAL;
619
620 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
621 if (error)
622 return error;
623 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
624 if (error)
625 return error;
626 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
627 if (error)
628 return error;
629
630 return 0;
631 }
632
633 static void
634 voyagerfb_restore_palette(struct voyagerfb_softc *sc)
635 {
636 int i;
637
638 for (i = 0; i < (1 << sc->sc_depth); i++) {
639 voyagerfb_putpalreg(sc, i, sc->sc_cmap_red[i],
640 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
641 }
642 }
643
644 static int
645 voyagerfb_putpalreg(struct voyagerfb_softc *sc, int idx, uint8_t r,
646 uint8_t g, uint8_t b)
647 {
648 uint32_t reg;
649
650 reg = (r << 16) | (g << 8) | b;
651 /* XXX we should probably write the CRT palette too */
652 bus_space_write_4(sc->sc_memt, sc->sc_regh,
653 SM502_PALETTE_PANEL + (idx << 2), reg);
654 return 0;
655 }
656
657 static void
658 voyagerfb_init(struct voyagerfb_softc *sc)
659 {
660 int reg;
661
662 voyagerfb_wait(sc);
663 /* disable colour compare */
664 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_COLOR_COMP_MASK, 0);
665 /* allow writes to all planes */
666 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PLANEMASK,
667 0xffffffff);
668 /* disable clipping */
669 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CLIP_TOP_LEFT, 0);
670 /* source and destination in local memory, no offset */
671 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC_BASE, 0);
672 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST_BASE, 0);
673 /* pitch is screen stride */
674 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PITCH,
675 sc->sc_width | (sc->sc_width << 16));
676 /* window is screen width */
677 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_WINDOW_WIDTH,
678 sc->sc_width | (sc->sc_width << 16));
679 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL);
680 reg &= ~SM502_PDC_DEPTH_MASK;
681
682 switch (sc->sc_depth) {
683 case 8:
684 bus_space_write_4(sc->sc_memt, sc->sc_regh,
685 SM502_STRETCH, SM502_STRETCH_8BIT);
686 sc->sc_stride = sc->sc_width;
687 reg |= SM502_PDC_8BIT;
688 break;
689 case 16:
690 bus_space_write_4(sc->sc_memt, sc->sc_regh,
691 SM502_STRETCH, SM502_STRETCH_16BIT);
692 sc->sc_stride = sc->sc_width << 1;
693 reg |= SM502_PDC_16BIT;
694 break;
695 case 24:
696 case 32:
697 bus_space_write_4(sc->sc_memt, sc->sc_regh,
698 SM502_STRETCH, SM502_STRETCH_32BIT);
699 sc->sc_stride = sc->sc_width << 2;
700 reg |= SM502_PDC_32BIT;
701 break;
702 }
703 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_FB_OFFSET,
704 (sc->sc_stride << 16) | sc->sc_stride);
705 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL,
706 reg);
707
708 /* put the cursor at the end of video memory */
709 sc->sc_cursor_addr = 16 * 1024 * 1024 - 16 * 64; /* XXX */
710 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr);
711 sc->sc_cursor = (uint32_t *)((uint8_t *)bus_space_vaddr(sc->sc_memt, sc->sc_fbh)
712 + sc->sc_cursor_addr);
713 #ifdef VOYAGERFB_DEBUG
714 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, 0x00100010);
715 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL12, 0x0000ffff);
716 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL3, 0x0000f800);
717 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR,
718 SM502_CRSR_ENABLE | sc->sc_cursor_addr);
719 sc->sc_cursor[0] = 0x00000000;
720 sc->sc_cursor[1] = 0x00000000;
721 sc->sc_cursor[2] = 0xffffffff;
722 sc->sc_cursor[3] = 0xffffffff;
723 sc->sc_cursor[4] = 0xaaaaaaaa;
724 sc->sc_cursor[5] = 0xaaaaaaaa;
725 sc->sc_cursor[6] = 0xffffffff;
726 sc->sc_cursor[7] = 0x00000000;
727 #else
728 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR,
729 sc->sc_cursor_addr);
730 #endif
731 }
732
733 static void
734 voyagerfb_rectfill(struct voyagerfb_softc *sc, int x, int y, int wi, int he,
735 uint32_t colour)
736 {
737
738 voyagerfb_ready(sc);
739 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL,
740 ROP_COPY |
741 SM502_CTRL_USE_ROP2 |
742 SM502_CTRL_CMD_RECTFILL |
743 SM502_CTRL_QUICKSTART_E);
744 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND,
745 colour);
746 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
747 (x << 16) | y);
748 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
749 (wi << 16) | he);
750 }
751
752 static void
753 voyagerfb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
754 int wi, int he, int rop)
755 {
756 struct voyagerfb_softc *sc = cookie;
757 uint32_t cmd;
758
759 cmd = (rop & 0xf) | SM502_CTRL_USE_ROP2 | SM502_CTRL_CMD_BITBLT |
760 SM502_CTRL_QUICKSTART_E;
761
762 voyagerfb_ready(sc);
763
764 if (xd <= xs) {
765 /* left to right */
766 } else {
767 /*
768 * According to the manual this flag reverses only the blitter's
769 * X direction. At least on my Gdium it also reverses the Y
770 * direction
771 */
772 cmd |= SM502_CTRL_R_TO_L;
773 xs += wi - 1;
774 xd += wi - 1;
775 ys += he - 1;
776 yd += he - 1;
777 }
778
779 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
780 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC,
781 (xs << 16) | ys);
782 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
783 (xd << 16) | yd);
784 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
785 (wi << 16) | he);
786 }
787
788 static void
789 voyagerfb_cursor(void *cookie, int on, int row, int col)
790 {
791 struct rasops_info *ri = cookie;
792 struct vcons_screen *scr = ri->ri_hw;
793 struct voyagerfb_softc *sc = scr->scr_cookie;
794 int x, y, wi, he;
795
796 wi = ri->ri_font->fontwidth;
797 he = ri->ri_font->fontheight;
798
799 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
800 x = ri->ri_ccol * wi + ri->ri_xorigin;
801 y = ri->ri_crow * he + ri->ri_yorigin;
802 if (ri->ri_flg & RI_CURSOR) {
803 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
804 ri->ri_flg &= ~RI_CURSOR;
805 }
806 ri->ri_crow = row;
807 ri->ri_ccol = col;
808 if (on) {
809 x = ri->ri_ccol * wi + ri->ri_xorigin;
810 y = ri->ri_crow * he + ri->ri_yorigin;
811 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
812 ri->ri_flg |= RI_CURSOR;
813 }
814 } else {
815 scr->scr_ri.ri_crow = row;
816 scr->scr_ri.ri_ccol = col;
817 scr->scr_ri.ri_flg &= ~RI_CURSOR;
818 }
819
820 }
821
822 static inline void
823 voyagerfb_feed8(struct voyagerfb_softc *sc, uint8_t *data, int len)
824 {
825 uint32_t *port = (uint32_t *)sc->sc_dataport;
826 int i;
827
828 for (i = 0; i < ((len + 3) & 0xfffc); i++) {
829 *port = *data;
830 data++;
831 }
832 }
833
834 static inline void
835 voyagerfb_feed16(struct voyagerfb_softc *sc, uint16_t *data, int len)
836 {
837 uint32_t *port = (uint32_t *)sc->sc_dataport;
838 int i;
839
840 len = len << 1;
841 for (i = 0; i < ((len + 1) & 0xfffe); i++) {
842 *port = *data;
843 data++;
844 }
845 }
846
847
848 static void
849 voyagerfb_putchar(void *cookie, int row, int col, u_int c, long attr)
850 {
851 struct rasops_info *ri = cookie;
852 struct wsdisplay_font *font = PICK_FONT(ri, c);
853 struct vcons_screen *scr = ri->ri_hw;
854 struct voyagerfb_softc *sc = scr->scr_cookie;
855 uint32_t cmd;
856 int fg, bg;
857 uint8_t *data;
858 int x, y, wi, he;
859 int rv;
860
861 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
862 return;
863
864 if (!CHAR_IN_FONT(c, font))
865 return;
866
867 wi = font->fontwidth;
868 he = font->fontheight;
869
870 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
871 fg = ri->ri_devcmap[(attr >> 24) & 0x0f];
872 x = ri->ri_xorigin + col * wi;
873 y = ri->ri_yorigin + row * he;
874 if (c == 0x20) {
875 voyagerfb_rectfill(sc, x, y, wi, he, bg);
876 return;
877 }
878
879 data = WSFONT_GLYPH(c, font);
880 if (!FONT_IS_ALPHA(font)) {
881 /* this is a mono font */
882 cmd = ROP_COPY |
883 SM502_CTRL_USE_ROP2 |
884 SM502_CTRL_CMD_HOSTWRT |
885 SM502_CTRL_HOSTBLT_MONO |
886 SM502_CTRL_QUICKSTART_E |
887 SM502_CTRL_MONO_PACK_32BIT;
888 voyagerfb_ready(sc);
889 bus_space_write_4(sc->sc_memt, sc->sc_regh,
890 SM502_CONTROL, cmd);
891 bus_space_write_4(sc->sc_memt, sc->sc_regh,
892 SM502_FOREGROUND, fg);
893 bus_space_write_4(sc->sc_memt, sc->sc_regh,
894 SM502_BACKGROUND, bg);
895 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0);
896 bus_space_write_4(sc->sc_memt, sc->sc_regh,
897 SM502_DST, (x << 16) | y);
898 bus_space_write_4(sc->sc_memt, sc->sc_regh,
899 SM502_DIMENSION, (wi << 16) | he);
900 /* now feed the data, padded to 32bit */
901 switch (ri->ri_font->stride) {
902 case 1:
903 voyagerfb_feed8(sc, data, ri->ri_fontscale);
904 break;
905 case 2:
906 voyagerfb_feed16(sc, (uint16_t *)data,
907 ri->ri_fontscale);
908 break;
909
910 }
911 } else {
912 /*
913 * alpha font
914 * we can't accelerate the actual alpha blending but
915 * we can at least use a host blit to go through the
916 * pipeline instead of having to sync the engine
917 */
918 int i, j, r, g, b, aval, pad;
919 int rf, gf, bf, rb, gb, bb;
920 uint32_t pixel;
921
922 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
923 if (rv == GC_OK)
924 return;
925
926 cmd = ROP_COPY |
927 SM502_CTRL_USE_ROP2 |
928 SM502_CTRL_CMD_HOSTWRT |
929 SM502_CTRL_QUICKSTART_E;
930 voyagerfb_ready(sc);
931 bus_space_write_4(sc->sc_memt, sc->sc_regh,
932 SM502_CONTROL, cmd);
933 bus_space_write_4(sc->sc_memt, sc->sc_regh,
934 SM502_SRC, 0);
935 bus_space_write_4(sc->sc_memt, sc->sc_regh,
936 SM502_DST, (x << 16) | y);
937 bus_space_write_4(sc->sc_memt, sc->sc_regh,
938 SM502_DIMENSION, (wi << 16) | he);
939 rf = (fg >> 16) & 0xff;
940 rb = (bg >> 16) & 0xff;
941 gf = (fg >> 8) & 0xff;
942 gb = (bg >> 8) & 0xff;
943 bf = fg & 0xff;
944 bb = bg & 0xff;
945 pad = wi & 1;
946 for (i = 0; i < he; i++) {
947 for (j = 0; j < wi; j++) {
948 aval = *data;
949 data++;
950 if (aval == 0) {
951 pixel = bg;
952 } else if (aval == 255) {
953 pixel = fg;
954 } else {
955 r = aval * rf + (255 - aval) * rb;
956 g = aval * gf + (255 - aval) * gb;
957 b = aval * bf + (255 - aval) * bb;
958 pixel = (r & 0xff00) << 8 |
959 (g & 0xff00) |
960 (b & 0xff00) >> 8;
961 }
962 bus_space_write_4(sc->sc_memt, sc->sc_regh,
963 SM502_DATAPORT, pixel);
964 }
965 if (pad)
966 bus_space_write_4(sc->sc_memt, sc->sc_regh,
967 SM502_DATAPORT, 0);
968 }
969 if (rv == GC_ADD) {
970 glyphcache_add(&sc->sc_gc, c, x, y);
971 }
972 }
973 }
974
975 static void
976 voyagerfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
977 {
978 struct rasops_info *ri = cookie;
979 struct vcons_screen *scr = ri->ri_hw;
980 struct voyagerfb_softc *sc = scr->scr_cookie;
981 int32_t xs, xd, y, width, height;
982
983 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
984 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
985 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
986 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
987 width = ri->ri_font->fontwidth * ncols;
988 height = ri->ri_font->fontheight;
989 voyagerfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY);
990 }
991 }
992
993 static void
994 voyagerfb_erasecols(void *cookie, int row, int startcol, int ncols,
995 long fillattr)
996 {
997 struct rasops_info *ri = cookie;
998 struct vcons_screen *scr = ri->ri_hw;
999 struct voyagerfb_softc *sc = scr->scr_cookie;
1000 int32_t x, y, width, height, fg, bg, ul;
1001
1002 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1003 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1004 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1005 width = ri->ri_font->fontwidth * ncols;
1006 height = ri->ri_font->fontheight;
1007 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1008
1009 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1010 }
1011 }
1012
1013 static void
1014 voyagerfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1015 {
1016 struct rasops_info *ri = cookie;
1017 struct vcons_screen *scr = ri->ri_hw;
1018 struct voyagerfb_softc *sc = scr->scr_cookie;
1019 int32_t x, ys, yd, width, height;
1020 int i;
1021
1022 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1023 x = ri->ri_xorigin;
1024 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1025 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1026 width = ri->ri_emuwidth;
1027 height = ri->ri_font->fontheight * nrows;
1028 if ((nrows > 1) && (dstrow > srcrow)) {
1029 /*
1030 * the blitter can't do bottom-up copies so we have
1031 * to copy line by line here
1032 * should probably use a command sequence
1033 */
1034 ys += (height - ri->ri_font->fontheight);
1035 yd += (height - ri->ri_font->fontheight);
1036 for (i = 0; i < nrows; i++) {
1037 voyagerfb_bitblt(sc, x, ys, x, yd, width,
1038 ri->ri_font->fontheight, ROP_COPY);
1039 ys -= ri->ri_font->fontheight;
1040 yd -= ri->ri_font->fontheight;
1041 }
1042 } else
1043 voyagerfb_bitblt(sc, x, ys, x, yd, width, height,
1044 ROP_COPY);
1045 }
1046 }
1047
1048 static void
1049 voyagerfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1050 {
1051 struct rasops_info *ri = cookie;
1052 struct vcons_screen *scr = ri->ri_hw;
1053 struct voyagerfb_softc *sc = scr->scr_cookie;
1054 int32_t x, y, width, height, fg, bg, ul;
1055
1056 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1057 x = ri->ri_xorigin;
1058 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1059 width = ri->ri_emuwidth;
1060 height = ri->ri_font->fontheight * nrows;
1061 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1062
1063 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1064 }
1065 }
1066
1067 /* backlight control */
1068 static void
1069 voyagerfb_setup_backlight(struct voyagerfb_softc *sc)
1070 {
1071 /* switch the pin to gpio mode if it isn't already */
1072 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1073 /* turn it on */
1074 voyager_write_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1075 sc->sc_bl_on = 1;
1076 sc->sc_bl_level = 255;
1077 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP,
1078 voyagerfb_brightness_up, TRUE);
1079 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN,
1080 voyagerfb_brightness_down, TRUE);
1081 }
1082
1083 static void
1084 voyagerfb_set_backlight(struct voyagerfb_softc *sc, int level)
1085 {
1086
1087 /*
1088 * should we do nothing when backlight is off, should we just store the
1089 * level and use it when turning back on or should we just flip sc_bl_on
1090 * and turn the backlight on?
1091 * For now turn it on so a crashed screensaver can't get the user stuck
1092 * with a dark screen as long as hotkeys work
1093 */
1094 if (level > 255) level = 255;
1095 if (level < 0) level = 0;
1096 if (level == sc->sc_bl_level)
1097 return;
1098 sc->sc_bl_level = level;
1099 if (sc->sc_bl_on == 0)
1100 sc->sc_bl_on = 1;
1101 /* and here we would actually muck with the hardware */
1102 if ((level == 0) || (level == 255)) {
1103 /* in these cases bypass the PWM and use the gpio */
1104 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1105 if (level == 0) {
1106 voyager_write_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1107 } else {
1108 voyager_write_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1109 }
1110 } else {
1111 uint32_t pwm;
1112
1113 pwm = voyager_set_pwm(20000, level * 1000 / 256);
1114 pwm |= SM502_PWM_ENABLE;
1115 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM0, pwm);
1116
1117 /* let the PWM take over */
1118 voyager_control_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT);
1119 }
1120 }
1121
1122 static void
1123 voyagerfb_switch_backlight(struct voyagerfb_softc *sc, int on)
1124 {
1125
1126 if (on == sc->sc_bl_on)
1127 return;
1128 sc->sc_bl_on = on;
1129 if (on) {
1130 int level = sc->sc_bl_level;
1131
1132 sc->sc_bl_level = -1;
1133 voyagerfb_set_backlight(sc, level);
1134 } else {
1135 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1136 voyager_write_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0);
1137 }
1138 }
1139
1140
1141 static void
1142 voyagerfb_brightness_up(device_t dev)
1143 {
1144 struct voyagerfb_softc *sc = device_private(dev);
1145
1146 voyagerfb_set_backlight(sc, sc->sc_bl_level + 8);
1147 }
1148
1149 static void
1150 voyagerfb_brightness_down(device_t dev)
1151 {
1152 struct voyagerfb_softc *sc = device_private(dev);
1153
1154 voyagerfb_set_backlight(sc, sc->sc_bl_level - 8);
1155 }
1156
1157 static int
1158 voyagerfb_set_curpos(struct voyagerfb_softc *sc, int x, int y)
1159 {
1160 uint32_t val;
1161 int xx, yy;
1162
1163 sc->sc_cur_x = x;
1164 sc->sc_cur_y = y;
1165
1166 xx = x - sc->sc_hot_x;
1167 yy = y - sc->sc_hot_y;
1168
1169 if (xx < 0) xx = abs(xx) | 0x800;
1170 if (yy < 0) yy = abs(yy) | 0x800;
1171
1172 val = (xx & 0xffff) | (yy << 16);
1173 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, val);
1174
1175 return 0;
1176 }
1177
1178 static int
1179 voyagerfb_gcursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur)
1180 {
1181 /* do nothing for now */
1182 return 0;
1183 }
1184
1185 static int
1186 voyagerfb_scursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur)
1187 {
1188 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1189
1190 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1191 SM502_PANEL_CRSR_ADDR,
1192 sc->sc_cursor_addr | (cur->enable ? SM502_CRSR_ENABLE : 0));
1193 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr);
1194 }
1195 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1196
1197 sc->sc_hot_x = cur->hot.x;
1198 sc->sc_hot_y = cur->hot.y;
1199 }
1200 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1201
1202 voyagerfb_set_curpos(sc, cur->pos.x, cur->pos.y);
1203 }
1204 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1205 int i, idx;
1206 uint32_t val;
1207
1208 for (i = 0; i < cur->cmap.count; i++) {
1209 val = ((cur->cmap.red[i] & 0xf8) << 8) |
1210 ((cur->cmap.green[i] & 0xfc) << 3) |
1211 ((cur->cmap.blue[i] & 0xf8) >> 3);
1212 idx = i + cur->cmap.index;
1213 bus_space_write_2(sc->sc_memt, sc->sc_regh,
1214 SM502_PANEL_CRSR_COL12 + (idx << 1),
1215 val);
1216 /*
1217 * if userland doesn't try to set the 3rd colour we
1218 * assume it expects an X11-style 2 colour cursor
1219 * X should be our main user anyway
1220 */
1221 if ((idx == 1) &&
1222 ((cur->cmap.count + cur->cmap.index) < 3)) {
1223 bus_space_write_2(sc->sc_memt, sc->sc_regh,
1224 SM502_PANEL_CRSR_COL3,
1225 val);
1226 }
1227 DPRINTF("%s: %d %04x\n", __func__, i + cur->cmap.index, val);
1228 }
1229 }
1230 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1231
1232 int i, j, cnt = 0;
1233 uint32_t latch = 0, omask;
1234 uint8_t imask;
1235 DPRINTF("%s: %d %d\n", __func__, cur->size.x, cur->size.y);
1236 for (i = 0; i < 256; i++) {
1237 omask = 0x00000001;
1238 imask = 0x01;
1239 cur->image[cnt] &= cur->mask[cnt];
1240 for (j = 0; j < 8; j++) {
1241 if (cur->mask[cnt] & imask)
1242 latch |= omask;
1243 omask <<= 1;
1244 if (cur->image[cnt] & imask)
1245 latch |= omask;
1246 omask <<= 1;
1247 imask <<= 1;
1248 }
1249 cnt++;
1250 imask = 0x01;
1251 cur->image[cnt] &= cur->mask[cnt];
1252 for (j = 0; j < 8; j++) {
1253 if (cur->mask[cnt] & imask)
1254 latch |= omask;
1255 omask <<= 1;
1256 if (cur->image[cnt] & imask)
1257 latch |= omask;
1258 omask <<= 1;
1259 imask <<= 1;
1260 }
1261 cnt++;
1262 sc->sc_cursor[i] = latch;
1263 latch = 0;
1264 }
1265 }
1266 return 0;
1267 }
1268