xref: /openbsd/sys/arch/sparc64/dev/ifb.c (revision 9c2b19e4)
1 /*	$OpenBSD: ifb.c,v 1.3 2008/12/27 14:33:55 kettenis 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 reconfigured 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. This however leads
86  * to parasite overlays appearing sometimes in the screen...
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  * 0040 component configuration
101  * This register controls which parts of the board will be addressed by
102  * writes to other configuration registers.
103  * Apparently the low two bytes control the frame buffer windows for the
104  * given head (starting at 1).
105  * The high two bytes are texture related.
106  */
107 #define	IFB_REG_COMPONENT_SELECT	0x0040
108 
109 /*
110  * 0058 magnifying configuration
111  * This register apparently controls magnifying.
112  * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8,
113  *   11: by 16)
114  * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8)
115  */
116 #define	IFB_REG_MAGNIFY			0x0058
117 #define	IFB_REG_MAGNIFY_DISABLE			0x00000000
118 #define	IFB_REG_MAGNIFY_X2			0x00000040
119 #define	IFB_REG_MAGNIFY_X4			0x00000080
120 #define	IFB_REG_MAGNIFY_X8			0x000000c0
121 #define	IFB_REG_MAGNIFY_WINDIV2			0x00000000
122 #define	IFB_REG_MAGNIFY_WINDIV4			0x00000010
123 #define	IFB_REG_MAGNIFY_WINDIV8			0x00000020
124 #define	IFB_REG_MAGNIFY_WINDIV16		0x00000030
125 
126 /*
127  * 0070 display resolution
128  * Contains the size of the display, as ((height - 1) << 16) | (width - 1)
129  */
130 #define	IFB_REG_RESOLUTION		0x0070
131 /*
132  * 0074 configuration register
133  * Contains 0x1a000088 | ((Log2 stride) << 16)
134  */
135 #define	IFB_REG_CONFIG			0x0074
136 /*
137  * 0078 32bit frame buffer window #0 (8 to 9 MB)
138  * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
139  */
140 #define	IFB_REG_FB32_0			0x0078
141 /*
142  * 007c 32bit frame buffer window #1 (8 to 9 MB)
143  * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
144  */
145 #define	IFB_REG_FB32_1			0x007c
146 /*
147  * 0080 8bit frame buffer window #0 (2 to 2.2 MB)
148  * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
149  */
150 #define	IFB_REG_FB8_0			0x0080
151 /*
152  * 0084 8bit frame buffer window #1 (2 to 2.2 MB)
153  * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
154  */
155 #define	IFB_REG_FB8_1			0x0084
156 /*
157  * 0088 unknown window (as large as a 32 bit frame buffer)
158  */
159 #define	IFB_REG_FB_UNK0			0x0088
160 /*
161  * 008c unknown window (as large as a 8 bit frame buffer)
162  */
163 #define	IFB_REG_FB_UNK1			0x008c
164 /*
165  * 0090 unknown window (as large as a 8 bit frame buffer)
166  */
167 #define	IFB_REG_FB_UNK2			0x0090
168 
169 /*
170  * 00bc RAMDAC palette index register
171  */
172 #define	IFB_REG_CMAP_INDEX		0x00bc
173 /*
174  * 00c0 RAMDAC palette data register
175  */
176 #define	IFB_REG_CMAP_DATA		0x00c0
177 
178 /*
179  * 00e4 DPMS state register
180  * States ``off'' and ``suspend'' need chip reprogramming before video can
181  * be enabled again.
182  */
183 #define	IFB_REG_DPMS_STATE		0x00e4
184 #define	IFB_REG_DPMS_OFF			0x00000000
185 #define	IFB_REG_DPMS_SUSPEND			0x00000001
186 #define	IFB_REG_DPMS_STANDBY			0x00000002
187 #define	IFB_REG_DPMS_ON				0x00000003
188 
189 struct ifb_softc {
190 	struct sunfb sc_sunfb;
191 	int sc_nscreens;
192 
193 	bus_space_tag_t sc_mem_t;
194 	pcitag_t sc_pcitag;
195 
196 	bus_space_handle_t sc_mem_h;
197 	bus_addr_t sc_membase;
198 	bus_size_t sc_memlen;
199 	vaddr_t	sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr;
200 	bus_space_handle_t sc_reg_h;
201 
202 	struct wsdisplay_emulops sc_old_ops;
203 	void (*sc_old_cursor)(struct rasops_info *);
204 
205 	int sc_console;
206 	u_int8_t sc_cmap_red[256];
207 	u_int8_t sc_cmap_green[256];
208 	u_int8_t sc_cmap_blue[256];
209 };
210 
211 int	ifb_ioctl(void *, u_long, caddr_t, int, struct proc *);
212 paddr_t	ifb_mmap(void *, off_t, int);
213 int	ifb_alloc_screen(void *, const struct wsscreen_descr *, void **,
214 	    int *, int *, long *);
215 void	ifb_free_screen(void *, void *);
216 int	ifb_show_screen(void *, void *, int,
217 	    void (*cb)(void *, int, int), void *);
218 void	ifb_burner(void *, u_int, u_int);
219 
220 struct wsdisplay_accessops ifb_accessops = {
221 	ifb_ioctl,
222 	ifb_mmap,
223 	ifb_alloc_screen,
224 	ifb_free_screen,
225 	ifb_show_screen,
226 	NULL,
227 	NULL,
228 	NULL,
229 	ifb_burner
230 };
231 
232 int	ifbmatch(struct device *, void *, void *);
233 void	ifbattach(struct device *, struct device *, void *);
234 
235 struct cfattach ifb_ca = {
236 	sizeof (struct ifb_softc), ifbmatch, ifbattach
237 };
238 
239 struct cfdriver ifb_cd = {
240 	NULL, "ifb", DV_DULL
241 };
242 
243 int	ifb_mapregs(struct ifb_softc *, struct pci_attach_args *);
244 int	ifb_is_console(int);
245 int	ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *);
246 int	ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *);
247 void	ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
248 
249 void	ifb_putchar(void *, int, int, u_int, long);
250 void	ifb_copycols(void *, int, int, int, int);
251 void	ifb_erasecols(void *, int, int, int, long);
252 void	ifb_copyrows(void *, int, int, int);
253 void	ifb_eraserows(void *, int, int, long);
254 void	ifb_do_cursor(struct rasops_info *);
255 
256 const struct pci_matchid ifb_devices[] = {
257     { PCI_VENDOR_INTERGRAPH, PCI_PRODUCT_INTERGRAPH_EXPERT3D },
258     { PCI_VENDOR_3DLABS,     PCI_PRODUCT_3DLABS_WILDCAT_6210 },
259     { PCI_VENDOR_3DLABS,     PCI_PRODUCT_3DLABS_WILDCAT_5110 },/* Sun XVR-500 */
260     { PCI_VENDOR_3DLABS,     PCI_PRODUCT_3DLABS_WILDCAT_7210 },
261 };
262 
263 int
264 ifbmatch(struct device *parent, void *cf, void *aux)
265 {
266 	struct pci_attach_args *paa = aux;
267 	int node;
268 	char *name;
269 
270 	if (pci_matchbyid(paa, ifb_devices,
271 	    sizeof(ifb_devices) / sizeof(ifb_devices[0])) != 0)
272 		return 1;
273 
274 	node = PCITAG_NODE(paa->pa_tag);
275 	name = getpropstring(node, "name");
276 	if (strcmp(name, "SUNW,Expert3D") == 0 ||
277 	    strcmp(name, "SUNW,Expert3D-Lite") == 0)
278 		return 1;
279 
280 	return 0;
281 }
282 
283 void
284 ifbattach(struct device *parent, struct device *self, void *aux)
285 {
286 	struct ifb_softc *sc = (struct ifb_softc *)self;
287 	struct pci_attach_args *paa = aux;
288 	struct rasops_info *ri;
289 	int node;
290 
291 	sc->sc_mem_t = paa->pa_memt;
292 	sc->sc_pcitag = paa->pa_tag;
293 
294 	printf("\n");
295 
296 	if (ifb_mapregs(sc, paa))
297 		return;
298 
299 	sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h);
300 	sc->sc_fb8bank0_vaddr = sc->sc_memvaddr +
301 	    bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
302 	      IFB_REG_OFFSET + IFB_REG_FB8_0) - sc->sc_membase;
303 	sc->sc_fb8bank1_vaddr = sc->sc_memvaddr +
304 	    bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
305 	      IFB_REG_OFFSET + IFB_REG_FB8_1) - sc->sc_membase;
306 
307 	node = PCITAG_NODE(paa->pa_tag);
308 	sc->sc_console = ifb_is_console(node);
309 
310 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
311 
312 	printf("%s: %dx%d\n",
313 	    self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
314 
315 #if 0
316 	/*
317 	 * Make sure the frame buffer is configured to sane values.
318 	 * So much more is needed there... documentation permitting.
319 	 */
320 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
321 	    IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101);
322 	delay(1000);
323 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
324 	    IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE);
325 #endif
326 
327 	ri = &sc->sc_sunfb.sf_ro;
328 	ri->ri_bits = NULL;
329 	ri->ri_hw = sc;
330 
331 	/* do NOT pass RI_CLEAR yet */
332 	fbwscons_init(&sc->sc_sunfb, RI_BSWAP);
333 	ri->ri_flg &= ~RI_FULLCLEAR;	/* due to the way we handle updates */
334 
335 	if (!sc->sc_console) {
336 		bzero((void *)sc->sc_fb8bank0_vaddr, sc->sc_sunfb.sf_fbsize);
337 		bzero((void *)sc->sc_fb8bank1_vaddr, sc->sc_sunfb.sf_fbsize);
338 	}
339 
340 	/* pick centering delta */
341 	sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits;
342 	sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits;
343 
344 	sc->sc_old_ops = ri->ri_ops;	/* structure copy */
345 	sc->sc_old_cursor = ri->ri_do_cursor;
346 	ri->ri_ops.copyrows = ifb_copyrows;
347 	ri->ri_ops.copycols = ifb_copycols;
348 	ri->ri_ops.eraserows = ifb_eraserows;
349 	ri->ri_ops.erasecols = ifb_erasecols;
350 	ri->ri_ops.putchar = ifb_putchar;
351 	ri->ri_do_cursor = ifb_do_cursor;
352 
353 	fbwscons_setcolormap(&sc->sc_sunfb, ifb_setcolor);
354 	if (sc->sc_console)
355 		fbwscons_console_init(&sc->sc_sunfb, -1);
356 	fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console);
357 }
358 
359 int
360 ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
361 {
362 	struct ifb_softc *sc = v;
363 	struct wsdisplay_fbinfo *wdf;
364 	struct pcisel *sel;
365 
366 	switch (cmd) {
367 	case WSDISPLAYIO_GTYPE:
368 		*(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
369 		break;
370 
371 	case WSDISPLAYIO_SMODE:
372 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
373 			fbwscons_setcolormap(&sc->sc_sunfb, ifb_setcolor);
374 		break;
375 	case WSDISPLAYIO_GINFO:
376 		wdf = (void *)data;
377 		wdf->height = sc->sc_sunfb.sf_height;
378 		wdf->width  = sc->sc_sunfb.sf_width;
379 		wdf->depth  = sc->sc_sunfb.sf_depth;
380 		wdf->cmsize = 256;
381 		break;
382 	case WSDISPLAYIO_LINEBYTES:
383 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
384 		break;
385 
386 	case WSDISPLAYIO_GETCMAP:
387 		return ifb_getcmap(sc, (struct wsdisplay_cmap *)data);
388 	case WSDISPLAYIO_PUTCMAP:
389 		return ifb_putcmap(sc, (struct wsdisplay_cmap *)data);
390 
391 	case WSDISPLAYIO_GPCIID:
392 		sel = (struct pcisel *)data;
393 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
394 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
395 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
396 		break;
397 
398 	case WSDISPLAYIO_SVIDEO:
399 	case WSDISPLAYIO_GVIDEO:
400 		break;
401 
402 	case WSDISPLAYIO_GCURPOS:
403 	case WSDISPLAYIO_SCURPOS:
404 	case WSDISPLAYIO_GCURMAX:
405 	case WSDISPLAYIO_GCURSOR:
406 	case WSDISPLAYIO_SCURSOR:
407 	default:
408 		return -1; /* not supported yet */
409         }
410 
411 	return 0;
412 }
413 
414 int
415 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
416 {
417 	u_int index = cm->index;
418 	u_int count = cm->count;
419 	int error;
420 
421 	if (index >= 256 || count > 256 - index)
422 		return EINVAL;
423 
424 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
425 	if (error)
426 		return error;
427 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
428 	if (error)
429 		return error;
430 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
431 	if (error)
432 		return error;
433 	return 0;
434 }
435 
436 int
437 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
438 {
439 	u_int index = cm->index;
440 	u_int count = cm->count;
441 	u_int i;
442 	int error;
443 	u_char *r, *g, *b;
444 
445 	if (index >= 256 || count > 256 - index)
446 		return EINVAL;
447 
448 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
449 		return error;
450 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
451 		return error;
452 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
453 		return error;
454 
455 	r = &sc->sc_cmap_red[index];
456 	g = &sc->sc_cmap_green[index];
457 	b = &sc->sc_cmap_blue[index];
458 
459 	for (i = 0; i < count; i++) {
460 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
461 		    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
462 		bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
463 		    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
464 		    (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2));
465 		r++, g++, b++, index++;
466 	}
467 	return 0;
468 }
469 
470 void
471 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
472 {
473 	struct ifb_softc *sc = v;
474 
475 	sc->sc_cmap_red[index] = r;
476 	sc->sc_cmap_green[index] = g;
477 	sc->sc_cmap_blue[index] = b;
478 
479 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
480 	    IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
481 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
482 	    IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
483 	    (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2));
484 }
485 
486 int
487 ifb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
488     int *curxp, int *curyp, long *attrp)
489 {
490 	struct ifb_softc *sc = v;
491 
492 	if (sc->sc_nscreens > 0)
493 		return ENOMEM;
494 
495 	*cookiep = &sc->sc_sunfb.sf_ro;
496 	*curyp = 0;
497 	*curxp = 0;
498 	sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
499 	    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
500 	sc->sc_nscreens++;
501 	return 0;
502 }
503 
504 void
505 ifb_free_screen(void *v, void *cookie)
506 {
507 	struct ifb_softc *sc = v;
508 
509 	sc->sc_nscreens--;
510 }
511 
512 int
513 ifb_show_screen(void *v, void *cookie, int waitok,
514     void (*cb)(void *, int, int), void *cbarg)
515 {
516 	return 0;
517 }
518 
519 paddr_t
520 ifb_mmap(void *v, off_t off, int prot)
521 {
522 	return -1;
523 }
524 
525 void
526 ifb_burner(void *v, u_int on, u_int flags)
527 {
528 	struct ifb_softc *sc = (struct ifb_softc *)v;
529 	int s;
530 	uint32_t dpms;
531 
532 	s = splhigh();
533 	if (on)
534 		dpms = IFB_REG_DPMS_ON;
535 	else {
536 #ifdef notyet
537 		if (flags & WSDISPLAY_BURN_VBLANK)
538 			dpms = IFB_REG_DPMS_SUSPEND;
539 		else
540 #endif
541 			dpms = IFB_REG_DPMS_STANDBY;
542 	}
543 	bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
544 	    IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms);
545 	splx(s);
546 }
547 
548 int
549 ifb_is_console(int node)
550 {
551 	extern int fbnode;
552 
553 	return fbnode == node;
554 }
555 
556 int
557 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa)
558 {
559 	u_int32_t cf;
560 	int bar, rc;
561 
562 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG);
563 	bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf);
564 
565 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
566 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
567 		rc = EINVAL;
568 	else {
569 		rc = pci_mapreg_map(pa, bar, cf,
570 		    BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h,
571 		    &sc->sc_membase, &sc->sc_memlen, 0);
572 	}
573 	if (rc != 0) {
574 		printf("%s: can't map video memory\n",
575 		    sc->sc_sunfb.sf_dev.dv_xname);
576 		return rc;
577 	}
578 
579 	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4);
580 	if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
581 		rc = EINVAL;
582 	else {
583 		rc = pci_mapreg_map(pa, bar + 4, cf,
584 		    0, NULL, &sc->sc_reg_h, NULL, NULL, 0x9000);
585 	}
586 	if (rc != 0) {
587 		printf("%s: can't map register space\n",
588 		    sc->sc_sunfb.sf_dev.dv_xname);
589 		return rc;
590 	}
591 
592 	return 0;
593 }
594 
595 void
596 ifb_putchar(void *cookie, int row, int col, u_int uc, long attr)
597 {
598 	struct rasops_info *ri = cookie;
599 	struct ifb_softc *sc = ri->ri_hw;
600 
601 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
602 	sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
603 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
604 	sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
605 }
606 
607 void
608 ifb_copycols(void *cookie, int row, int src, int dst, int num)
609 {
610 	struct rasops_info *ri = cookie;
611 	struct ifb_softc *sc = ri->ri_hw;
612 
613 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
614 	sc->sc_old_ops.copycols(cookie, row, src, dst, num);
615 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
616 	sc->sc_old_ops.copycols(cookie, row, src, dst, num);
617 }
618 
619 void
620 ifb_erasecols(void *cookie, int row, int col, int num, long attr)
621 {
622 	struct rasops_info *ri = cookie;
623 	struct ifb_softc *sc = ri->ri_hw;
624 
625 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
626 	sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
627 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
628 	sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
629 }
630 
631 void
632 ifb_copyrows(void *cookie, int src, int dst, int num)
633 {
634 	struct rasops_info *ri = cookie;
635 	struct ifb_softc *sc = ri->ri_hw;
636 
637 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
638 	sc->sc_old_ops.copyrows(cookie, src, dst, num);
639 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
640 	sc->sc_old_ops.copyrows(cookie, src, dst, num);
641 }
642 
643 void
644 ifb_eraserows(void *cookie, int row, int num, long attr)
645 {
646 	struct rasops_info *ri = cookie;
647 	struct ifb_softc *sc = ri->ri_hw;
648 
649 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
650 	sc->sc_old_ops.eraserows(cookie, row, num, attr);
651 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
652 	sc->sc_old_ops.eraserows(cookie, row, num, attr);
653 }
654 
655 void
656 ifb_do_cursor(struct rasops_info *ri)
657 {
658 	struct ifb_softc *sc = ri->ri_hw;
659 
660 	ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
661 	sc->sc_old_cursor(ri);
662 	ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
663 	sc->sc_old_cursor(ri);
664 }
665