xref: /openbsd/sys/arch/sparc64/dev/ifb.c (revision 67d1d392)
1 /*	$OpenBSD: ifb.c,v 1.8 2008/12/28 17:27:11 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2007, 2008 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Least-effort driver for the Sun Expert3D cards (based on the
21  * ``Wildcat'' chips.
22  *
23  * There is no public documentation for these chips available.
24  * Since they are no longer supported by 3DLabs (which got bought by
25  * Creative), and Sun does not want to publish even minimal information
26  * or source code, the best we can do is experiment.
27  *
28  * Quoting Alan Coopersmith in
29  * http://mail.opensolaris.org/pipermail/opensolaris-discuss/2005-December/011885.html
30  * ``Unfortunately, the lawyers have asked we not give details about why
31  *   specific components are not being released.''
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/errno.h>
38 #include <sys/ioctl.h>
39 #include <sys/malloc.h>
40 #include <sys/pciio.h>
41 
42 #include <uvm/uvm_extern.h>
43 
44 #include <machine/autoconf.h>
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47 #include <machine/openfirm.h>
48 
49 #include <dev/pci/pcireg.h>
50 #include <dev/pci/pcivar.h>
51 #include <dev/pci/pcidevs.h>
52 
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wscons/wsdisplayvar.h>
55 
56 #include <dev/rasops/rasops.h>
57 
58 #include <machine/fbvar.h>
59 
60 /*
61  * Parts of the following hardware knowledge come from David S. Miller's
62  * XVR-500 Linux driver (drivers/video/sunxvr500.c).
63  */
64 
65 /*
66  * The Expert3D and Expert3d-Lite cards are built around the Wildcat
67  * 5110, 6210 and 7210 chips.
68  *
69  * The card exposes the following resources:
70  * - a 32MB aperture window in which views to the different frame buffer
71  *   areas can be mapped, in the first BAR.
72  * - a 64KB PROM and registers area, in the second BAR, with the registers
73  *   starting 32KB within this area.
74  * - a 8MB memory mapping, which purpose is unknown, in the third BAR.
75  *
76  * In the state the PROM leaves us in, the 8MB frame buffer windows map
77  * the video memory as interleaved stripes:
78  * - frame buffer #0 will map horizontal pixels 00-1f, 60-9f, e0-11f, etc.
79  * - frame buffer #1 will map horizontal pixels 20-5f, a0-df, 120-15f, etc.
80  * However the non-visible parts of each stripe can still be addressed
81  * (probably for fast screen switching).
82  *
83  * Unfortunately, since we do not know how to reconfigure the stripes
84  * to provide at least a linear frame buffer, we have to write to both
85  * windows and have them provide the complete image.
86  *
87  * Moreover, high pixel values in the overlay planes (such as 0xff or 0xfe)
88  * seem to enable other planes with random contents, so we'll limit ourselves
89  * to 7bpp opration.
90  */
91 
92 /*
93  * The Expert3D has an extra BAR that is not present on the -Lite
94  * version.  This register contains bits that tell us how many BARs to
95  * skip before we get to the BARs that interest us.
96  */
97 #define IFB_PCI_CFG			0x5c
98 #define IFB_PCI_CFG_BAR_OFFSET(x)	((x & 0x000000e0) >> 3)
99 
100 #define	IFB_REG_OFFSET			0x8000
101 
102 /*
103  * 0000 magic
104  * This register seems to be used to issue commands to the
105  * acceleration hardware.
106  *
107  */
108 #define IFB_REG_MAGIC			0x0000
109 #define IFB_REG_MAGIC_DIR_BACKWARDS_Y		(0x08 | 0x02)
110 #define IFB_REG_MAGIC_DIR_BACKWARDS_X		(0x04 | 0x01)
111 
112 /*
113  * 0040 component configuration
114  * This register controls which parts of the board will be addressed by
115  * writes to other configuration registers.
116  * Apparently the low two bytes control the frame buffer windows for the
117  * given head (starting at 1).
118  * The high two bytes are texture related.
119  */
120 #define	IFB_REG_COMPONENT_SELECT	0x0040
121 
122 /*
123  * 0044 status
124  * This register has a bit that signals completion of commands issued
125  * to the acceleration hardware.
126  */
127 #define IFB_REG_STATUS			0x0044
128 #define IFB_REG_STATUS_DONE			0x00000004
129 
130 /*
131  * 0058 magnifying configuration
132  * This register apparently controls magnifying.
133  * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8,
134  *   11: by 16)
135  * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8)
136  */
137 #define	IFB_REG_MAGNIFY			0x0058
138 #define	IFB_REG_MAGNIFY_DISABLE			0x00000000
139 #define	IFB_REG_MAGNIFY_X2			0x00000040
140 #define	IFB_REG_MAGNIFY_X4			0x00000080
141 #define	IFB_REG_MAGNIFY_X8			0x000000c0
142 #define	IFB_REG_MAGNIFY_WINDIV2			0x00000000
143 #define	IFB_REG_MAGNIFY_WINDIV4			0x00000010
144 #define	IFB_REG_MAGNIFY_WINDIV8			0x00000020
145 #define	IFB_REG_MAGNIFY_WINDIV16		0x00000030
146 
147 /*
148  * 0070 display resolution
149  * Contains the size of the display, as ((height - 1) << 16) | (width - 1)
150  */
151 #define	IFB_REG_RESOLUTION		0x0070
152 /*
153  * 0074 configuration register
154  * Contains 0x1a000088 | ((Log2 stride) << 16)
155  */
156 #define	IFB_REG_CONFIG			0x0074
157 /*
158  * 0078 32bit frame buffer window #0 (8 to 9 MB)
159  * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
160  */
161 #define	IFB_REG_FB32_0			0x0078
162 /*
163  * 007c 32bit frame buffer window #1 (8 to 9 MB)
164  * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
165  */
166 #define	IFB_REG_FB32_1			0x007c
167 /*
168  * 0080 8bit frame buffer window #0 (2 to 2.2 MB)
169  * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
170  */
171 #define	IFB_REG_FB8_0			0x0080
172 /*
173  * 0084 8bit frame buffer window #1 (2 to 2.2 MB)
174  * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
175  */
176 #define	IFB_REG_FB8_1			0x0084
177 /*
178  * 0088 unknown window (as large as a 32 bit frame buffer)
179  */
180 #define	IFB_REG_FB_UNK0			0x0088
181 /*
182  * 008c unknown window (as large as a 8 bit frame buffer)
183  */
184 #define	IFB_REG_FB_UNK1			0x008c
185 /*
186  * 0090 unknown window (as large as a 8 bit frame buffer)
187  */
188 #define	IFB_REG_FB_UNK2			0x0090
189 
190 /*
191  * 00bc RAMDAC palette index register
192  */
193 #define	IFB_REG_CMAP_INDEX		0x00bc
194 /*
195  * 00c0 RAMDAC palette data register
196  */
197 #define	IFB_REG_CMAP_DATA		0x00c0
198 
199 /*
200  * 00e4 DPMS state register
201  * States ``off'' and ``suspend'' need chip reprogramming before video can
202  * be enabled again.
203  */
204 #define	IFB_REG_DPMS_STATE		0x00e4
205 #define	IFB_REG_DPMS_OFF			0x00000000
206 #define	IFB_REG_DPMS_SUSPEND			0x00000001
207 #define	IFB_REG_DPMS_STANDBY			0x00000002
208 #define	IFB_REG_DPMS_ON				0x00000003
209 
210 #define IFB_COORDS(x, y)	((x) | (y) << 16)
211 
212 struct ifb_softc {
213 	struct sunfb sc_sunfb;
214 	int sc_nscreens;
215 
216 	bus_space_tag_t sc_mem_t;
217 	pcitag_t sc_pcitag;
218 
219 	bus_space_handle_t sc_mem_h;
220 	bus_addr_t sc_membase;
221 	bus_size_t sc_memlen;
222 	vaddr_t	sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr;
223 	bus_space_handle_t sc_reg_h;
224 
225 	struct wsdisplay_emulops sc_old_ops;
226 	void (*sc_old_cursor)(struct rasops_info *);
227 
228 	int sc_console;
229 	u_int8_t sc_cmap_red[256];
230 	u_int8_t sc_cmap_green[256];
231 	u_int8_t sc_cmap_blue[256];
232 };
233 
234 int	ifb_ioctl(void *, u_long, caddr_t, int, struct proc *);
235 paddr_t	ifb_mmap(void *, off_t, int);
236 void	ifb_burner(void *, u_int, u_int);
237 
238 struct wsdisplay_accessops ifb_accessops = {
239 	ifb_ioctl,
240 	ifb_mmap,
241 	NULL,	/* alloc_screen */
242 	NULL,	/* free_screen */
243 	NULL,	/* show_screen */
244 	NULL,	/* load_font */
245 	NULL,	/* scrollback */
246 	NULL,	/* getchar */
247 	ifb_burner,
248 	NULL	/* pollc */
249 };
250 
251 int	ifbmatch(struct device *, void *, void *);
252 void	ifbattach(struct device *, struct device *, void *);
253 
254 struct cfattach ifb_ca = {
255 	sizeof (struct ifb_softc), ifbmatch, ifbattach
256 };
257 
258 struct cfdriver ifb_cd = {
259 	NULL, "ifb", DV_DULL
260 };
261 
262 int	ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *);
263 int	ifb_is_console(int);
264 int	ifb_mapregs(struct ifb_softc *, struct pci_attach_args *);
265 int	ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *);
266 void	ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
267 void	ifb_setcolormap(struct sunfb *,
268 	    void (*)(void *, u_int, u_int8_t, u_int8_t, u_int8_t));
269 
270 void	ifb_copyrect(struct ifb_softc *, int, int, int, int, int, int);
271 void	ifb_putchar(void *, int, int, u_int, long);
272 void	ifb_copycols(void *, int, int, int, int);
273 void	ifb_erasecols(void *, int, int, int, long);
274 void	ifb_copyrows(void *, int, int, int);
275 void	ifb_eraserows(void *, int, int, long);
276 void	ifb_do_cursor(struct rasops_info *);
277 
278 const struct pci_matchid ifb_devices[] = {
279     { PCI_VENDOR_INTERGRAPH, PCI_PRODUCT_INTERGRAPH_EXPERT3D },
280     { PCI_VENDOR_3DLABS,     PCI_PRODUCT_3DLABS_WILDCAT_6210 },
281     { PCI_VENDOR_3DLABS,     PCI_PRODUCT_3DLABS_WILDCAT_5110 },/* Sun XVR-500 */
282     { PCI_VENDOR_3DLABS,     PCI_PRODUCT_3DLABS_WILDCAT_7210 },
283 };
284 
285 int
286 ifbmatch(struct device *parent, void *cf, void *aux)
287 {
288 	struct pci_attach_args *paa = aux;
289 	int node;
290 	char *name;
291 
292 	if (pci_matchbyid(paa, ifb_devices,
293 	    sizeof(ifb_devices) / sizeof(ifb_devices[0])) != 0)
294 		return 1;
295 
296 	node = PCITAG_NODE(paa->pa_tag);
297 	name = getpropstring(node, "name");
298 	if (strcmp(name, "SUNW,Expert3D") == 0 ||
299 	    strcmp(name, "SUNW,Expert3D-Lite") == 0)
300 		return 1;
301 
302 	return 0;
303 }
304 
305 void
306 ifbattach(struct device *parent, struct device *self, void *aux)
307 {
308 	struct ifb_softc *sc = (struct ifb_softc *)self;
309 	struct pci_attach_args *paa = aux;
310 	struct rasops_info *ri;
311 	int node;
312 
313 	sc->sc_mem_t = paa->pa_memt;
314 	sc->sc_pcitag = paa->pa_tag;
315 
316 	printf("\n");
317 
318 	if (ifb_mapregs(sc, paa))
319 		return;
320 
321 	sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h);
322 	sc->sc_fb8bank0_vaddr = sc->sc_memvaddr +
323 	    bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
324 	      IFB_REG_OFFSET + IFB_REG_FB8_0) - sc->sc_membase;
325 	sc->sc_fb8bank1_vaddr = sc->sc_memvaddr +
326 	    bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
327 	      IFB_REG_OFFSET + IFB_REG_FB8_1) - sc->sc_membase;
328 
329 	node = PCITAG_NODE(paa->pa_tag);
330 	sc->sc_console = ifb_is_console(node);
331 
332 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
333 
334 	printf("%s: %dx%d\n",
335 	    self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
336 
337 #if 0
338 	/*
339 	 * Make sure the frame buffer is configured to sane values.
340 	 * So much more is needed there... documentation permitting.
341 	 */
342 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
343 	    IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101);
344 	delay(1000);
345 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
346 	    IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE);
347 #endif
348 
349 	ri = &sc->sc_sunfb.sf_ro;
350 	ri->ri_bits = NULL;
351 	ri->ri_hw = sc;
352 
353 	fbwscons_init(&sc->sc_sunfb, RI_BSWAP, sc->sc_console);
354 	ri->ri_flg &= ~RI_FULLCLEAR;	/* due to the way we handle updates */
355 
356 	if (!sc->sc_console) {
357 		bzero((void *)sc->sc_fb8bank0_vaddr, sc->sc_sunfb.sf_fbsize);
358 		bzero((void *)sc->sc_fb8bank1_vaddr, sc->sc_sunfb.sf_fbsize);
359 	}
360 
361 	/* pick centering delta */
362 	sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits;
363 	sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits;
364 
365 	sc->sc_old_ops = ri->ri_ops;	/* structure copy */
366 	sc->sc_old_cursor = ri->ri_do_cursor;
367 	ri->ri_ops.copyrows = ifb_copyrows;
368 	ri->ri_ops.copycols = ifb_copycols;
369 	ri->ri_ops.eraserows = ifb_eraserows;
370 	ri->ri_ops.erasecols = ifb_erasecols;
371 	ri->ri_ops.putchar = ifb_putchar;
372 	ri->ri_do_cursor = ifb_do_cursor;
373 
374 	ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
375 
376 	if (sc->sc_console)
377 		fbwscons_console_init(&sc->sc_sunfb, -1);
378 	fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console);
379 }
380 
381 int
382 ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
383 {
384 	struct ifb_softc *sc = v;
385 	struct wsdisplay_fbinfo *wdf;
386 	struct pcisel *sel;
387 
388 	switch (cmd) {
389 	case WSDISPLAYIO_GTYPE:
390 		*(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
391 		break;
392 
393 	case WSDISPLAYIO_SMODE:
394 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
395 			ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
396 		break;
397 	case WSDISPLAYIO_GINFO:
398 		wdf = (void *)data;
399 		wdf->height = sc->sc_sunfb.sf_height;
400 		wdf->width  = sc->sc_sunfb.sf_width;
401 		wdf->depth  = sc->sc_sunfb.sf_depth;
402 		wdf->cmsize = 256;
403 		break;
404 	case WSDISPLAYIO_LINEBYTES:
405 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
406 		break;
407 
408 	case WSDISPLAYIO_GETCMAP:
409 		return ifb_getcmap(sc, (struct wsdisplay_cmap *)data);
410 	case WSDISPLAYIO_PUTCMAP:
411 		return ifb_putcmap(sc, (struct wsdisplay_cmap *)data);
412 
413 	case WSDISPLAYIO_GPCIID:
414 		sel = (struct pcisel *)data;
415 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
416 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
417 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
418 		break;
419 
420 	case WSDISPLAYIO_SVIDEO:
421 	case WSDISPLAYIO_GVIDEO:
422 		break;
423 
424 	case WSDISPLAYIO_GCURPOS:
425 	case WSDISPLAYIO_SCURPOS:
426 	case WSDISPLAYIO_GCURMAX:
427 	case WSDISPLAYIO_GCURSOR:
428 	case WSDISPLAYIO_SCURSOR:
429 	default:
430 		return -1; /* not supported yet */
431         }
432 
433 	return 0;
434 }
435 
436 int
437 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
438 {
439 	u_int index = cm->index;
440 	u_int count = cm->count;
441 	int error;
442 
443 	if (index >= 256 || count > 256 - index)
444 		return EINVAL;
445 
446 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
447 	if (error)
448 		return error;
449 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
450 	if (error)
451 		return error;
452 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
453 	if (error)
454 		return error;
455 	return 0;
456 }
457 
458 int
459 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
460 {
461 	u_int index = cm->index;
462 	u_int count = cm->count;
463 	u_int i;
464 	int error;
465 	u_char *r, *g, *b;
466 
467 	if (index >= 256 || count > 256 - index)
468 		return EINVAL;
469 
470 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
471 		return error;
472 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
473 		return error;
474 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
475 		return error;
476 
477 	r = &sc->sc_cmap_red[index];
478 	g = &sc->sc_cmap_green[index];
479 	b = &sc->sc_cmap_blue[index];
480 
481 	for (i = 0; i < count; i++) {
482 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
483 		    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
484 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
485 		    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
486 		    (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2));
487 		r++, g++, b++, index++;
488 	}
489 	return 0;
490 }
491 
492 void
493 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
494 {
495 	struct ifb_softc *sc = v;
496 
497 	sc->sc_cmap_red[index] = r;
498 	sc->sc_cmap_green[index] = g;
499 	sc->sc_cmap_blue[index] = b;
500 
501 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
502 	    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
503 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
504 	    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
505 	    (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2));
506 }
507 
508 /* similar in spirit to fbwscons_setcolormap() */
509 void
510 ifb_setcolormap(struct sunfb *sf,
511     void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
512 {
513 	struct rasops_info *ri = &sf->sf_ro;
514 	int i;
515 	const u_char *color;
516 
517 	/*
518 	 * Compensate for overlay plane limitations. Since we'll operate
519 	 * in 7bpp mode, our basic colors will use positions 00 to 0f,
520 	 * and the inverted colors will use positions 7f to 70.
521 	 */
522 
523 	for (i = 0x00; i < 0x10; i++) {
524 		color = &rasops_cmap[i * 3];
525 		setcolor(sf, i, color[0], color[1], color[2]);
526 	}
527 	for (i = 0x70; i < 0x80; i++) {
528 		color = &rasops_cmap[(0xf0 | i) * 3];
529 		setcolor(sf, i, color[0], color[1], color[2]);
530 	}
531 
532 	/*
533 	 * Proper operation apparently needs black to be 01, always.
534 	 * Replace black, red and white with white, black and red.
535 	 * Kind of ugly, but it works.
536 	 */
537 	ri->ri_devcmap[WSCOL_WHITE] = 0x00000000;
538 	ri->ri_devcmap[WSCOL_BLACK] = 0x01010101;
539 	ri->ri_devcmap[WSCOL_RED] = 0x07070707;
540 
541 	color = &rasops_cmap[(WSCOL_WHITE + 8) * 3];	/* real white */
542 	setcolor(sf, 0, color[0], color[1], color[2]);
543 	setcolor(sf, 0x7f ^ 0, ~color[0], ~color[1], ~color[2]);
544 	color = &rasops_cmap[WSCOL_BLACK * 3];
545 	setcolor(sf, 1, color[0], color[1], color[2]);
546 	setcolor(sf, 0x7f ^ 1, ~color[0], ~color[1], ~color[2]);
547 	color = &rasops_cmap[WSCOL_RED * 3];
548 	setcolor(sf, 7, color[0], color[1], color[2]);
549 	setcolor(sf, 0x7f ^ 7, ~color[0], ~color[1], ~color[2]);
550 }
551 
552 paddr_t
553 ifb_mmap(void *v, off_t off, int prot)
554 {
555 	return -1;
556 }
557 
558 void
559 ifb_burner(void *v, u_int on, u_int flags)
560 {
561 	struct ifb_softc *sc = (struct ifb_softc *)v;
562 	int s;
563 	uint32_t dpms;
564 
565 	s = splhigh();
566 	if (on)
567 		dpms = IFB_REG_DPMS_ON;
568 	else {
569 #ifdef notyet
570 		if (flags & WSDISPLAY_BURN_VBLANK)
571 			dpms = IFB_REG_DPMS_SUSPEND;
572 		else
573 #endif
574 			dpms = IFB_REG_DPMS_STANDBY;
575 	}
576 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
577 	    IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms);
578 	splx(s);
579 }
580 
581 int
582 ifb_is_console(int node)
583 {
584 	extern int fbnode;
585 
586 	return fbnode == node;
587 }
588 
589 int
590 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa)
591 {
592 	u_int32_t cf;
593 	int bar, rc;
594 
595 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG);
596 	bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf);
597 
598 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
599 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
600 		rc = EINVAL;
601 	else {
602 		rc = pci_mapreg_map(pa, bar, cf,
603 		    BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h,
604 		    &sc->sc_membase, &sc->sc_memlen, 0);
605 	}
606 	if (rc != 0) {
607 		printf("%s: can't map video memory\n",
608 		    sc->sc_sunfb.sf_dev.dv_xname);
609 		return rc;
610 	}
611 
612 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4);
613 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
614 		rc = EINVAL;
615 	else {
616 		rc = pci_mapreg_map(pa, bar + 4, cf,
617 		    0, NULL, &sc->sc_reg_h, NULL, NULL, 0x9000);
618 	}
619 	if (rc != 0) {
620 		printf("%s: can't map register space\n",
621 		    sc->sc_sunfb.sf_dev.dv_xname);
622 		return rc;
623 	}
624 
625 	return 0;
626 }
627 
628 void
629 ifb_putchar(void *cookie, int row, int col, u_int uc, long attr)
630 {
631 	struct rasops_info *ri = cookie;
632 	struct ifb_softc *sc = ri->ri_hw;
633 
634 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
635 	sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
636 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
637 	sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
638 }
639 
640 void
641 ifb_copycols(void *cookie, int row, int src, int dst, int num)
642 {
643 	struct rasops_info *ri = cookie;
644 	struct ifb_softc *sc = ri->ri_hw;
645 
646 	num *= ri->ri_font->fontwidth;
647 	src *= ri->ri_font->fontwidth;
648 	dst *= ri->ri_font->fontwidth;
649 	row *= ri->ri_font->fontheight;
650 
651 	ifb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
652 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
653 	    num, ri->ri_font->fontheight);
654 }
655 
656 void
657 ifb_erasecols(void *cookie, int row, int col, int num, long attr)
658 {
659 	struct rasops_info *ri = cookie;
660 	struct ifb_softc *sc = ri->ri_hw;
661 
662 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
663 	sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
664 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
665 	sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
666 }
667 
668 void
669 ifb_copyrows(void *cookie, int src, int dst, int num)
670 {
671 	struct rasops_info *ri = cookie;
672 	struct ifb_softc *sc = ri->ri_hw;
673 
674 	num *= ri->ri_font->fontheight;
675 	src *= ri->ri_font->fontheight;
676 	dst *= ri->ri_font->fontheight;
677 
678 	ifb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
679 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
680 }
681 
682 void
683 ifb_eraserows(void *cookie, int row, int num, long attr)
684 {
685 	struct rasops_info *ri = cookie;
686 	struct ifb_softc *sc = ri->ri_hw;
687 
688 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
689 	sc->sc_old_ops.eraserows(cookie, row, num, attr);
690 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
691 	sc->sc_old_ops.eraserows(cookie, row, num, attr);
692 }
693 
694 void
695 ifb_copyrect(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h)
696 {
697 	int i, dir = 0;
698 
699 	if (sy < dy) {
700 		sy += h - 1;
701 		dy += h;
702 		dir |= IFB_REG_MAGIC_DIR_BACKWARDS_Y;
703 	}
704 	if (sx < dx) {
705 		sx += w - 1;
706 		dx += w;
707 		dir |= IFB_REG_MAGIC_DIR_BACKWARDS_X;
708 	}
709 
710 	/* Lots of magic numbers. */
711 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
712 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 2);
713 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
714 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 1);
715 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
716 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x540101ff);
717 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
718 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x61000001);
719 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
720 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
721 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
722 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x6301c080);
723 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
724 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x80000000);
725 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
726 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00330000);
727 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
728 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0xff);
729 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
730 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
731 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
732 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x64000303);
733 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
734 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
735 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
736 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
737 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
738 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00030000);
739 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
740 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x2200010d);
741 
742 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
743 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x33f01000 | dir);
744 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
745 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(dx, dy));
746 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
747 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(w, h));
748 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
749 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(sx, sy));
750 
751 	for (i = 1000000; i > 0; i--) {
752 		if (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
753 		    IFB_REG_OFFSET + IFB_REG_STATUS) & IFB_REG_STATUS_DONE)
754 			break;
755 		DELAY(1);
756 	}
757 }
758 
759 /*
760  * Similar to rasops_do_cursor(), but using a 7bit pixel mask.
761  */
762 void
763 ifb_do_cursor(struct rasops_info *ri)
764 {
765 	struct ifb_softc *sc = ri->ri_hw;
766 	int full1, height, cnt, slop1, slop2, row, col;
767 	int ovl_offset = sc->sc_fb8bank1_vaddr - sc->sc_fb8bank0_vaddr;
768 	u_char *dp0, *dp1, *rp;
769 
770 	row = ri->ri_crow;
771 	col = ri->ri_ccol;
772 
773 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
774 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
775 	height = ri->ri_font->fontheight;
776 	slop1 = (4 - ((long)rp & 3)) & 3;
777 
778 	if (slop1 > ri->ri_xscale)
779 		slop1 = ri->ri_xscale;
780 
781 	slop2 = (ri->ri_xscale - slop1) & 3;
782 	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
783 
784 	if ((slop1 | slop2) == 0) {
785 		/* A common case */
786 		while (height--) {
787 			dp0 = rp;
788 			dp1 = dp0 + ovl_offset;
789 			rp += ri->ri_stride;
790 
791 			for (cnt = full1; cnt; cnt--) {
792 				*(int32_t *)dp0 ^= 0x7f7f7f7f;
793 				*(int32_t *)dp1 ^= 0x7f7f7f7f;
794 				dp0 += 4;
795 				dp1 += 4;
796 			}
797 		}
798 	} else {
799 		/* XXX this is stupid.. use masks instead */
800 		while (height--) {
801 			dp0 = rp;
802 			dp1 = dp0 + ovl_offset;
803 			rp += ri->ri_stride;
804 
805 			if (slop1 & 1) {
806 				*dp0++ ^= 0x7f;
807 				*dp1++ ^= 0x7f;
808 			}
809 
810 			if (slop1 & 2) {
811 				*(int16_t *)dp0 ^= 0x7f7f;
812 				*(int16_t *)dp1 ^= 0x7f7f;
813 				dp0 += 2;
814 				dp1 += 2;
815 			}
816 
817 			for (cnt = full1; cnt; cnt--) {
818 				*(int32_t *)dp0 ^= 0x7f7f7f7f;
819 				*(int32_t *)dp1 ^= 0x7f7f7f7f;
820 				dp0 += 4;
821 				dp1 += 4;
822 			}
823 
824 			if (slop2 & 1) {
825 				*dp0++ ^= 0x7f;
826 				*dp1++ ^= 0x7f;
827 			}
828 
829 			if (slop2 & 2) {
830 				*(int16_t *)dp0 ^= 0x7f7f;
831 				*(int16_t *)dp1 ^= 0x7f7f;
832 			}
833 		}
834 	}
835 }
836