xref: /netbsd-src/sys/dev/pci/r128fb.c (revision 9ddb6ab554e70fb9bbd90c3d96b812bc57755a14)
1 /*	$NetBSD: r128fb.c,v 1.31 2012/03/08 05:42:44 macallan Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 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 ATI Rage 128 graphics controllers
30  * tested on macppc only so far
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: r128fb.c,v 1.31 2012/03/08 05:42:44 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/pci/r128fbreg.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 #include <dev/wscons/wsdisplay_glyphcachevar.h>
59 
60 #include <dev/i2c/i2cvar.h>
61 
62 #include "opt_r128fb.h"
63 #include "opt_vcons.h"
64 
65 #ifdef R128FB_DEBUG
66 #define DPRINTF printf
67 #else
68 #define DPRINTF while(0) printf
69 #endif
70 
71 struct r128fb_softc {
72 	device_t sc_dev;
73 
74 	pci_chipset_tag_t sc_pc;
75 	pcitag_t sc_pcitag;
76 
77 	bus_space_tag_t sc_memt;
78 	bus_space_tag_t sc_iot;
79 
80 	bus_space_handle_t sc_regh;
81 	bus_addr_t sc_fb, sc_reg;
82 	bus_size_t sc_fbsize, sc_regsize;
83 
84 	int sc_width, sc_height, sc_depth, sc_stride;
85 	int sc_locked, sc_have_backlight, sc_bl_level, sc_bl_on;
86 	struct vcons_screen sc_console_screen;
87 	struct wsscreen_descr sc_defaultscreen_descr;
88 	const struct wsscreen_descr *sc_screens[1];
89 	struct wsscreen_list sc_screenlist;
90 	struct vcons_data vd;
91 	int sc_mode;
92 	u_char sc_cmap_red[256];
93 	u_char sc_cmap_green[256];
94 	u_char sc_cmap_blue[256];
95 	/* engine stuff */
96 	uint32_t sc_master_cntl;
97 	glyphcache sc_gc;
98 };
99 
100 static int	r128fb_match(device_t, cfdata_t, void *);
101 static void	r128fb_attach(device_t, device_t, void *);
102 
103 CFATTACH_DECL_NEW(r128fb, sizeof(struct r128fb_softc),
104     r128fb_match, r128fb_attach, NULL, NULL);
105 
106 extern const u_char rasops_cmap[768];
107 
108 static int	r128fb_ioctl(void *, void *, u_long, void *, int,
109 			     struct lwp *);
110 static paddr_t	r128fb_mmap(void *, void *, off_t, int);
111 static void	r128fb_init_screen(void *, struct vcons_screen *, int, long *);
112 
113 static int	r128fb_putcmap(struct r128fb_softc *, struct wsdisplay_cmap *);
114 static int 	r128fb_getcmap(struct r128fb_softc *, struct wsdisplay_cmap *);
115 static void	r128fb_restore_palette(struct r128fb_softc *);
116 static int 	r128fb_putpalreg(struct r128fb_softc *, uint8_t, uint8_t,
117 			    uint8_t, uint8_t);
118 
119 static void	r128fb_init(struct r128fb_softc *);
120 static void	r128fb_flush_engine(struct r128fb_softc *);
121 static void	r128fb_rectfill(struct r128fb_softc *, int, int, int, int,
122 			    uint32_t);
123 static void	r128fb_bitblt(void *, int, int, int, int, int,
124 			    int, int);
125 
126 static void	r128fb_cursor(void *, int, int, int);
127 static void	r128fb_putchar(void *, int, int, u_int, long);
128 static void	r128fb_putchar_aa(void *, int, int, u_int, long);
129 static void	r128fb_copycols(void *, int, int, int, int);
130 static void	r128fb_erasecols(void *, int, int, int, long);
131 static void	r128fb_copyrows(void *, int, int, int);
132 static void	r128fb_eraserows(void *, int, int, long);
133 
134 static void	r128fb_brightness_up(device_t);
135 static void	r128fb_brightness_down(device_t);
136 /* set backlight level */
137 static void	r128fb_set_backlight(struct r128fb_softc *, int);
138 /* turn backlight on and off without messing with the level */
139 static void	r128fb_switch_backlight(struct r128fb_softc *, int);
140 
141 struct wsdisplay_accessops r128fb_accessops = {
142 	r128fb_ioctl,
143 	r128fb_mmap,
144 	NULL,	/* alloc_screen */
145 	NULL,	/* free_screen */
146 	NULL,	/* show_screen */
147 	NULL, 	/* load_font */
148 	NULL,	/* pollc */
149 	NULL	/* scroll */
150 };
151 
152 static inline void
153 r128fb_wait(struct r128fb_softc *sc, int slots)
154 {
155 	uint32_t reg;
156 
157 	do {
158 		reg = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
159 		    R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK);
160 	} while (reg <= slots);
161 }
162 
163 static void
164 r128fb_flush_engine(struct r128fb_softc *sc)
165 {
166 	uint32_t reg;
167 
168 	reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_PC_NGUI_CTLSTAT);
169 	reg |= R128_PC_FLUSH_ALL;
170 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_PC_NGUI_CTLSTAT, reg);
171 	do {
172 		reg = bus_space_read_4(sc->sc_memt, sc->sc_regh,
173 		    R128_PC_NGUI_CTLSTAT);
174 	} while (reg & R128_PC_BUSY);
175 }
176 
177 static int
178 r128fb_match(device_t parent, cfdata_t match, void *aux)
179 {
180 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
181 
182 	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
183 		return 0;
184 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_ATI)
185 		return 0;
186 
187 	/* only cards tested on so far - likely need a list */
188 	if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGE1AGP4XT) ||
189 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGE3AGP4XT) ||
190 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGEGLPCI) ||
191 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGE_MOB_M3_AGP))
192 		return 100;
193 	return (0);
194 }
195 
196 static void
197 r128fb_attach(device_t parent, device_t self, void *aux)
198 {
199 	struct r128fb_softc	*sc = device_private(self);
200 	struct pci_attach_args	*pa = aux;
201 	struct rasops_info	*ri;
202 	bus_space_tag_t		tag;
203 	struct wsemuldisplaydev_attach_args aa;
204 	prop_dictionary_t	dict;
205 	unsigned long		defattr;
206 	bool			is_console;
207 	int			i, j;
208 	uint32_t		reg, flags;
209 	uint8_t			tmp;
210 
211 	sc->sc_pc = pa->pa_pc;
212 	sc->sc_pcitag = pa->pa_tag;
213 	sc->sc_memt = pa->pa_memt;
214 	sc->sc_iot = pa->pa_iot;
215 	sc->sc_dev = self;
216 
217 	pci_aprint_devinfo(pa, NULL);
218 
219 	/* fill in parameters from properties */
220 	dict = device_properties(self);
221 	if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
222 		aprint_error("%s: no width property\n", device_xname(self));
223 		return;
224 	}
225 	if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
226 		aprint_error("%s: no height property\n", device_xname(self));
227 		return;
228 	}
229 	if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
230 		aprint_error("%s: no depth property\n", device_xname(self));
231 		return;
232 	}
233 	if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) {
234 		aprint_error("%s: no linebytes property\n",
235 		    device_xname(self));
236 		return;
237 	}
238 
239 	prop_dictionary_get_bool(dict, "is_console", &is_console);
240 
241 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x10, PCI_MAPREG_TYPE_MEM,
242 	    &sc->sc_fb, &sc->sc_fbsize, &flags)) {
243 		aprint_error("%s: failed to map the frame buffer.\n",
244 		    device_xname(sc->sc_dev));
245 	}
246 
247 	if (pci_mapreg_map(pa, 0x18, PCI_MAPREG_TYPE_MEM, 0,
248 	    &tag, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) {
249 		aprint_error("%s: failed to map registers.\n",
250 		    device_xname(sc->sc_dev));
251 	}
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 	    &r128fb_accessops);
271 	sc->vd.init_screen = r128fb_init_screen;
272 
273 	/* init engine here */
274 	r128fb_init(sc);
275 
276 	ri = &sc->sc_console_screen.scr_ri;
277 
278 	j = 0;
279 	if (sc->sc_depth == 8) {
280 		/* generate an r3g3b2 colour map */
281 		for (i = 0; i < 256; i++) {
282 			tmp = i & 0xe0;
283 			/*
284 			 * replicate bits so 0xe0 maps to a red value of 0xff
285 			 * in order to make white look actually white
286 			 */
287 			tmp |= (tmp >> 3) | (tmp >> 6);
288 			sc->sc_cmap_red[i] = tmp;
289 
290 			tmp = (i & 0x1c) << 3;
291 			tmp |= (tmp >> 3) | (tmp >> 6);
292 			sc->sc_cmap_green[i] = tmp;
293 
294 			tmp = (i & 0x03) << 6;
295 			tmp |= tmp >> 2;
296 			tmp |= tmp >> 4;
297 			sc->sc_cmap_blue[i] = tmp;
298 
299 			r128fb_putpalreg(sc, i, sc->sc_cmap_red[i],
300 				       sc->sc_cmap_green[i],
301 				       sc->sc_cmap_blue[i]);
302 		}
303 	} else {
304 		/* steal rasops' ANSI cmap */
305 		for (i = 0; i < 256; i++) {
306 			sc->sc_cmap_red[i] = i;
307 			sc->sc_cmap_green[i] = i;
308 			sc->sc_cmap_blue[i] = i;
309 			r128fb_putpalreg(sc, i, i, i, i);
310 			j += 3;
311 		}
312 	}
313 
314 	sc->sc_gc.gc_bitblt = r128fb_bitblt;
315 	sc->sc_gc.gc_blitcookie = sc;
316 	sc->sc_gc.gc_rop = R128_ROP3_S;
317 	if (is_console) {
318 		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
319 		    &defattr);
320 		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
321 
322 		r128fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
323 		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
324 		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
325 		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
326 		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
327 		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
328 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
329 				sc->sc_width,
330 				(0x800000 / sc->sc_stride) - sc->sc_height - 5,
331 				ri->ri_font->fontwidth,
332 				ri->ri_font->fontheight,
333 				defattr);
334 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
335 		    defattr);
336 		vcons_replay_msgbuf(&sc->sc_console_screen);
337 	} else {
338 		/*
339 		 * since we're not the console we can postpone the rest
340 		 * until someone actually allocates a screen for us
341 		 */
342 		(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
343 		glyphcache_init(&sc->sc_gc, sc->sc_height,
344 				sc->sc_width,
345 				(0x800000 / sc->sc_stride) - sc->sc_height,
346 				ri->ri_font->fontwidth,
347 				ri->ri_font->fontheight,
348 				defattr);
349 	}
350 
351 	/* no suspend/resume support yet */
352 	pmf_device_register(sc->sc_dev, NULL, NULL);
353 
354 	reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL);
355 	DPRINTF("R128_LVDS_GEN_CNTL: %08x\n", reg);
356 	if (reg & R128_LVDS_ON) {
357 		sc->sc_have_backlight = 1;
358 		sc->sc_bl_on = 1;
359 		sc->sc_bl_level = 255 -
360 		    ((reg & R128_LEVEL_MASK) >> R128_LEVEL_SHIFT);
361 		pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP,
362 		    r128fb_brightness_up, TRUE);
363 		pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN,
364 		    r128fb_brightness_down, TRUE);
365 		aprint_verbose("%s: LVDS output is active, enabling backlight"
366 			       " control\n", device_xname(self));
367 	} else
368 		sc->sc_have_backlight = 0;
369 
370 	aa.console = is_console;
371 	aa.scrdata = &sc->sc_screenlist;
372 	aa.accessops = &r128fb_accessops;
373 	aa.accesscookie = &sc->vd;
374 
375 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
376 }
377 
378 static int
379 r128fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
380 	struct lwp *l)
381 {
382 	struct vcons_data *vd = v;
383 	struct r128fb_softc *sc = vd->cookie;
384 	struct wsdisplay_fbinfo *wdf;
385 	struct vcons_screen *ms = vd->active;
386 	struct wsdisplay_param  *param;
387 
388 	switch (cmd) {
389 	case WSDISPLAYIO_GTYPE:
390 		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
391 		return 0;
392 
393 	/* PCI config read/write passthrough. */
394 	case PCI_IOC_CFGREAD:
395 	case PCI_IOC_CFGWRITE:
396 		return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
397 		    cmd, data, flag, l);
398 
399 	case WSDISPLAYIO_GET_BUSID:
400 		return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, sc->sc_pcitag, data);
401 
402 	case WSDISPLAYIO_GINFO:
403 		if (ms == NULL)
404 			return ENODEV;
405 		wdf = (void *)data;
406 		wdf->height = ms->scr_ri.ri_height;
407 		wdf->width = ms->scr_ri.ri_width;
408 		wdf->depth = ms->scr_ri.ri_depth;
409 		wdf->cmsize = 256;
410 		return 0;
411 
412 	case WSDISPLAYIO_GETCMAP:
413 		return r128fb_getcmap(sc,
414 		    (struct wsdisplay_cmap *)data);
415 
416 	case WSDISPLAYIO_PUTCMAP:
417 		return r128fb_putcmap(sc,
418 		    (struct wsdisplay_cmap *)data);
419 
420 	case WSDISPLAYIO_LINEBYTES:
421 		*(u_int *)data = sc->sc_stride;
422 		return 0;
423 
424 	case WSDISPLAYIO_SMODE: {
425 		int new_mode = *(int*)data;
426 		if (new_mode != sc->sc_mode) {
427 			sc->sc_mode = new_mode;
428 			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
429 				r128fb_init(sc);
430 				r128fb_restore_palette(sc);
431 				glyphcache_wipe(&sc->sc_gc);
432 				r128fb_rectfill(sc, 0, 0, sc->sc_width,
433 				    sc->sc_height, ms->scr_ri.ri_devcmap[
434 				    (ms->scr_defattr >> 16) & 0xff]);
435 				vcons_redraw_screen(ms);
436 			}
437 		}
438 		}
439 		return 0;
440 
441 	case WSDISPLAYIO_GETPARAM:
442 		param = (struct wsdisplay_param *)data;
443 		if (sc->sc_have_backlight == 0)
444 			return EPASSTHROUGH;
445 		switch (param->param) {
446 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
447 			param->min = 0;
448 			param->max = 255;
449 			param->curval = sc->sc_bl_level;
450 			return 0;
451 		case WSDISPLAYIO_PARAM_BACKLIGHT:
452 			param->min = 0;
453 			param->max = 1;
454 			param->curval = sc->sc_bl_on;
455 			return 0;
456 		}
457 		return EPASSTHROUGH;
458 
459 	case WSDISPLAYIO_SETPARAM:
460 		param = (struct wsdisplay_param *)data;
461 		if (sc->sc_have_backlight == 0)
462 			return EPASSTHROUGH;
463 		switch (param->param) {
464 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
465 			r128fb_set_backlight(sc, param->curval);
466 			return 0;
467 		case WSDISPLAYIO_PARAM_BACKLIGHT:
468 			r128fb_switch_backlight(sc,  param->curval);
469 			return 0;
470 		}
471 		return EPASSTHROUGH;
472 	case WSDISPLAYIO_GET_EDID: {
473 		struct wsdisplayio_edid_info *d = data;
474 		return wsdisplayio_get_edid(sc->sc_dev, d);
475 	}
476 	}
477 	return EPASSTHROUGH;
478 }
479 
480 static paddr_t
481 r128fb_mmap(void *v, void *vs, off_t offset, int prot)
482 {
483 	struct vcons_data *vd = v;
484 	struct r128fb_softc *sc = vd->cookie;
485 	paddr_t pa;
486 
487 	/* 'regular' framebuffer mmap()ing */
488 	if (offset < sc->sc_fbsize) {
489 		pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot,
490 		    BUS_SPACE_MAP_LINEAR);
491 		return pa;
492 	}
493 
494 	/*
495 	 * restrict all other mappings to processes with superuser privileges
496 	 * or the kernel itself
497 	 */
498 	if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER,
499 	    NULL) != 0) {
500 		aprint_normal("%s: mmap() rejected.\n",
501 		    device_xname(sc->sc_dev));
502 		return -1;
503 	}
504 
505 	if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
506 		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
507 		    BUS_SPACE_MAP_LINEAR);
508 		return pa;
509 	}
510 
511 	if ((offset >= sc->sc_reg) &&
512 	    (offset < (sc->sc_reg + sc->sc_regsize))) {
513 		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
514 		    BUS_SPACE_MAP_LINEAR);
515 		return pa;
516 	}
517 
518 #ifdef PCI_MAGIC_IO_RANGE
519 	/* allow mapping of IO space */
520 	if ((offset >= PCI_MAGIC_IO_RANGE) &&
521 	    (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
522 		pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
523 		    0, prot, BUS_SPACE_MAP_LINEAR);
524 		return pa;
525 	}
526 #endif
527 
528 #ifdef OFB_ALLOW_OTHERS
529 	if (offset >= 0x80000000) {
530 		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
531 		    BUS_SPACE_MAP_LINEAR);
532 		return pa;
533 	}
534 #endif
535 	return -1;
536 }
537 
538 static void
539 r128fb_init_screen(void *cookie, struct vcons_screen *scr,
540     int existing, long *defattr)
541 {
542 	struct r128fb_softc *sc = cookie;
543 	struct rasops_info *ri = &scr->scr_ri;
544 
545 	ri->ri_depth = sc->sc_depth;
546 	ri->ri_width = sc->sc_width;
547 	ri->ri_height = sc->sc_height;
548 	ri->ri_stride = sc->sc_stride;
549 	ri->ri_flg = RI_CENTER;
550 	if (sc->sc_depth == 8)
551 		ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
552 
553 	rasops_init(ri, 0, 0);
554 	ri->ri_caps = WSSCREEN_WSCOLORS;
555 #ifdef VCONS_DRAW_INTR
556 	scr->scr_flags |= VCONS_DONT_READ;
557 #endif
558 
559 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
560 		    sc->sc_width / ri->ri_font->fontwidth);
561 
562 	ri->ri_hw = scr;
563 	ri->ri_ops.copyrows = r128fb_copyrows;
564 	ri->ri_ops.copycols = r128fb_copycols;
565 	ri->ri_ops.eraserows = r128fb_eraserows;
566 	ri->ri_ops.erasecols = r128fb_erasecols;
567 	ri->ri_ops.cursor = r128fb_cursor;
568 	if (FONT_IS_ALPHA(ri->ri_font)) {
569 		ri->ri_ops.putchar = r128fb_putchar_aa;
570 		ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG,
571 		     0, &sc->sc_gc.gc_attr);
572 	} else
573 		ri->ri_ops.putchar = r128fb_putchar;
574 }
575 
576 static int
577 r128fb_putcmap(struct r128fb_softc *sc, struct wsdisplay_cmap *cm)
578 {
579 	u_char *r, *g, *b;
580 	u_int index = cm->index;
581 	u_int count = cm->count;
582 	int i, error;
583 	u_char rbuf[256], gbuf[256], bbuf[256];
584 
585 #ifdef R128FB_DEBUG
586 	aprint_debug("putcmap: %d %d\n",index, count);
587 #endif
588 	if (cm->index >= 256 || cm->count > 256 ||
589 	    (cm->index + cm->count) > 256)
590 		return EINVAL;
591 	error = copyin(cm->red, &rbuf[index], count);
592 	if (error)
593 		return error;
594 	error = copyin(cm->green, &gbuf[index], count);
595 	if (error)
596 		return error;
597 	error = copyin(cm->blue, &bbuf[index], count);
598 	if (error)
599 		return error;
600 
601 	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
602 	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
603 	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
604 
605 	r = &sc->sc_cmap_red[index];
606 	g = &sc->sc_cmap_green[index];
607 	b = &sc->sc_cmap_blue[index];
608 
609 	for (i = 0; i < count; i++) {
610 		r128fb_putpalreg(sc, index, *r, *g, *b);
611 		index++;
612 		r++, g++, b++;
613 	}
614 	return 0;
615 }
616 
617 static int
618 r128fb_getcmap(struct r128fb_softc *sc, struct wsdisplay_cmap *cm)
619 {
620 	u_int index = cm->index;
621 	u_int count = cm->count;
622 	int error;
623 
624 	if (index >= 255 || count > 256 || index + count > 256)
625 		return EINVAL;
626 
627 	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
628 	if (error)
629 		return error;
630 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
631 	if (error)
632 		return error;
633 	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
634 	if (error)
635 		return error;
636 
637 	return 0;
638 }
639 
640 static void
641 r128fb_restore_palette(struct r128fb_softc *sc)
642 {
643 	int i;
644 
645 	for (i = 0; i < (1 << sc->sc_depth); i++) {
646 		r128fb_putpalreg(sc, i, sc->sc_cmap_red[i],
647 		    sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
648 	}
649 }
650 
651 static int
652 r128fb_putpalreg(struct r128fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
653     uint8_t b)
654 {
655 	uint32_t reg;
656 
657 	/* whack the DAC */
658 	reg = (r << 16) | (g << 8) | b;
659 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_PALETTE_INDEX, idx);
660 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_PALETTE_DATA, reg);
661 	return 0;
662 }
663 
664 static void
665 r128fb_init(struct r128fb_softc *sc)
666 {
667 	uint32_t datatype, d, reg;
668 
669 	r128fb_flush_engine(sc);
670 
671 	r128fb_wait(sc, 9);
672 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_CRTC_OFFSET, 0);
673 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DEFAULT_OFFSET, 0);
674 	/* pitch is in units of 8 pixels */
675 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DEFAULT_PITCH,
676 	    sc->sc_width >> 3);
677 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_AUX_SC_CNTL, 0);
678 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
679 	    R128_DEFAULT_SC_BOTTOM_RIGHT,
680 	    R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
681 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SC_TOP_LEFT, 0);
682 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SC_BOTTOM_RIGHT,
683 	    R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
684 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
685 	    R128_DEFAULT_SC_BOTTOM_RIGHT,
686 	    R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
687 
688 #if 0
689 #if BYTE_ORDER == BIG_ENDIAN
690 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_DATATYPE,
691 	    R128_HOST_BIG_ENDIAN_EN);
692 #else
693 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_DATATYPE, 0);
694 #endif
695 #endif
696 	r128fb_wait(sc, 7);
697 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_PITCH,
698 	    sc->sc_width >> 3);
699 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_PITCH,
700 	    sc->sc_width >> 3);
701 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_OFFSET, 0);
702 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_OFFSET, 0);
703 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_WRITE_MASK,
704 	    0xffffffff);
705 
706 	switch (sc->sc_depth) {
707 		case 8:
708 			datatype = R128_GMC_DST_8BPP_CI;
709 			d = R128_CRTC_COLOR_8BIT;
710 			break;
711 		case 15:
712 			datatype = R128_GMC_DST_15BPP;
713 			d = R128_CRTC_COLOR_15BIT;
714 			break;
715 		case 16:
716 			datatype = R128_GMC_DST_16BPP;
717 			d = R128_CRTC_COLOR_16BIT;
718 			break;
719 		case 24:
720 			datatype = R128_GMC_DST_24BPP;
721 			d = R128_CRTC_COLOR_24BIT;
722 			break;
723 		case 32:
724 			datatype = R128_GMC_DST_32BPP;
725 			d = R128_CRTC_COLOR_32BIT;
726 			break;
727 		default:
728 			aprint_error("%s: unsupported depth %d\n",
729 			    device_xname(sc->sc_dev), sc->sc_depth);
730 			return;
731 	}
732 	sc->sc_master_cntl = R128_GMC_CLR_CMP_CNTL_DIS |
733 	    R128_GMC_AUX_CLIP_DIS | datatype;
734 	reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_CRTC_GEN_CNTL);
735 	DPRINTF("depth: %d\n", reg & R128_CRTC_PIX_WIDTH);
736 	reg &= ~R128_CRTC_PIX_WIDTH;
737 	reg |= d;
738 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_CRTC_GEN_CNTL, reg);
739 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_CRTC_PITCH, sc->sc_width >> 3);
740 	r128fb_flush_engine(sc);
741 }
742 
743 static void
744 r128fb_rectfill(struct r128fb_softc *sc, int x, int y, int wi, int he,
745      uint32_t colour)
746 {
747 
748 	r128fb_wait(sc, 5);
749 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_GUI_MASTER_CNTL,
750 	    R128_GMC_BRUSH_SOLID_COLOR |
751 	    R128_GMC_SRC_DATATYPE_COLOR |
752 	    R128_ROP3_P |
753 	    sc->sc_master_cntl);
754 
755 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_BRUSH_FRGD_CLR,
756 	    colour);
757 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_CNTL,
758 	    R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM);
759 	/* now feed it coordinates */
760 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y,
761 	    (x << 16) | y);
762 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_WIDTH_HEIGHT,
763 	    (wi << 16) | he);
764 }
765 
766 static void
767 r128fb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
768     int wi, int he, int rop)
769 {
770 	struct r128fb_softc *sc = cookie;
771 	uint32_t dp_cntl = 0;
772 
773 	r128fb_wait(sc, 5);
774 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_GUI_MASTER_CNTL,
775 	    R128_GMC_BRUSH_SOLID_COLOR |
776 	    R128_GMC_SRC_DATATYPE_COLOR |
777 	    rop |
778 	    R128_DP_SRC_SOURCE_MEMORY |
779 	    sc->sc_master_cntl);
780 
781 	if (yd <= ys) {
782 		dp_cntl = R128_DST_Y_TOP_TO_BOTTOM;
783 	} else {
784 		ys += he - 1;
785 		yd += he - 1;
786 	}
787 	if (xd <= xs) {
788 		dp_cntl |= R128_DST_X_LEFT_TO_RIGHT;
789 	} else {
790 		xs += wi - 1;
791 		xd += wi - 1;
792 	}
793 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_CNTL, dp_cntl);
794 
795 	/* now feed it coordinates */
796 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_X_Y,
797 	    (xs << 16) | ys);
798 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y,
799 	    (xd << 16) | yd);
800 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_WIDTH_HEIGHT,
801 	    (wi << 16) | he);
802 }
803 
804 static void
805 r128fb_cursor(void *cookie, int on, int row, int col)
806 {
807 	struct rasops_info *ri = cookie;
808 	struct vcons_screen *scr = ri->ri_hw;
809 	struct r128fb_softc *sc = scr->scr_cookie;
810 	int x, y, wi, he;
811 
812 	wi = ri->ri_font->fontwidth;
813 	he = ri->ri_font->fontheight;
814 
815 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
816 		x = ri->ri_ccol * wi + ri->ri_xorigin;
817 		y = ri->ri_crow * he + ri->ri_yorigin;
818 		if (ri->ri_flg & RI_CURSOR) {
819 			r128fb_bitblt(sc, x, y, x, y, wi, he, R128_ROP3_Dn);
820 			ri->ri_flg &= ~RI_CURSOR;
821 		}
822 		ri->ri_crow = row;
823 		ri->ri_ccol = col;
824 		if (on) {
825 			x = ri->ri_ccol * wi + ri->ri_xorigin;
826 			y = ri->ri_crow * he + ri->ri_yorigin;
827 			r128fb_bitblt(sc, x, y, x, y, wi, he, R128_ROP3_Dn);
828 			ri->ri_flg |= RI_CURSOR;
829 		}
830 	} else {
831 		scr->scr_ri.ri_crow = row;
832 		scr->scr_ri.ri_ccol = col;
833 		scr->scr_ri.ri_flg &= ~RI_CURSOR;
834 	}
835 
836 }
837 
838 static void
839 r128fb_putchar(void *cookie, int row, int col, u_int c, long attr)
840 {
841 	struct rasops_info *ri = cookie;
842 	struct wsdisplay_font *font = PICK_FONT(ri, c);
843 	struct vcons_screen *scr = ri->ri_hw;
844 	struct r128fb_softc *sc = scr->scr_cookie;
845 	void *data;
846 	uint32_t fg, bg;
847 	int i, x, y, wi, he, offset;
848 
849 	if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
850 		return;
851 
852 	if (!CHAR_IN_FONT(c, font))
853 		return;
854 
855 	wi = font->fontwidth;
856 	he = font->fontheight;
857 
858 	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
859 	fg = ri->ri_devcmap[(attr >> 24) & 0xf];
860 	x = ri->ri_xorigin + col * wi;
861 	y = ri->ri_yorigin + row * he;
862 
863 	if (c == 0x20) {
864 		r128fb_rectfill(sc, x, y, wi, he, bg);
865 		return;
866 	}
867 
868 	data = WSFONT_GLYPH(c, font);
869 
870 	r128fb_wait(sc, 8);
871 
872 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
873 	    R128_DP_GUI_MASTER_CNTL,
874 	    R128_GMC_BRUSH_SOLID_COLOR |
875 	    R128_GMC_SRC_DATATYPE_MONO_FG_BG |
876 	    R128_ROP3_S |
877 	    R128_DP_SRC_SOURCE_HOST_DATA |
878 	    R128_GMC_DST_CLIPPING |
879 	    sc->sc_master_cntl);
880 
881 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
882 	    R128_DP_CNTL,
883 	    R128_DST_Y_TOP_TO_BOTTOM |
884 	    R128_DST_X_LEFT_TO_RIGHT);
885 
886 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
887 	    R128_DP_SRC_FRGD_CLR, fg);
888 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
889 	    R128_DP_SRC_BKGD_CLR, bg);
890 
891 	/*
892 	 * The Rage 128 doesn't have anything to skip pixels
893 	 * when colour expanding but all coordinates
894 	 * are signed so we just clip the leading bytes and
895 	 * trailing bits away
896 	 */
897 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
898 	    R128_SC_RIGHT, x + wi - 1);
899 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
900 	    R128_SC_LEFT, x);
901 
902 	/* needed? */
903 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_X_Y, 0);
904 
905 	offset = 32 - (font->stride << 3);
906 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y,
907 	    ((x - offset) << 16) | y);
908 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
909 	    R128_DST_WIDTH_HEIGHT, (32 << 16) | he);
910 
911 	r128fb_wait(sc, he);
912 	switch (font->stride) {
913 		case 1: {
914 			uint8_t *data8 = data;
915 			uint32_t reg;
916 			for (i = 0; i < he; i++) {
917 				reg = *data8;
918 				bus_space_write_stream_4(sc->sc_memt,
919 				    sc->sc_regh, R128_HOST_DATA0, reg);
920 				data8++;
921 			}
922 			break;
923 		}
924 		case 2: {
925 			uint16_t *data16 = data;
926 			uint32_t reg;
927 			for (i = 0; i < he; i++) {
928 				reg = *data16;
929 				bus_space_write_stream_4(sc->sc_memt,
930 				    sc->sc_regh, R128_HOST_DATA0, reg);
931 				data16++;
932 			}
933 			break;
934 		}
935 	}
936 }
937 
938 static void
939 r128fb_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
940 {
941 	struct rasops_info *ri = cookie;
942 	struct wsdisplay_font *font = PICK_FONT(ri, c);
943 	struct vcons_screen *scr = ri->ri_hw;
944 	struct r128fb_softc *sc = scr->scr_cookie;
945 	uint32_t bg, latch = 0, bg8, fg8, pixel;
946 	int i, x, y, wi, he, r, g, b, aval;
947 	int r1, g1, b1, r0, g0, b0, fgo, bgo;
948 	uint8_t *data8;
949 	int rv, cnt = 0;
950 
951 	if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
952 		return;
953 
954 	if (!CHAR_IN_FONT(c, font))
955 		return;
956 
957 	wi = font->fontwidth;
958 	he = font->fontheight;
959 
960 	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
961 	x = ri->ri_xorigin + col * wi;
962 	y = ri->ri_yorigin + row * he;
963 	if (c == 0x20) {
964 		r128fb_rectfill(sc, x, y, wi, he, bg);
965 		return;
966 	}
967 
968 	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
969 	if (rv == GC_OK)
970 		return;
971 
972 	data8 = WSFONT_GLYPH(c, font);
973 
974 	r128fb_wait(sc, 5);
975 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
976 	    R128_DP_GUI_MASTER_CNTL,
977 	    R128_GMC_BRUSH_SOLID_COLOR |
978 	    R128_GMC_SRC_DATATYPE_COLOR |
979 	    R128_ROP3_S |
980 	    R128_DP_SRC_SOURCE_HOST_DATA |
981 	    sc->sc_master_cntl);
982 
983 	bus_space_write_4(sc->sc_memt, sc->sc_regh,
984 	    R128_DP_CNTL,
985 	    R128_DST_Y_TOP_TO_BOTTOM |
986 	    R128_DST_X_LEFT_TO_RIGHT);
987 
988 	/* needed? */
989 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_X_Y, 0);
990 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y,
991 	    (x << 16) | y);
992 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_WIDTH_HEIGHT,
993 	    (wi << 16) | he);
994 
995 	/*
996 	 * we need the RGB colours here, so get offsets into rasops_cmap
997 	 */
998 	fgo = ((attr >> 24) & 0xf) * 3;
999 	bgo = ((attr >> 16) & 0xf) * 3;
1000 
1001 	r0 = rasops_cmap[bgo];
1002 	r1 = rasops_cmap[fgo];
1003 	g0 = rasops_cmap[bgo + 1];
1004 	g1 = rasops_cmap[fgo + 1];
1005 	b0 = rasops_cmap[bgo + 2];
1006 	b1 = rasops_cmap[fgo + 2];
1007 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6))
1008 	bg8 = R3G3B2(r0, g0, b0);
1009 	fg8 = R3G3B2(r1, g1, b1);
1010 
1011 	r128fb_wait(sc, 16);
1012 
1013 	for (i = 0; i < ri->ri_fontscale; i++) {
1014 		aval = *data8;
1015 		if (aval == 0) {
1016 			pixel = bg8;
1017 		} else if (aval == 255) {
1018 			pixel = fg8;
1019 		} else {
1020 			r = aval * r1 + (255 - aval) * r0;
1021 			g = aval * g1 + (255 - aval) * g0;
1022 			b = aval * b1 + (255 - aval) * b0;
1023 			pixel = ((r & 0xe000) >> 8) |
1024 				((g & 0xe000) >> 11) |
1025 				((b & 0xc000) >> 14);
1026 		}
1027 		latch = (latch << 8) | pixel;
1028 		/* write in 32bit chunks */
1029 		if ((i & 3) == 3) {
1030 			bus_space_write_stream_4(sc->sc_memt, sc->sc_regh,
1031 			    R128_HOST_DATA0, latch);
1032 			/*
1033 			 * not strictly necessary, old data should be shifted
1034 			 * out
1035 			 */
1036 			latch = 0;
1037 			cnt++;
1038 			if (cnt > 15) {
1039 				r128fb_wait(sc, 16);
1040 				cnt = 0;
1041 			}
1042 		}
1043 		data8++;
1044 	}
1045 	/* if we have pixels left in latch write them out */
1046 	if ((i & 3) != 0) {
1047 		latch = latch << ((4 - (i & 3)) << 3);
1048 		bus_space_write_stream_4(sc->sc_memt, sc->sc_regh,
1049 				    R128_HOST_DATA0, latch);
1050 	}
1051 	if (rv == GC_ADD) {
1052 		glyphcache_add(&sc->sc_gc, c, x, y);
1053 	}
1054 }
1055 
1056 static void
1057 r128fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1058 {
1059 	struct rasops_info *ri = cookie;
1060 	struct vcons_screen *scr = ri->ri_hw;
1061 	struct r128fb_softc *sc = scr->scr_cookie;
1062 	int32_t xs, xd, y, width, height;
1063 
1064 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1065 		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1066 		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1067 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1068 		width = ri->ri_font->fontwidth * ncols;
1069 		height = ri->ri_font->fontheight;
1070 		r128fb_bitblt(sc, xs, y, xd, y, width, height, R128_ROP3_S);
1071 	}
1072 }
1073 
1074 static void
1075 r128fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1076 {
1077 	struct rasops_info *ri = cookie;
1078 	struct vcons_screen *scr = ri->ri_hw;
1079 	struct r128fb_softc *sc = scr->scr_cookie;
1080 	int32_t x, y, width, height, fg, bg, ul;
1081 
1082 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1083 		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1084 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1085 		width = ri->ri_font->fontwidth * ncols;
1086 		height = ri->ri_font->fontheight;
1087 		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1088 
1089 		r128fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1090 	}
1091 }
1092 
1093 static void
1094 r128fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1095 {
1096 	struct rasops_info *ri = cookie;
1097 	struct vcons_screen *scr = ri->ri_hw;
1098 	struct r128fb_softc *sc = scr->scr_cookie;
1099 	int32_t x, ys, yd, width, height;
1100 
1101 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1102 		x = ri->ri_xorigin;
1103 		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1104 		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1105 		width = ri->ri_emuwidth;
1106 		height = ri->ri_font->fontheight * nrows;
1107 		r128fb_bitblt(sc, x, ys, x, yd, width, height, R128_ROP3_S);
1108 	}
1109 }
1110 
1111 static void
1112 r128fb_eraserows(void *cookie, int row, int nrows, long fillattr)
1113 {
1114 	struct rasops_info *ri = cookie;
1115 	struct vcons_screen *scr = ri->ri_hw;
1116 	struct r128fb_softc *sc = scr->scr_cookie;
1117 	int32_t x, y, width, height, fg, bg, ul;
1118 
1119 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1120 		x = ri->ri_xorigin;
1121 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1122 		width = ri->ri_emuwidth;
1123 		height = ri->ri_font->fontheight * nrows;
1124 		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1125 
1126 		r128fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1127 	}
1128 }
1129 
1130 static void
1131 r128fb_set_backlight(struct r128fb_softc *sc, int level)
1132 {
1133 	uint32_t reg;
1134 
1135 	/*
1136 	 * should we do nothing when backlight is off, should we just store the
1137 	 * level and use it when turning back on or should we just flip sc_bl_on
1138 	 * and turn the backlight on?
1139 	 * For now turn it on so a crashed screensaver can't get the user stuck
1140 	 * with a dark screen as long as hotkeys work
1141 	 */
1142 	if (level > 255) level = 255;
1143 	if (level < 0) level = 0;
1144 	if (level == sc->sc_bl_level)
1145 		return;
1146 	sc->sc_bl_level = level;
1147 	if (sc->sc_bl_on == 0)
1148 		sc->sc_bl_on = 1;
1149 	level = 255 - level;
1150 	reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL);
1151 	reg &= ~R128_LEVEL_MASK;
1152 	reg |= (level << R128_LEVEL_SHIFT);
1153 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL, reg);
1154 	DPRINTF("backlight level: %d reg %08x\n", level, reg);
1155 }
1156 
1157 static void
1158 r128fb_switch_backlight(struct r128fb_softc *sc, int on)
1159 {
1160 	uint32_t reg;
1161 	int level;
1162 
1163 	if (on == sc->sc_bl_on)
1164 		return;
1165 	sc->sc_bl_on = on;
1166 	reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL);
1167 	reg &= ~R128_LEVEL_MASK;
1168 	level = on ? 255 - sc->sc_bl_level : 255;
1169 	reg |= level << R128_LEVEL_SHIFT;
1170 	bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL, reg);
1171 	DPRINTF("backlight state: %d reg %08x\n", on, reg);
1172 }
1173 
1174 
1175 static void
1176 r128fb_brightness_up(device_t dev)
1177 {
1178 	struct r128fb_softc *sc = device_private(dev);
1179 
1180 	r128fb_set_backlight(sc, sc->sc_bl_level + 8);
1181 }
1182 
1183 static void
1184 r128fb_brightness_down(device_t dev)
1185 {
1186 	struct r128fb_softc *sc = device_private(dev);
1187 
1188 	r128fb_set_backlight(sc, sc->sc_bl_level - 8);
1189 }
1190