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