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