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