xref: /openbsd/sys/arch/sparc64/dev/ifb.c (revision f45bd77d)
1 /*	$OpenBSD: ifb.c,v 1.13 2009/01/02 20:36:19 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2007, 2008, 2009 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, of which the non-visible parts
78  * can still be addressed (probably for fast screen switching).
79  *
80  * Unfortunately, since we do not know how to reconfigure the stripes
81  * to provide at least a linear frame buffer, we have to write to both
82  * windows and have them provide the complete image.
83  *
84  * Moreover, high pixel values in the overlay planes (such as 0xff or 0xfe)
85  * seem to enable other planes with random contents, so we'll limit ourselves
86  * to 7bpp opration.
87  */
88 
89 /*
90  * The Expert3D has an extra BAR that is not present on the -Lite
91  * version.  This register contains bits that tell us how many BARs to
92  * skip before we get to the BARs that interest us.
93  */
94 #define IFB_PCI_CFG			0x5c
95 #define IFB_PCI_CFG_BAR_OFFSET(x)	((x & 0x000000e0) >> 3)
96 
97 #define	IFB_REG_OFFSET			0x8000
98 
99 /*
100  * 0000 magic
101  * This register seems to be used to issue commands to the
102  * acceleration hardware.
103  *
104  */
105 #define IFB_REG_MAGIC			0x0000
106 #define IFB_REG_MAGIC_DIR_BACKWARDS_Y		(0x08 | 0x02)
107 #define IFB_REG_MAGIC_DIR_BACKWARDS_X		(0x04 | 0x01)
108 
109 /*
110  * 0040 component configuration
111  * This register controls which parts of the board will be addressed by
112  * writes to other configuration registers.
113  * Apparently the low two bytes control the frame buffer windows for the
114  * given head (starting at 1).
115  * The high two bytes are texture related.
116  */
117 #define	IFB_REG_COMPONENT_SELECT	0x0040
118 
119 /*
120  * 0044 status
121  * This register has a bit that signals completion of commands issued
122  * to the acceleration hardware.
123  */
124 #define IFB_REG_STATUS			0x0044
125 #define IFB_REG_STATUS_DONE			0x00000004
126 
127 /*
128  * 0058 magnifying configuration
129  * This register apparently controls magnifying.
130  * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8,
131  *   11: by 16)
132  * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8)
133  */
134 #define	IFB_REG_MAGNIFY			0x0058
135 #define	IFB_REG_MAGNIFY_DISABLE			0x00000000
136 #define	IFB_REG_MAGNIFY_X2			0x00000040
137 #define	IFB_REG_MAGNIFY_X4			0x00000080
138 #define	IFB_REG_MAGNIFY_X8			0x000000c0
139 #define	IFB_REG_MAGNIFY_WINDIV2			0x00000000
140 #define	IFB_REG_MAGNIFY_WINDIV4			0x00000010
141 #define	IFB_REG_MAGNIFY_WINDIV8			0x00000020
142 #define	IFB_REG_MAGNIFY_WINDIV16		0x00000030
143 
144 /*
145  * 0070 display resolution
146  * Contains the size of the display, as ((height - 1) << 16) | (width - 1)
147  */
148 #define	IFB_REG_RESOLUTION		0x0070
149 /*
150  * 0074 configuration register
151  * Contains 0x1a000088 | ((Log2 stride) << 16)
152  */
153 #define	IFB_REG_CONFIG			0x0074
154 /*
155  * 0078 32bit frame buffer window #0 (8 to 9 MB)
156  * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
157  */
158 #define	IFB_REG_FB32_0			0x0078
159 /*
160  * 007c 32bit frame buffer window #1 (8 to 9 MB)
161  * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
162  */
163 #define	IFB_REG_FB32_1			0x007c
164 /*
165  * 0080 8bit frame buffer window #0 (2 to 2.2 MB)
166  * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
167  */
168 #define	IFB_REG_FB8_0			0x0080
169 /*
170  * 0084 8bit frame buffer window #1 (2 to 2.2 MB)
171  * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
172  */
173 #define	IFB_REG_FB8_1			0x0084
174 /*
175  * 0088 unknown window (as large as a 32 bit frame buffer)
176  */
177 #define	IFB_REG_FB_UNK0			0x0088
178 /*
179  * 008c unknown window (as large as a 8 bit frame buffer)
180  */
181 #define	IFB_REG_FB_UNK1			0x008c
182 /*
183  * 0090 unknown window (as large as a 8 bit frame buffer)
184  */
185 #define	IFB_REG_FB_UNK2			0x0090
186 
187 /*
188  * 00bc RAMDAC palette index register
189  */
190 #define	IFB_REG_CMAP_INDEX		0x00bc
191 /*
192  * 00c0 RAMDAC palette data register
193  */
194 #define	IFB_REG_CMAP_DATA		0x00c0
195 
196 /*
197  * 00e4 DPMS state register
198  * States ``off'' and ``suspend'' need chip reprogramming before video can
199  * be enabled again.
200  */
201 #define	IFB_REG_DPMS_STATE		0x00e4
202 #define	IFB_REG_DPMS_OFF			0x00000000
203 #define	IFB_REG_DPMS_SUSPEND			0x00000001
204 #define	IFB_REG_DPMS_STANDBY			0x00000002
205 #define	IFB_REG_DPMS_ON				0x00000003
206 
207 /*
208  * (some) ROP codes
209  */
210 
211 #define	IFB_ROP_CLEAR	0x00000000	/* clear bits in rop mask */
212 #define	IFB_ROP_SRC	0x00330000	/* copy src bits matching rop mask */
213 #define	IFB_ROP_XOR	0x00cc0000	/* xor src bits with rop mask */
214 #define	IFB_ROP_SET	0x00ff0000	/* set bits in rop mask */
215 
216 #define IFB_COORDS(x, y)	((x) | (y) << 16)
217 
218 #define	IFB_PIXELMASK	0x7f	/* 7bpp */
219 
220 struct ifb_softc {
221 	struct sunfb sc_sunfb;
222 
223 	bus_space_tag_t sc_mem_t;
224 	pcitag_t sc_pcitag;
225 
226 	bus_space_handle_t sc_mem_h;
227 	bus_addr_t sc_membase, sc_fb8bank0_base, sc_fb8bank1_base;
228 	bus_size_t sc_memlen;
229 	vaddr_t	sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr;
230 
231 	bus_space_handle_t sc_reg_h;
232 	bus_addr_t sc_regbase;
233 	bus_size_t sc_reglen;
234 
235 	u_int	sc_mode;
236 
237 	void (*sc_old_putchar)(void *, int, int, u_int, long);
238 
239 	int sc_console;
240 	u_int8_t sc_cmap_red[256];
241 	u_int8_t sc_cmap_green[256];
242 	u_int8_t sc_cmap_blue[256];
243 };
244 
245 int	ifb_ioctl(void *, u_long, caddr_t, int, struct proc *);
246 paddr_t	ifb_mmap(void *, off_t, int);
247 void	ifb_burner(void *, u_int, u_int);
248 
249 struct wsdisplay_accessops ifb_accessops = {
250 	ifb_ioctl,
251 	ifb_mmap,
252 	NULL,	/* alloc_screen */
253 	NULL,	/* free_screen */
254 	NULL,	/* show_screen */
255 	NULL,	/* load_font */
256 	NULL,	/* scrollback */
257 	NULL,	/* getchar */
258 	ifb_burner,
259 	NULL	/* pollc */
260 };
261 
262 int	ifbmatch(struct device *, void *, void *);
263 void	ifbattach(struct device *, struct device *, void *);
264 
265 struct cfattach ifb_ca = {
266 	sizeof (struct ifb_softc), ifbmatch, ifbattach
267 };
268 
269 struct cfdriver ifb_cd = {
270 	NULL, "ifb", DV_DULL
271 };
272 
273 int	ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *);
274 int	ifb_is_console(int);
275 int	ifb_mapregs(struct ifb_softc *, struct pci_attach_args *);
276 int	ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *);
277 void	ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
278 void	ifb_setcolormap(struct sunfb *,
279 	    void (*)(void *, u_int, u_int8_t, u_int8_t, u_int8_t));
280 
281 void	ifb_copyrect(struct ifb_softc *, int, int, int, int, int, int);
282 void	ifb_fillrect(struct ifb_softc *, int, int, int, int, int);
283 void	ifb_rop(struct ifb_softc *, int, int, int, int, int, int, uint32_t,
284 	    int32_t);
285 void	ifb_rop_wait(struct ifb_softc *);
286 
287 void	ifb_putchar(void *, int, int, u_int, long);
288 void	ifb_copycols(void *, int, int, int, int);
289 void	ifb_erasecols(void *, int, int, int, long);
290 void	ifb_copyrows(void *, int, int, int);
291 void	ifb_eraserows(void *, int, int, long);
292 void	ifb_do_cursor(struct rasops_info *);
293 
294 int
295 ifbmatch(struct device *parent, void *cf, void *aux)
296 {
297 	return ifb_ident(aux);
298 }
299 
300 void
301 ifbattach(struct device *parent, struct device *self, void *aux)
302 {
303 	struct ifb_softc *sc = (struct ifb_softc *)self;
304 	struct pci_attach_args *paa = aux;
305 	struct rasops_info *ri;
306 	int node;
307 
308 	sc->sc_mem_t = paa->pa_memt;
309 	sc->sc_pcitag = paa->pa_tag;
310 
311 	printf("\n");
312 
313 	if (ifb_mapregs(sc, paa))
314 		return;
315 
316 	sc->sc_fb8bank0_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
317 	      IFB_REG_OFFSET + IFB_REG_FB8_0);
318 	sc->sc_fb8bank1_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
319 	      IFB_REG_OFFSET + IFB_REG_FB8_1);
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 	    sc->sc_fb8bank0_base - sc->sc_membase;
324 	sc->sc_fb8bank1_vaddr = sc->sc_memvaddr +
325 	    sc->sc_fb8bank1_base - sc->sc_membase;
326 
327 	node = PCITAG_NODE(paa->pa_tag);
328 	sc->sc_console = ifb_is_console(node);
329 
330 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
331 
332 	printf("%s: %dx%d\n",
333 	    self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
334 
335 #if 0
336 	/*
337 	 * Make sure the frame buffer is configured to sane values.
338 	 * So much more is needed there... documentation permitting.
339 	 */
340 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
341 	    IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101);
342 	delay(1000);
343 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
344 	    IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE);
345 #endif
346 
347 	ri = &sc->sc_sunfb.sf_ro;
348 	ri->ri_bits = NULL;
349 	ri->ri_hw = sc;
350 
351 	fbwscons_init(&sc->sc_sunfb, RI_BSWAP, sc->sc_console);
352 
353 	/*
354 	 * Clear the unwanted pixel planes: all if non console (thus
355 	 * white background), and all planes above 7bpp otherwise.
356 	 */
357 	ifb_rop(sc, 0, 0, 0, 0, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height,
358 	    IFB_ROP_CLEAR, sc->sc_console ? ~IFB_PIXELMASK : ~0);
359 	ifb_rop_wait(sc);
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_putchar = ri->ri_ops.putchar;
366 	ri->ri_ops.copyrows = ifb_copyrows;
367 	ri->ri_ops.copycols = ifb_copycols;
368 	ri->ri_ops.eraserows = ifb_eraserows;
369 	ri->ri_ops.erasecols = ifb_erasecols;
370 	ri->ri_ops.putchar = ifb_putchar;
371 	ri->ri_do_cursor = ifb_do_cursor;
372 
373 	ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
374 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
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 	int mode;
388 
389 	switch (cmd) {
390 	case WSDISPLAYIO_GTYPE:
391 		*(u_int *)data = WSDISPLAY_TYPE_IFB;
392 		break;
393 
394 	case WSDISPLAYIO_SMODE:
395 		mode = *(u_int *)data;
396 		if (mode == WSDISPLAYIO_MODE_EMUL)
397 			ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
398 		sc->sc_mode = mode;
399 		break;
400 	case WSDISPLAYIO_GINFO:
401 		wdf = (void *)data;
402 		wdf->height = sc->sc_sunfb.sf_height;
403 		wdf->width  = sc->sc_sunfb.sf_width;
404 		wdf->depth  = sc->sc_sunfb.sf_depth;
405 		wdf->cmsize = 256;
406 		break;
407 	case WSDISPLAYIO_LINEBYTES:
408 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
409 		break;
410 
411 	case WSDISPLAYIO_GETCMAP:
412 		return ifb_getcmap(sc, (struct wsdisplay_cmap *)data);
413 	case WSDISPLAYIO_PUTCMAP:
414 		return ifb_putcmap(sc, (struct wsdisplay_cmap *)data);
415 
416 	case WSDISPLAYIO_GPCIID:
417 		sel = (struct pcisel *)data;
418 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
419 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
420 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
421 		break;
422 
423 	case WSDISPLAYIO_SVIDEO:
424 	case WSDISPLAYIO_GVIDEO:
425 		break;
426 
427 	case WSDISPLAYIO_GCURPOS:
428 	case WSDISPLAYIO_SCURPOS:
429 	case WSDISPLAYIO_GCURMAX:
430 	case WSDISPLAYIO_GCURSOR:
431 	case WSDISPLAYIO_SCURSOR:
432 	default:
433 		return -1; /* not supported yet */
434         }
435 
436 	return 0;
437 }
438 
439 int
440 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
441 {
442 	u_int index = cm->index;
443 	u_int count = cm->count;
444 	int error;
445 
446 	if (index >= 256 || count > 256 - index)
447 		return EINVAL;
448 
449 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
450 	if (error)
451 		return error;
452 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
453 	if (error)
454 		return error;
455 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
456 	if (error)
457 		return error;
458 	return 0;
459 }
460 
461 int
462 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
463 {
464 	u_int index = cm->index;
465 	u_int count = cm->count;
466 	u_int i;
467 	int error;
468 	u_char *r, *g, *b;
469 
470 	if (index >= 256 || count > 256 - index)
471 		return EINVAL;
472 
473 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
474 		return error;
475 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
476 		return error;
477 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
478 		return error;
479 
480 	r = &sc->sc_cmap_red[index];
481 	g = &sc->sc_cmap_green[index];
482 	b = &sc->sc_cmap_blue[index];
483 
484 	for (i = 0; i < count; i++) {
485 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
486 		    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
487 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
488 		    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
489 		    (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2));
490 		r++, g++, b++, index++;
491 	}
492 	return 0;
493 }
494 
495 void
496 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
497 {
498 	struct ifb_softc *sc = v;
499 
500 	sc->sc_cmap_red[index] = r;
501 	sc->sc_cmap_green[index] = g;
502 	sc->sc_cmap_blue[index] = b;
503 
504 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
505 	    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
506 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
507 	    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
508 	    (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2));
509 }
510 
511 /* similar in spirit to fbwscons_setcolormap() */
512 void
513 ifb_setcolormap(struct sunfb *sf,
514     void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
515 {
516 	struct rasops_info *ri = &sf->sf_ro;
517 	int i;
518 	const u_char *color;
519 
520 	/*
521 	 * Compensate for overlay plane limitations. Since we'll operate
522 	 * in 7bpp mode, our basic colors will use positions 00 to 0f,
523 	 * and the inverted colors will use positions 7f to 70.
524 	 */
525 
526 	for (i = 0x00; i < 0x10; i++) {
527 		color = &rasops_cmap[i * 3];
528 		setcolor(sf, i, color[0], color[1], color[2]);
529 	}
530 	for (i = 0x70; i < 0x80; i++) {
531 		color = &rasops_cmap[(0xf0 | i) * 3];
532 		setcolor(sf, i, color[0], color[1], color[2]);
533 	}
534 
535 	/*
536 	 * Proper operation apparently needs black to be 01, always.
537 	 * Replace black, red and white with white, black and red.
538 	 * Kind of ugly, but it works.
539 	 */
540 	ri->ri_devcmap[WSCOL_WHITE] = 0x00000000;
541 	ri->ri_devcmap[WSCOL_BLACK] = 0x01010101;
542 	ri->ri_devcmap[WSCOL_RED] = 0x07070707;
543 
544 	color = &rasops_cmap[(WSCOL_WHITE + 8) * 3];	/* real white */
545 	setcolor(sf, 0, color[0], color[1], color[2]);
546 	setcolor(sf, IFB_PIXELMASK ^ 0, ~color[0], ~color[1], ~color[2]);
547 	color = &rasops_cmap[WSCOL_BLACK * 3];
548 	setcolor(sf, 1, color[0], color[1], color[2]);
549 	setcolor(sf, IFB_PIXELMASK ^ 1, ~color[0], ~color[1], ~color[2]);
550 	color = &rasops_cmap[WSCOL_RED * 3];
551 	setcolor(sf, 7, color[0], color[1], color[2]);
552 	setcolor(sf, IFB_PIXELMASK ^ 7, ~color[0], ~color[1], ~color[2]);
553 }
554 
555 paddr_t
556 ifb_mmap(void *v, off_t off, int prot)
557 {
558 	struct ifb_softc *sc = (struct ifb_softc *)v;
559 
560 	switch (sc->sc_mode) {
561 	case WSDISPLAYIO_MODE_MAPPED:
562 		/*
563 		 * In mapped mode, provide access to the two overlays,
564 		 * followed by the control registers, at the following
565 		 * addresses:
566 		 * 00000000	overlay 0, size up to 2MB (visible fb size)
567 		 * 01000000	overlay 1, size up to 2MB (visible fb size)
568 		 * 02000000	control registers
569 		 */
570 		off -= 0x00000000;
571 		if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) {
572 			return bus_space_mmap(sc->sc_mem_t,
573 			    sc->sc_fb8bank0_base,
574 			    off, prot, BUS_SPACE_MAP_LINEAR);
575 		}
576 		off -= 0x01000000;
577 		if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) {
578 			return bus_space_mmap(sc->sc_mem_t,
579 			    sc->sc_fb8bank1_base,
580 			    off, prot, BUS_SPACE_MAP_LINEAR);
581 		}
582 #ifdef notyet	/* not needed so far, will require an aperture check */
583 		off -= 0x01000000;
584 		if (off >= 0 && off < round_page(sc->sc_reglen)) {
585 			return bus_space_mmap(sc->sc_mem_t, sc->sc_regbase,
586 			    off, prot, BUS_SPACE_MAP_LINEAR);
587 		}
588 #endif
589 		break;
590 	}
591 
592 	return -1;
593 }
594 
595 void
596 ifb_burner(void *v, u_int on, u_int flags)
597 {
598 	struct ifb_softc *sc = (struct ifb_softc *)v;
599 	int s;
600 	uint32_t dpms;
601 
602 	s = splhigh();
603 	if (on)
604 		dpms = IFB_REG_DPMS_ON;
605 	else {
606 #ifdef notyet
607 		if (flags & WSDISPLAY_BURN_VBLANK)
608 			dpms = IFB_REG_DPMS_SUSPEND;
609 		else
610 #endif
611 			dpms = IFB_REG_DPMS_STANDBY;
612 	}
613 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
614 	    IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms);
615 	splx(s);
616 }
617 
618 int
619 ifb_is_console(int node)
620 {
621 	extern int fbnode;
622 
623 	return fbnode == node;
624 }
625 
626 int
627 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa)
628 {
629 	u_int32_t cf;
630 	int bar, rc;
631 
632 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG);
633 	bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf);
634 
635 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
636 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
637 		rc = EINVAL;
638 	else {
639 		rc = pci_mapreg_map(pa, bar, cf,
640 		    BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h,
641 		    &sc->sc_membase, &sc->sc_memlen, 0);
642 	}
643 	if (rc != 0) {
644 		printf("%s: can't map video memory\n",
645 		    sc->sc_sunfb.sf_dev.dv_xname);
646 		return rc;
647 	}
648 
649 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4);
650 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
651 		rc = EINVAL;
652 	else {
653 		rc = pci_mapreg_map(pa, bar + 4, cf,
654 		    0, NULL, &sc->sc_reg_h,
655 		     &sc->sc_regbase, &sc->sc_reglen, 0x9000);
656 	}
657 	if (rc != 0) {
658 		printf("%s: can't map register space\n",
659 		    sc->sc_sunfb.sf_dev.dv_xname);
660 		return rc;
661 	}
662 
663 	return 0;
664 }
665 
666 void
667 ifb_putchar(void *cookie, int row, int col, u_int uc, long attr)
668 {
669 	struct rasops_info *ri = cookie;
670 	struct ifb_softc *sc = ri->ri_hw;
671 
672 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
673 	sc->sc_old_putchar(cookie, row, col, uc, attr);
674 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
675 	sc->sc_old_putchar(cookie, row, col, uc, attr);
676 }
677 
678 void
679 ifb_copycols(void *cookie, int row, int src, int dst, int num)
680 {
681 	struct rasops_info *ri = cookie;
682 	struct ifb_softc *sc = ri->ri_hw;
683 
684 	num *= ri->ri_font->fontwidth;
685 	src *= ri->ri_font->fontwidth;
686 	dst *= ri->ri_font->fontwidth;
687 	row *= ri->ri_font->fontheight;
688 
689 	ifb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
690 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
691 	    num, ri->ri_font->fontheight);
692 }
693 
694 void
695 ifb_erasecols(void *cookie, int row, int col, int num, long attr)
696 {
697 	struct rasops_info *ri = cookie;
698 	struct ifb_softc *sc = ri->ri_hw;
699 	int bg, fg;
700 
701 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
702 
703 	row *= ri->ri_font->fontheight;
704 	col *= ri->ri_font->fontwidth;
705 	num *= ri->ri_font->fontwidth;
706 
707 	ifb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
708 	    num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
709 }
710 
711 void
712 ifb_copyrows(void *cookie, int src, int dst, int num)
713 {
714 	struct rasops_info *ri = cookie;
715 	struct ifb_softc *sc = ri->ri_hw;
716 
717 	num *= ri->ri_font->fontheight;
718 	src *= ri->ri_font->fontheight;
719 	dst *= ri->ri_font->fontheight;
720 
721 	ifb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
722 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
723 }
724 
725 void
726 ifb_eraserows(void *cookie, int row, int num, long attr)
727 {
728 	struct rasops_info *ri = cookie;
729 	struct ifb_softc *sc = ri->ri_hw;
730 	int bg, fg;
731 	int x, y, w;
732 
733 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
734 
735 	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
736 		num = ri->ri_height;
737 		x = y = 0;
738 		w = ri->ri_width;
739 	} else {
740 		num *= ri->ri_font->fontheight;
741 		x = ri->ri_xorigin;
742 		y = ri->ri_yorigin + row * ri->ri_font->fontheight;
743 		w = ri->ri_emuwidth;
744 	}
745 	ifb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
746 }
747 
748 void
749 ifb_copyrect(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h)
750 {
751 	ifb_rop(sc, sx, sy, dx, dy, w, h, IFB_ROP_SRC, IFB_PIXELMASK);
752 	ifb_rop_wait(sc);
753 }
754 
755 void
756 ifb_fillrect(struct ifb_softc *sc, int x, int y, int w, int h, int bg)
757 {
758 	int32_t mask;
759 
760 	/* pixels to set... */
761 	mask = IFB_PIXELMASK & bg;
762 	if (mask != 0) {
763 		ifb_rop(sc, x, y, x, y, w, h, IFB_ROP_SET, mask);
764 		ifb_rop_wait(sc);
765 	}
766 
767 	/* pixels to clear... */
768 	mask = IFB_PIXELMASK & ~bg;
769 	if (mask != 0) {
770 		ifb_rop(sc, x, y, x, y, w, h, IFB_ROP_CLEAR, mask);
771 		ifb_rop_wait(sc);
772 	}
773 }
774 
775 /*
776  * Perform a raster operation on both overlay planes.
777  * Puzzled by all the magic numbers in there? So are we. Isn't a dire
778  * lack of documentation wonderful?
779  */
780 void
781 ifb_rop(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h,
782     uint32_t rop, int32_t planemask)
783 {
784 	int dir = 0;
785 
786 	/*
787 	 * Compute rop direction. This only really matters for
788 	 * screen-to-screen copies.
789 	 */
790 	if (sy < dy /* && sy + h > dy */) {
791 		sy += h - 1;
792 		dy += h;
793 		dir |= IFB_REG_MAGIC_DIR_BACKWARDS_Y;
794 	}
795 	if (sx < dx /* && sx + w > dx */) {
796 		sx += w - 1;
797 		dx += w;
798 		dir |= IFB_REG_MAGIC_DIR_BACKWARDS_X;
799 	}
800 
801 	/* Which one of those below is your magic number for today? */
802 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
803 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 2);
804 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
805 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 1);
806 	/* the ``0101'' part is probably a component selection */
807 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
808 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x540101ff);
809 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
810 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x61000001);
811 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
812 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
813 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
814 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x6301c080);
815 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
816 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x80000000);
817 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
818 	    IFB_REG_OFFSET + IFB_REG_MAGIC, rop);
819 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
820 	    IFB_REG_OFFSET + IFB_REG_MAGIC, planemask);
821 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
822 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
823 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
824 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x64000303);
825 	/*
826 	 * This value is a pixel offset within the destination area. It is
827 	 * probably used to define complex polygon shapes, with the
828 	 * last pixel in the list being back to (0,0).
829 	 */
830 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
831 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(0, 0));
832 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
833 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
834 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
835 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00030000);
836 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
837 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x2200010d);
838 
839 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
840 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x33f01000 | dir);
841 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
842 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(dx, dy));
843 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
844 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(w, h));
845 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
846 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(sx, sy));
847 }
848 
849 void
850 ifb_rop_wait(struct ifb_softc *sc)
851 {
852 	int i;
853 
854 	for (i = 1000000; i > 0; i--) {
855 		if (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
856 		    IFB_REG_OFFSET + IFB_REG_STATUS) & IFB_REG_STATUS_DONE)
857 			break;
858 		DELAY(1);
859 	}
860 }
861 
862 void
863 ifb_do_cursor(struct rasops_info *ri)
864 {
865 	struct ifb_softc *sc = ri->ri_hw;
866 	int y, x;
867 
868 	y = ri->ri_yorigin + ri->ri_crow * ri->ri_font->fontheight;
869 	x = ri->ri_xorigin + ri->ri_ccol * ri->ri_font->fontwidth;
870 
871 	ifb_rop(sc, x, y, x, y, ri->ri_font->fontwidth, ri->ri_font->fontheight,
872 	    IFB_ROP_XOR, IFB_PIXELMASK);
873 	ifb_rop_wait(sc);
874 }
875