xref: /openbsd/sys/arch/sparc64/dev/ifb.c (revision 86dac4ab)
1 /*	$OpenBSD: ifb.c,v 1.10 2008/12/29 22:07:35 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, 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 #define IFB_COORDS(x, y)	((x) | (y) << 16)
208 
209 struct ifb_softc {
210 	struct sunfb sc_sunfb;
211 	int sc_nscreens;
212 
213 	bus_space_tag_t sc_mem_t;
214 	pcitag_t sc_pcitag;
215 
216 	bus_space_handle_t sc_mem_h;
217 	bus_addr_t sc_membase;
218 	bus_size_t sc_memlen;
219 	vaddr_t	sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr;
220 	bus_space_handle_t sc_reg_h;
221 
222 	struct wsdisplay_emulops sc_old_ops;
223 	void (*sc_old_cursor)(struct rasops_info *);
224 
225 	int sc_console;
226 	u_int8_t sc_cmap_red[256];
227 	u_int8_t sc_cmap_green[256];
228 	u_int8_t sc_cmap_blue[256];
229 };
230 
231 int	ifb_ioctl(void *, u_long, caddr_t, int, struct proc *);
232 paddr_t	ifb_mmap(void *, off_t, int);
233 void	ifb_burner(void *, u_int, u_int);
234 
235 struct wsdisplay_accessops ifb_accessops = {
236 	ifb_ioctl,
237 	ifb_mmap,
238 	NULL,	/* alloc_screen */
239 	NULL,	/* free_screen */
240 	NULL,	/* show_screen */
241 	NULL,	/* load_font */
242 	NULL,	/* scrollback */
243 	NULL,	/* getchar */
244 	ifb_burner,
245 	NULL	/* pollc */
246 };
247 
248 int	ifbmatch(struct device *, void *, void *);
249 void	ifbattach(struct device *, struct device *, void *);
250 
251 struct cfattach ifb_ca = {
252 	sizeof (struct ifb_softc), ifbmatch, ifbattach
253 };
254 
255 struct cfdriver ifb_cd = {
256 	NULL, "ifb", DV_DULL
257 };
258 
259 int	ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *);
260 int	ifb_is_console(int);
261 int	ifb_mapregs(struct ifb_softc *, struct pci_attach_args *);
262 int	ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *);
263 void	ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
264 void	ifb_setcolormap(struct sunfb *,
265 	    void (*)(void *, u_int, u_int8_t, u_int8_t, u_int8_t));
266 
267 void	ifb_copyrect(struct ifb_softc *, int, int, int, int, int, int);
268 void	ifb_putchar(void *, int, int, u_int, long);
269 void	ifb_copycols(void *, int, int, int, int);
270 void	ifb_erasecols(void *, int, int, int, long);
271 void	ifb_copyrows(void *, int, int, int);
272 void	ifb_eraserows(void *, int, int, long);
273 void	ifb_do_cursor(struct rasops_info *);
274 
275 int
276 ifbmatch(struct device *parent, void *cf, void *aux)
277 {
278 	return ifb_ident(aux);
279 }
280 
281 void
282 ifbattach(struct device *parent, struct device *self, void *aux)
283 {
284 	struct ifb_softc *sc = (struct ifb_softc *)self;
285 	struct pci_attach_args *paa = aux;
286 	struct rasops_info *ri;
287 	int node;
288 
289 	sc->sc_mem_t = paa->pa_memt;
290 	sc->sc_pcitag = paa->pa_tag;
291 
292 	printf("\n");
293 
294 	if (ifb_mapregs(sc, paa))
295 		return;
296 
297 	sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h);
298 	sc->sc_fb8bank0_vaddr = sc->sc_memvaddr +
299 	    bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
300 	      IFB_REG_OFFSET + IFB_REG_FB8_0) - sc->sc_membase;
301 	sc->sc_fb8bank1_vaddr = sc->sc_memvaddr +
302 	    bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
303 	      IFB_REG_OFFSET + IFB_REG_FB8_1) - sc->sc_membase;
304 
305 	node = PCITAG_NODE(paa->pa_tag);
306 	sc->sc_console = ifb_is_console(node);
307 
308 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
309 
310 	printf("%s: %dx%d\n",
311 	    self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
312 
313 #if 0
314 	/*
315 	 * Make sure the frame buffer is configured to sane values.
316 	 * So much more is needed there... documentation permitting.
317 	 */
318 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
319 	    IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101);
320 	delay(1000);
321 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
322 	    IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE);
323 #endif
324 
325 	ri = &sc->sc_sunfb.sf_ro;
326 	ri->ri_bits = NULL;
327 	ri->ri_hw = sc;
328 
329 	fbwscons_init(&sc->sc_sunfb, RI_BSWAP, sc->sc_console);
330 	ri->ri_flg &= ~RI_FULLCLEAR;	/* due to the way we handle updates */
331 
332 	if (!sc->sc_console) {
333 		bzero((void *)sc->sc_fb8bank0_vaddr, sc->sc_sunfb.sf_fbsize);
334 		bzero((void *)sc->sc_fb8bank1_vaddr, sc->sc_sunfb.sf_fbsize);
335 	}
336 
337 	/* pick centering delta */
338 	sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits;
339 	sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits;
340 
341 	sc->sc_old_ops = ri->ri_ops;	/* structure copy */
342 	sc->sc_old_cursor = ri->ri_do_cursor;
343 	ri->ri_ops.copyrows = ifb_copyrows;
344 	ri->ri_ops.copycols = ifb_copycols;
345 	ri->ri_ops.eraserows = ifb_eraserows;
346 	ri->ri_ops.erasecols = ifb_erasecols;
347 	ri->ri_ops.putchar = ifb_putchar;
348 	ri->ri_do_cursor = ifb_do_cursor;
349 
350 	ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
351 
352 	if (sc->sc_console)
353 		fbwscons_console_init(&sc->sc_sunfb, -1);
354 	fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console);
355 }
356 
357 int
358 ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
359 {
360 	struct ifb_softc *sc = v;
361 	struct wsdisplay_fbinfo *wdf;
362 	struct pcisel *sel;
363 
364 	switch (cmd) {
365 	case WSDISPLAYIO_GTYPE:
366 		*(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
367 		break;
368 
369 	case WSDISPLAYIO_SMODE:
370 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
371 			ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
372 		break;
373 	case WSDISPLAYIO_GINFO:
374 		wdf = (void *)data;
375 		wdf->height = sc->sc_sunfb.sf_height;
376 		wdf->width  = sc->sc_sunfb.sf_width;
377 		wdf->depth  = sc->sc_sunfb.sf_depth;
378 		wdf->cmsize = 256;
379 		break;
380 	case WSDISPLAYIO_LINEBYTES:
381 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
382 		break;
383 
384 	case WSDISPLAYIO_GETCMAP:
385 		return ifb_getcmap(sc, (struct wsdisplay_cmap *)data);
386 	case WSDISPLAYIO_PUTCMAP:
387 		return ifb_putcmap(sc, (struct wsdisplay_cmap *)data);
388 
389 	case WSDISPLAYIO_GPCIID:
390 		sel = (struct pcisel *)data;
391 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
392 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
393 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
394 		break;
395 
396 	case WSDISPLAYIO_SVIDEO:
397 	case WSDISPLAYIO_GVIDEO:
398 		break;
399 
400 	case WSDISPLAYIO_GCURPOS:
401 	case WSDISPLAYIO_SCURPOS:
402 	case WSDISPLAYIO_GCURMAX:
403 	case WSDISPLAYIO_GCURSOR:
404 	case WSDISPLAYIO_SCURSOR:
405 	default:
406 		return -1; /* not supported yet */
407         }
408 
409 	return 0;
410 }
411 
412 int
413 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
414 {
415 	u_int index = cm->index;
416 	u_int count = cm->count;
417 	int error;
418 
419 	if (index >= 256 || count > 256 - index)
420 		return EINVAL;
421 
422 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
423 	if (error)
424 		return error;
425 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
426 	if (error)
427 		return error;
428 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
429 	if (error)
430 		return error;
431 	return 0;
432 }
433 
434 int
435 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
436 {
437 	u_int index = cm->index;
438 	u_int count = cm->count;
439 	u_int i;
440 	int error;
441 	u_char *r, *g, *b;
442 
443 	if (index >= 256 || count > 256 - index)
444 		return EINVAL;
445 
446 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
447 		return error;
448 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
449 		return error;
450 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
451 		return error;
452 
453 	r = &sc->sc_cmap_red[index];
454 	g = &sc->sc_cmap_green[index];
455 	b = &sc->sc_cmap_blue[index];
456 
457 	for (i = 0; i < count; i++) {
458 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
459 		    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
460 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
461 		    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
462 		    (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2));
463 		r++, g++, b++, index++;
464 	}
465 	return 0;
466 }
467 
468 void
469 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
470 {
471 	struct ifb_softc *sc = v;
472 
473 	sc->sc_cmap_red[index] = r;
474 	sc->sc_cmap_green[index] = g;
475 	sc->sc_cmap_blue[index] = b;
476 
477 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
478 	    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
479 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
480 	    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
481 	    (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2));
482 }
483 
484 /* similar in spirit to fbwscons_setcolormap() */
485 void
486 ifb_setcolormap(struct sunfb *sf,
487     void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
488 {
489 	struct rasops_info *ri = &sf->sf_ro;
490 	int i;
491 	const u_char *color;
492 
493 	/*
494 	 * Compensate for overlay plane limitations. Since we'll operate
495 	 * in 7bpp mode, our basic colors will use positions 00 to 0f,
496 	 * and the inverted colors will use positions 7f to 70.
497 	 */
498 
499 	for (i = 0x00; i < 0x10; i++) {
500 		color = &rasops_cmap[i * 3];
501 		setcolor(sf, i, color[0], color[1], color[2]);
502 	}
503 	for (i = 0x70; i < 0x80; i++) {
504 		color = &rasops_cmap[(0xf0 | i) * 3];
505 		setcolor(sf, i, color[0], color[1], color[2]);
506 	}
507 
508 	/*
509 	 * Proper operation apparently needs black to be 01, always.
510 	 * Replace black, red and white with white, black and red.
511 	 * Kind of ugly, but it works.
512 	 */
513 	ri->ri_devcmap[WSCOL_WHITE] = 0x00000000;
514 	ri->ri_devcmap[WSCOL_BLACK] = 0x01010101;
515 	ri->ri_devcmap[WSCOL_RED] = 0x07070707;
516 
517 	color = &rasops_cmap[(WSCOL_WHITE + 8) * 3];	/* real white */
518 	setcolor(sf, 0, color[0], color[1], color[2]);
519 	setcolor(sf, 0x7f ^ 0, ~color[0], ~color[1], ~color[2]);
520 	color = &rasops_cmap[WSCOL_BLACK * 3];
521 	setcolor(sf, 1, color[0], color[1], color[2]);
522 	setcolor(sf, 0x7f ^ 1, ~color[0], ~color[1], ~color[2]);
523 	color = &rasops_cmap[WSCOL_RED * 3];
524 	setcolor(sf, 7, color[0], color[1], color[2]);
525 	setcolor(sf, 0x7f ^ 7, ~color[0], ~color[1], ~color[2]);
526 }
527 
528 paddr_t
529 ifb_mmap(void *v, off_t off, int prot)
530 {
531 	return -1;
532 }
533 
534 void
535 ifb_burner(void *v, u_int on, u_int flags)
536 {
537 	struct ifb_softc *sc = (struct ifb_softc *)v;
538 	int s;
539 	uint32_t dpms;
540 
541 	s = splhigh();
542 	if (on)
543 		dpms = IFB_REG_DPMS_ON;
544 	else {
545 #ifdef notyet
546 		if (flags & WSDISPLAY_BURN_VBLANK)
547 			dpms = IFB_REG_DPMS_SUSPEND;
548 		else
549 #endif
550 			dpms = IFB_REG_DPMS_STANDBY;
551 	}
552 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
553 	    IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms);
554 	splx(s);
555 }
556 
557 int
558 ifb_is_console(int node)
559 {
560 	extern int fbnode;
561 
562 	return fbnode == node;
563 }
564 
565 int
566 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa)
567 {
568 	u_int32_t cf;
569 	int bar, rc;
570 
571 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG);
572 	bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf);
573 
574 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
575 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
576 		rc = EINVAL;
577 	else {
578 		rc = pci_mapreg_map(pa, bar, cf,
579 		    BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h,
580 		    &sc->sc_membase, &sc->sc_memlen, 0);
581 	}
582 	if (rc != 0) {
583 		printf("%s: can't map video memory\n",
584 		    sc->sc_sunfb.sf_dev.dv_xname);
585 		return rc;
586 	}
587 
588 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4);
589 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
590 		rc = EINVAL;
591 	else {
592 		rc = pci_mapreg_map(pa, bar + 4, cf,
593 		    0, NULL, &sc->sc_reg_h, NULL, NULL, 0x9000);
594 	}
595 	if (rc != 0) {
596 		printf("%s: can't map register space\n",
597 		    sc->sc_sunfb.sf_dev.dv_xname);
598 		return rc;
599 	}
600 
601 	return 0;
602 }
603 
604 void
605 ifb_putchar(void *cookie, int row, int col, u_int uc, long attr)
606 {
607 	struct rasops_info *ri = cookie;
608 	struct ifb_softc *sc = ri->ri_hw;
609 
610 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
611 	sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
612 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
613 	sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
614 }
615 
616 void
617 ifb_copycols(void *cookie, int row, int src, int dst, int num)
618 {
619 	struct rasops_info *ri = cookie;
620 	struct ifb_softc *sc = ri->ri_hw;
621 
622 	num *= ri->ri_font->fontwidth;
623 	src *= ri->ri_font->fontwidth;
624 	dst *= ri->ri_font->fontwidth;
625 	row *= ri->ri_font->fontheight;
626 
627 	ifb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
628 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
629 	    num, ri->ri_font->fontheight);
630 }
631 
632 void
633 ifb_erasecols(void *cookie, int row, int col, int num, long attr)
634 {
635 	struct rasops_info *ri = cookie;
636 	struct ifb_softc *sc = ri->ri_hw;
637 
638 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
639 	sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
640 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
641 	sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
642 }
643 
644 void
645 ifb_copyrows(void *cookie, int src, int dst, int num)
646 {
647 	struct rasops_info *ri = cookie;
648 	struct ifb_softc *sc = ri->ri_hw;
649 
650 	num *= ri->ri_font->fontheight;
651 	src *= ri->ri_font->fontheight;
652 	dst *= ri->ri_font->fontheight;
653 
654 	ifb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
655 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
656 }
657 
658 void
659 ifb_eraserows(void *cookie, int row, int num, long attr)
660 {
661 	struct rasops_info *ri = cookie;
662 	struct ifb_softc *sc = ri->ri_hw;
663 	int bg, fg, done, cnt;
664 
665 	/*
666 	 * Perform the first line with plain rasops code (adapted below)...
667 	 */
668 
669 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
670 
671 	memset((void *)(sc->sc_fb8bank0_vaddr + row * ri->ri_yscale),
672 	    ri->ri_devcmap[bg], ri->ri_emustride);
673 	memset((void *)(sc->sc_fb8bank1_vaddr + row * ri->ri_yscale),
674 	    ri->ri_devcmap[bg], ri->ri_emustride);
675 
676 	/*
677 	 * ...then copy it over and over until the whole area is done.
678 	 */
679 
680 	row *= ri->ri_font->fontheight;
681 	num *= ri->ri_font->fontheight;
682 	row += ri->ri_yorigin;
683 
684 	for (done = 1, num -= done; num != 0;) {
685 		cnt = min(done, num);
686 
687 		ifb_copyrect(sc, ri->ri_xorigin, row,
688 		    ri->ri_xorigin, row + done, ri->ri_emuwidth, cnt);
689 
690 		done += cnt;
691 		num -= cnt;
692 	}
693 }
694 
695 void
696 ifb_copyrect(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h)
697 {
698 	int i, dir = 0;
699 
700 	if (sy < dy /* && sy + h > dy */) {
701 		sy += h - 1;
702 		dy += h;
703 		dir |= IFB_REG_MAGIC_DIR_BACKWARDS_Y;
704 	}
705 	if (sx < dx /* && sx + w > dx */) {
706 		sx += w - 1;
707 		dx += w;
708 		dir |= IFB_REG_MAGIC_DIR_BACKWARDS_X;
709 	}
710 
711 	/* Lots of magic numbers. */
712 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
713 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 2);
714 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
715 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 1);
716 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
717 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x540101ff);
718 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
719 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x61000001);
720 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
721 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
722 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
723 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x6301c080);
724 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
725 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x80000000);
726 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
727 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00330000);
728 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
729 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0xff);
730 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
731 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
732 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
733 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x64000303);
734 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
735 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
736 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
737 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0);
738 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
739 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00030000);
740 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
741 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x2200010d);
742 
743 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
744 	    IFB_REG_OFFSET + IFB_REG_MAGIC, 0x33f01000 | dir);
745 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
746 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(dx, dy));
747 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
748 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(w, h));
749 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
750 	    IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(sx, sy));
751 
752 	for (i = 1000000; i > 0; i--) {
753 		if (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
754 		    IFB_REG_OFFSET + IFB_REG_STATUS) & IFB_REG_STATUS_DONE)
755 			break;
756 		DELAY(1);
757 	}
758 }
759 
760 /*
761  * Similar to rasops_do_cursor(), but using a 7bit pixel mask.
762  */
763 
764 #define	CURSOR_MASK	0x7f7f7f7f
765 
766 void
767 ifb_do_cursor(struct rasops_info *ri)
768 {
769 	struct ifb_softc *sc = ri->ri_hw;
770 	int full1, height, cnt, slop1, slop2, row, col;
771 	int ovl_offset = sc->sc_fb8bank1_vaddr - sc->sc_fb8bank0_vaddr;
772 	u_char *dp0, *dp1, *rp;
773 
774 	row = ri->ri_crow;
775 	col = ri->ri_ccol;
776 
777 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
778 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
779 	height = ri->ri_font->fontheight;
780 	slop1 = (4 - ((long)rp & 3)) & 3;
781 
782 	if (slop1 > ri->ri_xscale)
783 		slop1 = ri->ri_xscale;
784 
785 	slop2 = (ri->ri_xscale - slop1) & 3;
786 	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
787 
788 	if ((slop1 | slop2) == 0) {
789 		/* A common case */
790 		while (height--) {
791 			dp0 = rp;
792 			dp1 = dp0 + ovl_offset;
793 			rp += ri->ri_stride;
794 
795 			for (cnt = full1; cnt; cnt--) {
796 				*(int32_t *)dp0 ^= CURSOR_MASK;
797 				*(int32_t *)dp1 ^= CURSOR_MASK;
798 				dp0 += 4;
799 				dp1 += 4;
800 			}
801 		}
802 	} else {
803 		/* XXX this is stupid.. use masks instead */
804 		while (height--) {
805 			dp0 = rp;
806 			dp1 = dp0 + ovl_offset;
807 			rp += ri->ri_stride;
808 
809 			if (slop1 & 1) {
810 				*dp0++ ^= (u_char)CURSOR_MASK;
811 				*dp1++ ^= (u_char)CURSOR_MASK;
812 			}
813 
814 			if (slop1 & 2) {
815 				*(int16_t *)dp0 ^= (int16_t)CURSOR_MASK;
816 				*(int16_t *)dp1 ^= (int16_t)CURSOR_MASK;
817 				dp0 += 2;
818 				dp1 += 2;
819 			}
820 
821 			for (cnt = full1; cnt; cnt--) {
822 				*(int32_t *)dp0 ^= CURSOR_MASK;
823 				*(int32_t *)dp1 ^= CURSOR_MASK;
824 				dp0 += 4;
825 				dp1 += 4;
826 			}
827 
828 			if (slop2 & 1) {
829 				*dp0++ ^= (u_char)CURSOR_MASK;
830 				*dp1++ ^= (u_char)CURSOR_MASK;
831 			}
832 
833 			if (slop2 & 2) {
834 				*(int16_t *)dp0 ^= (int16_t)CURSOR_MASK;
835 				*(int16_t *)dp1 ^= (int16_t)CURSOR_MASK;
836 			}
837 		}
838 	}
839 }
840