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