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