xref: /openbsd/sys/arch/loongson/dev/smfb.c (revision 5af055cd)
1 /*	$OpenBSD: smfb.c,v 1.16 2013/10/21 10:36:14 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2009, 2010 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  * SiliconMotion SM502 and SM712 frame buffer driver.
21  *
22  * Assumes its video output is an LCD panel, in 5:6:5 mode, and fixed
23  * 1024x600 or 800x480 resolution, depending on the system model.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/device.h>
29 
30 #include <machine/autoconf.h>
31 #include <machine/bus.h>
32 #include <machine/cpu.h>
33 
34 #include <uvm/uvm_extern.h>
35 
36 #include <dev/ic/vgareg.h>
37 #include <dev/isa/isareg.h>
38 #include <dev/pci/pcireg.h>
39 #include <dev/pci/pcivar.h>
40 #include <dev/pci/pcidevs.h>
41 
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/rasops/rasops.h>
45 
46 #include <loongson/dev/voyagerreg.h>
47 #include <loongson/dev/voyagervar.h>
48 #include <loongson/dev/smfbreg.h>
49 
50 struct smfb_softc;
51 
52 /* minimal frame buffer information, suitable for early console */
53 struct smfb {
54 	struct smfb_softc	*sc;
55 	struct rasops_info	ri;
56 	int			is5xx;
57 
58 	/* DPR registers */
59 	bus_space_tag_t		dprt;
60 	bus_space_handle_t	dprh;
61 	/* MMIO space (SM7xx) or control registers (SM5xx) */
62 	bus_space_tag_t		mmiot;
63 	bus_space_handle_t	mmioh;
64 	/* DCR registers (SM5xx) */
65 	bus_space_tag_t		dcrt;
66 	bus_space_handle_t	dcrh;
67 
68 	struct wsscreen_descr	wsd;
69 };
70 
71 #define	DCR_READ(fb, reg) \
72 	bus_space_read_4((fb)->dcrt, (fb)->dcrh, (reg))
73 #define	DCR_WRITE(fb, reg, val) \
74 	bus_space_write_4((fb)->dcrt, (fb)->dcrh, (reg), (val))
75 #define	DPR_READ(fb, reg) \
76 	bus_space_read_4((fb)->dprt, (fb)->dprh, (reg))
77 #define	DPR_WRITE(fb, reg, val) \
78 	bus_space_write_4((fb)->dprt, (fb)->dprh, (reg), (val))
79 
80 struct smfb_softc {
81 	struct device		 sc_dev;
82 	struct smfb		*sc_fb;
83 	struct smfb		 sc_fb_store;
84 
85 	struct wsscreen_list	 sc_wsl;
86 	struct wsscreen_descr	*sc_scrlist[1];
87 	int			 sc_nscr;
88 };
89 
90 int	smfb_pci_match(struct device *, void *, void *);
91 void	smfb_pci_attach(struct device *, struct device *, void *);
92 int	smfb_voyager_match(struct device *, void *, void *);
93 void	smfb_voyager_attach(struct device *, struct device *, void *);
94 int	smfb_activate(struct device *, int);
95 
96 const struct cfattach smfb_pci_ca = {
97 	sizeof(struct smfb_softc), smfb_pci_match, smfb_pci_attach,
98 	NULL, smfb_activate
99 };
100 
101 const struct cfattach smfb_voyager_ca = {
102 	sizeof(struct smfb_softc), smfb_voyager_match, smfb_voyager_attach,
103 	smfb_activate
104 };
105 
106 struct cfdriver smfb_cd = {
107 	NULL, "smfb", DV_DULL
108 };
109 
110 int	smfb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
111 	    int *, long *);
112 void	smfb_burner(void *, uint, uint);
113 void	smfb_free_screen(void *, void *);
114 int	smfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
115 int	smfb_list_font(void *, struct wsdisplay_font *);
116 int	smfb_load_font(void *, void *, struct wsdisplay_font *);
117 paddr_t	smfb_mmap(void *, off_t, int);
118 int	smfb_show_screen(void *, void *, int, void (*)(void *, int, int),
119 	    void *);
120 
121 struct wsdisplay_accessops smfb_accessops = {
122 	.ioctl = smfb_ioctl,
123 	.mmap = smfb_mmap,
124 	.alloc_screen = smfb_alloc_screen,
125 	.free_screen = smfb_free_screen,
126 	.show_screen = smfb_show_screen,
127 	.load_font = smfb_load_font,
128 	.list_font = smfb_list_font,
129 	.burn_screen = smfb_burner
130 };
131 
132 int	smfb_setup(struct smfb *, bus_space_tag_t, bus_space_handle_t,
133 	    bus_space_tag_t, bus_space_handle_t);
134 
135 void	smfb_copyrect(struct smfb *, int, int, int, int, int, int);
136 void	smfb_fillrect(struct smfb *, int, int, int, int, int);
137 int	smfb_copyrows(void *, int, int, int);
138 int	smfb_copycols(void *, int, int, int, int);
139 int	smfb_do_cursor(struct rasops_info *);
140 int	smfb_erasecols(void *, int, int, int, long);
141 int	smfb_eraserows(void *, int, int, long);
142 int	smfb_wait(struct smfb *);
143 
144 void	smfb_wait_panel_vsync(struct smfb *, int);
145 uint8_t	smfb_vgats_read(struct smfb *, uint);
146 void	smfb_vgats_write(struct smfb *, uint, uint8_t);
147 
148 void	smfb_attach_common(struct smfb_softc *, int, bus_space_tag_t,
149 	    bus_space_handle_t, bus_space_tag_t, bus_space_handle_t);
150 
151 static struct smfb smfbcn;
152 
153 const struct pci_matchid smfb_devices[] = {
154 	{ PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712 }
155 };
156 
157 int
158 smfb_pci_match(struct device *parent, void *vcf, void *aux)
159 {
160 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
161 
162 	return pci_matchbyid(pa, smfb_devices, nitems(smfb_devices));
163 }
164 
165 int
166 smfb_voyager_match(struct device *parent, void *vcf, void *aux)
167 {
168 	struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
169 	struct cfdata *cf = (struct cfdata *)vcf;
170 
171 	return strcmp(vaa->vaa_name, cf->cf_driver->cd_name) == 0;
172 }
173 
174 void
175 smfb_pci_attach(struct device *parent, struct device *self, void *aux)
176 {
177 	struct smfb_softc *sc = (struct smfb_softc *)self;
178 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
179 	bus_space_tag_t memt;
180 	bus_space_handle_t memh;
181 
182 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM,
183 	    BUS_SPACE_MAP_LINEAR, &memt, &memh, NULL, NULL, 0) != 0) {
184 		printf(": can't map frame buffer\n");
185 		return;
186 	}
187 
188 	smfb_attach_common(sc, 0, memt, memh, memt, memh);
189 }
190 
191 void
192 smfb_voyager_attach(struct device *parent, struct device *self, void *aux)
193 {
194 	struct smfb_softc *sc = (struct smfb_softc *)self;
195 	struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
196 
197 	smfb_attach_common(sc, 1, vaa->vaa_fbt, vaa->vaa_fbh, vaa->vaa_mmiot,
198 	    vaa->vaa_mmioh);
199 }
200 
201 void
202 smfb_attach_common(struct smfb_softc *sc, int is5xx, bus_space_tag_t memt,
203     bus_space_handle_t memh, bus_space_tag_t mmiot, bus_space_handle_t mmioh)
204 {
205 	struct wsemuldisplaydev_attach_args waa;
206 	int console;
207 
208 	console = smfbcn.ri.ri_hw != NULL;
209 
210 	if (console) {
211 		sc->sc_fb = &smfbcn;
212 		sc->sc_fb->sc = sc;
213 	} else {
214 		sc->sc_fb = &sc->sc_fb_store;
215 		sc->sc_fb->is5xx = is5xx;
216 		if (smfb_setup(sc->sc_fb, memt, memh, mmiot, mmioh) != 0) {
217 			printf(": can't setup frame buffer\n");
218 			return;
219 		}
220 	}
221 
222 	/* XXX print resolution */
223 	printf("\n");
224 
225 	sc->sc_scrlist[0] = &sc->sc_fb->wsd;
226 	sc->sc_wsl.nscreens = 1;
227 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
228 
229 	waa.console = console;
230 	waa.scrdata = &sc->sc_wsl;
231 	waa.accessops = &smfb_accessops;
232 	waa.accesscookie = sc;
233 	waa.defaultscreens = 0;
234 
235 	config_found((struct device *)sc, &waa, wsemuldisplaydevprint);
236 }
237 
238 /*
239  * wsdisplay accesops
240  */
241 
242 int
243 smfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
244     int *curxp, int *curyp, long *attrp)
245 {
246 	struct smfb_softc *sc = (struct smfb_softc *)v;
247 	struct rasops_info *ri = &sc->sc_fb->ri;
248 
249 	if (sc->sc_nscr > 0)
250 		return ENOMEM;
251 
252 	*cookiep = ri;
253 	*curxp = *curyp = 0;
254 	ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
255 	sc->sc_nscr++;
256 
257 	return 0;
258 }
259 
260 void
261 smfb_free_screen(void *v, void *cookie)
262 {
263 	struct smfb_softc *sc = (struct smfb_softc *)v;
264 
265 	sc->sc_nscr--;
266 }
267 
268 int
269 smfb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
270 {
271 	struct smfb_softc *sc = (struct smfb_softc *)v;
272 	struct rasops_info *ri = &sc->sc_fb->ri;
273 	struct wsdisplay_fbinfo *wdf;
274 
275 	switch (cmd) {
276 	case WSDISPLAYIO_GTYPE:
277 		*(uint *)data = WSDISPLAY_TYPE_SMFB;
278 		break;
279 	case WSDISPLAYIO_GINFO:
280 		wdf = (struct wsdisplay_fbinfo *)data;
281 		wdf->width = ri->ri_width;
282 		wdf->height = ri->ri_height;
283 		wdf->depth = ri->ri_depth;
284 		wdf->cmsize = 0;
285 		break;
286 	case WSDISPLAYIO_LINEBYTES:
287 		*(uint *)data = ri->ri_stride;
288 		break;
289 	default:
290 		return -1;
291 	}
292 
293 	return 0;
294 }
295 
296 int
297 smfb_show_screen(void *v, void *cookie, int waitok,
298     void (*cb)(void *, int, int), void *cbarg)
299 {
300 	return 0;
301 }
302 
303 paddr_t
304 smfb_mmap(void *v, off_t offset, int prot)
305 {
306 	struct smfb_softc *sc = (struct smfb_softc *)v;
307 	struct rasops_info *ri = &sc->sc_fb->ri;
308 
309 	if ((offset & PAGE_MASK) != 0)
310 		return -1;
311 
312 	if (offset < 0 || offset >= ri->ri_stride * ri->ri_height)
313 		return -1;
314 
315 	return XKPHYS_TO_PHYS((paddr_t)ri->ri_bits) + offset;
316 }
317 
318 int
319 smfb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
320 {
321 	struct smfb_softc *sc = (struct smfb_softc *)v;
322 	struct rasops_info *ri = &sc->sc_fb->ri;
323 
324 	return rasops_load_font(ri, emulcookie, font);
325 }
326 
327 int
328 smfb_list_font(void *v, struct wsdisplay_font *font)
329 {
330 	struct smfb_softc *sc = (struct smfb_softc *)v;
331 	struct rasops_info *ri = &sc->sc_fb->ri;
332 
333 	return rasops_list_font(ri, font);
334 }
335 
336 void
337 smfb_burner(void *v, uint on, uint flg)
338 {
339 	struct smfb_softc *sc = (struct smfb_softc *)v;
340 	struct smfb *fb = sc->sc_fb;
341 
342 	if (fb->is5xx) {
343 		if (on) {
344 			/*
345 			 * Wait for a few cycles after restoring power,
346 			 * to prevent white flickering.
347 			 */
348 			DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL,
349 			    DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) | PDC_VDD);
350 			smfb_wait_panel_vsync(fb, 4);
351 			DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL,
352 			    DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) | PDC_DATA);
353 			smfb_wait_panel_vsync(fb, 4);
354 			DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL,
355 			    DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) |
356 			    (PDC_BIAS | PDC_EN));
357 		} else
358 			DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL,
359 			    DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) &
360 			    ~(PDC_EN | PDC_BIAS | PDC_DATA | PDC_VDD));
361 	} else {
362 		if (on) {
363 			smfb_vgats_write(fb, 0x31,
364 			    smfb_vgats_read(fb, 0x31) | 0x01);
365 		} else {
366 			smfb_vgats_write(fb, 0x21,
367 			    smfb_vgats_read(fb, 0x21) | 0x30);
368 			smfb_vgats_write(fb, 0x31,
369 			    smfb_vgats_read(fb, 0x31) & ~0x01);
370 		}
371 	}
372 }
373 
374 /*
375  * Frame buffer initialization.
376  */
377 
378 int
379 smfb_setup(struct smfb *fb, bus_space_tag_t memt, bus_space_handle_t memh,
380     bus_space_tag_t mmiot, bus_space_handle_t mmioh)
381 {
382 	struct rasops_info *ri;
383 	int accel = 0;
384 	int rc;
385 
386 	ri = &fb->ri;
387 	switch (sys_platform->system_type) {
388 	case LOONGSON_EBT700:
389 		ri->ri_width = 800;
390 		ri->ri_height = 480;
391 		break;
392 	default:
393 	case LOONGSON_GDIUM:
394 	case LOONGSON_LYNLOONG:
395 	case LOONGSON_YEELOONG:
396 		ri->ri_width = 1024;
397 		ri->ri_height = 600;
398 		break;
399 	}
400 	ri->ri_depth = 16;
401 	ri->ri_stride = (ri->ri_width * ri->ri_depth) / 8;
402 	ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR;
403 	ri->ri_bits = (void *)bus_space_vaddr(memt, memh);
404 	ri->ri_hw = fb;
405 
406 #ifdef __MIPSEL__
407 	/* swap B and R */
408 	ri->ri_rnum = 5;
409 	ri->ri_rpos = 11;
410 	ri->ri_gnum = 6;
411 	ri->ri_gpos = 5;
412 	ri->ri_bnum = 5;
413 	ri->ri_bpos = 0;
414 #endif
415 
416 	rasops_init(ri, 160, 160);
417 
418 	strlcpy(fb->wsd.name, "std", sizeof(fb->wsd.name));
419 	fb->wsd.ncols = ri->ri_cols;
420 	fb->wsd.nrows = ri->ri_rows;
421 	fb->wsd.textops = &ri->ri_ops;
422 	fb->wsd.fontwidth = ri->ri_font->fontwidth;
423 	fb->wsd.fontheight = ri->ri_font->fontheight;
424 	fb->wsd.capabilities = ri->ri_caps;
425 
426 	if (fb->is5xx) {
427 		fb->dcrt = mmiot;
428 		if ((rc = bus_space_subregion(mmiot, mmioh, SM5XX_DCR_BASE,
429 		    SM5XX_DCR_SIZE, &fb->dcrh)) != 0)
430 			return rc;
431 		fb->dprt = mmiot;
432 		if ((rc = bus_space_subregion(mmiot, mmioh, SM5XX_DPR_BASE,
433 		    SMXXX_DPR_SIZE, &fb->dprh)) != 0)
434 			return rc;
435 		fb->mmiot = mmiot;
436 		if ((rc = bus_space_subregion(mmiot, mmioh, SM5XX_MMIO_BASE,
437 		    SM5XX_MMIO_SIZE, &fb->mmioh)) != 0)
438 			return rc;
439 		accel = 1;
440 	} else {
441 		fb->dprt = memt;
442 		if ((rc = bus_space_subregion(memt, memh, SM7XX_DPR_BASE,
443 		    SMXXX_DPR_SIZE, &fb->dprh)) != 0)
444 			return rc;
445 		fb->mmiot = memt;
446 		if ((rc = bus_space_subregion(memt, memh, SM7XX_MMIO_BASE,
447 		    SM7XX_MMIO_SIZE, &fb->mmioh)) != 0)
448 			return rc;
449 		accel = 1;
450 	}
451 
452 	/*
453 	 * Setup 2D acceleration whenever possible
454 	 */
455 
456 	if (accel) {
457 		if (smfb_wait(fb) != 0)
458 			accel = 0;
459 	}
460 	if (accel) {
461 		DPR_WRITE(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0));
462 		/* use of width both times is intentional */
463 		DPR_WRITE(fb, DPR_PITCH,
464 		    DPR_COORDS(ri->ri_width, ri->ri_width));
465 		DPR_WRITE(fb, DPR_SRC_WINDOW,
466 		    DPR_COORDS(ri->ri_width, ri->ri_width));
467 		DPR_WRITE(fb, DPR_BYTE_BIT_MASK, 0xffffffff);
468 		DPR_WRITE(fb, DPR_COLOR_COMPARE_MASK, 0);
469 		DPR_WRITE(fb, DPR_COLOR_COMPARE, 0);
470 		DPR_WRITE(fb, DPR_SRC_BASE, 0);
471 		DPR_WRITE(fb, DPR_DST_BASE, 0);
472 		DPR_READ(fb, DPR_DST_BASE);
473 
474 		ri->ri_ops.copycols = smfb_copycols;
475 		ri->ri_ops.copyrows = smfb_copyrows;
476 		ri->ri_ops.erasecols = smfb_erasecols;
477 		ri->ri_ops.eraserows = smfb_eraserows;
478 	}
479 
480 	return 0;
481 }
482 
483 void
484 smfb_copyrect(struct smfb *fb, int sx, int sy, int dx, int dy, int w, int h)
485 {
486 	uint32_t dir;
487 
488 	/* Compute rop direction */
489 	if (sy < dy || (sy == dy && sx <= dx)) {
490 		sx += w - 1;
491 		dx += w - 1;
492 		sy += h - 1;
493 		dy += h - 1;
494 		dir = DE_CTRL_RTOL;
495 	} else
496 		dir = 0;
497 
498 	DPR_WRITE(fb, DPR_SRC_COORDS, DPR_COORDS(sx, sy));
499 	DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(dx, dy));
500 	DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h));
501 	DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | dir |
502 	    (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) |
503 	    (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
504 	DPR_READ(fb, DPR_DE_CTRL);
505 
506 	smfb_wait(fb);
507 }
508 
509 void
510 smfb_fillrect(struct smfb *fb, int x, int y, int w, int h, int bg)
511 {
512 	struct rasops_info *ri;
513 
514 	ri = &fb->ri;
515 
516 	DPR_WRITE(fb, DPR_FG_COLOR, ri->ri_devcmap[bg]);
517 	DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(x, y));
518 	DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h));
519 	DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE |
520 	    (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) |
521 	    (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
522 	DPR_READ(fb, DPR_DE_CTRL);
523 
524 	smfb_wait(fb);
525 }
526 
527 int
528 smfb_copyrows(void *cookie, int src, int dst, int num)
529 {
530 	struct rasops_info *ri = cookie;
531 	struct smfb *fb = ri->ri_hw;
532 	struct wsdisplay_font *f = ri->ri_font;
533 
534 	num *= f->fontheight;
535 	src *= f->fontheight;
536 	dst *= f->fontheight;
537 
538 	smfb_copyrect(fb, ri->ri_xorigin, ri->ri_yorigin + src,
539 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
540 
541 	return 0;
542 }
543 
544 int
545 smfb_copycols(void *cookie, int row, int src, int dst, int num)
546 {
547 	struct rasops_info *ri = cookie;
548 	struct smfb *fb = ri->ri_hw;
549 	struct wsdisplay_font *f = ri->ri_font;
550 
551 	num *= f->fontwidth;
552 	src *= f->fontwidth;
553 	dst *= f->fontwidth;
554 	row *= f->fontheight;
555 
556 	smfb_copyrect(fb, ri->ri_xorigin + src, ri->ri_yorigin + row,
557 	    ri->ri_xorigin + dst, ri->ri_yorigin + row, num, f->fontheight);
558 
559 	return 0;
560 }
561 
562 int
563 smfb_erasecols(void *cookie, int row, int col, int num, long attr)
564 {
565 	struct rasops_info *ri = cookie;
566 	struct smfb *fb = ri->ri_hw;
567 	struct wsdisplay_font *f = ri->ri_font;
568 	int bg, fg;
569 
570 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
571 
572 	row *= f->fontheight;
573 	col *= f->fontwidth;
574 	num *= f->fontwidth;
575 
576 	smfb_fillrect(fb, ri->ri_xorigin + col, ri->ri_yorigin + row,
577 	    num, f->fontheight, bg);
578 
579 	return 0;
580 }
581 
582 int
583 smfb_eraserows(void *cookie, int row, int num, long attr)
584 {
585 	struct rasops_info *ri = cookie;
586 	struct smfb *fb = ri->ri_hw;
587 	struct wsdisplay_font *f = ri->ri_font;
588 	int bg, fg;
589 	int x, y, w;
590 
591 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
592 
593 	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
594 		num = ri->ri_height;
595 		x = y = 0;
596 		w = ri->ri_width;
597 	} else {
598 		num *= f->fontheight;
599 		x = ri->ri_xorigin;
600 		y = ri->ri_yorigin + row * f->fontheight;
601 		w = ri->ri_emuwidth;
602 	}
603 	smfb_fillrect(fb, x, y, w, num, bg);
604 
605 	return 0;
606 }
607 
608 int
609 smfb_wait(struct smfb *fb)
610 {
611 	uint32_t reg;
612 	int i;
613 
614 	i = 10000;
615 	while (i-- != 0) {
616 		if (fb->is5xx) {
617 			reg = bus_space_read_4(fb->mmiot, fb->mmioh,
618 			    VOYAGER_SYSTEM_CONTROL);
619 			if ((reg & (VSC_FIFO_EMPTY | VSC_2DENGINE_BUSY)) ==
620 			    VSC_FIFO_EMPTY)
621 				return 0;
622 		} else {
623 			reg = smfb_vgats_read(fb, 0x16);
624 			if ((reg & 0x18) == 0x10)
625 				return 0;
626 		}
627 		delay(1);
628 	}
629 
630 	return EBUSY;
631 }
632 
633 /*
634  * wait for a few panel vertical retrace cycles (5xx only)
635  */
636 void
637 smfb_wait_panel_vsync(struct smfb *fb, int ncycles)
638 {
639 	while (ncycles-- != 0) {
640 		/* wait for end of retrace-in-progress */
641 		while (ISSET(bus_space_read_4(fb->mmiot, fb->mmioh,
642 		    VOYAGER_COMMANDLIST_STATUS), VCS_SP))
643 			delay(10);
644 		/* wait for start of retrace */
645 		while (!ISSET(bus_space_read_4(fb->mmiot, fb->mmioh,
646 		    VOYAGER_COMMANDLIST_STATUS), VCS_SP))
647 			delay(10);
648 	}
649 }
650 
651 /*
652  * vga sequencer access through mmio space (non-5xx only)
653  */
654 
655 uint8_t
656 smfb_vgats_read(struct smfb *fb, uint regno)
657 {
658 	bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno);
659 	return bus_space_read_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA);
660 }
661 
662 void
663 smfb_vgats_write(struct smfb *fb, uint regno, uint8_t value)
664 {
665 	bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno);
666 	bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA, value);
667 }
668 
669 /*
670  * Early console code
671  */
672 
673 int smfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
674 
675 int
676 smfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, pcitag_t tag,
677     pcireg_t id)
678 {
679 	long defattr;
680 	struct rasops_info *ri;
681 	bus_space_handle_t fbh, mmioh;
682 	pcireg_t bar;
683 	int rc, is5xx;
684 
685 	/* filter out unrecognized devices */
686 	switch (id) {
687 	default:
688 		return ENODEV;
689 	case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712):
690 		is5xx = 0;
691 		break;
692 	case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM501):
693 		is5xx = 1;
694 		break;
695 	}
696 
697 	smfbcn.is5xx = is5xx;
698 
699 	bar = pci_conf_read_early(tag, PCI_MAPREG_START);
700 	if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
701 		return EINVAL;
702 	rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
703 	    BUS_SPACE_MAP_LINEAR, &fbh);
704 	if (rc != 0)
705 		return rc;
706 
707 	if (smfbcn.is5xx) {
708 		bar = pci_conf_read_early(tag, PCI_MAPREG_START + 0x04);
709 		if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
710 			return EINVAL;
711 		rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
712 		    BUS_SPACE_MAP_LINEAR, &mmioh);
713 		if (rc != 0)
714 			return rc;
715 	} else {
716 		mmioh = fbh;
717 	}
718 
719 	rc = smfb_setup(&smfbcn, memt, fbh, memt, mmioh);
720 	if (rc != 0)
721 		return rc;
722 
723 	ri = &smfbcn.ri;
724 	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
725 	wsdisplay_cnattach(&smfbcn.wsd, ri, 0, 0, defattr);
726 
727 	return 0;
728 }
729 
730 int
731 smfb_activate(struct device *self, int act)
732 {
733 	struct smfb_softc *sc = (struct smfb_softc *)self;
734 
735 	switch (act) {
736 	case DVACT_SUSPEND:
737 		smfb_burner(sc, 0, 0);
738 		break;
739 	case DVACT_RESUME:
740 		smfb_burner(sc, 1, 0);
741 		break;
742 	}
743 
744 	return 0;
745 }
746