1 /* $OpenBSD: smfb.c,v 1.20 2021/01/02 14:29:16 visa 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->cmsize = 0; 286 break; 287 case WSDISPLAYIO_LINEBYTES: 288 *(uint *)data = ri->ri_stride; 289 break; 290 default: 291 return -1; 292 } 293 294 return 0; 295 } 296 297 int 298 smfb_show_screen(void *v, void *cookie, int waitok, 299 void (*cb)(void *, int, int), void *cbarg) 300 { 301 return 0; 302 } 303 304 paddr_t 305 smfb_mmap(void *v, off_t offset, int prot) 306 { 307 struct smfb_softc *sc = (struct smfb_softc *)v; 308 struct rasops_info *ri = &sc->sc_fb->ri; 309 310 if ((offset & PAGE_MASK) != 0) 311 return -1; 312 313 if (offset < 0 || offset >= ri->ri_stride * ri->ri_height) 314 return -1; 315 316 return XKPHYS_TO_PHYS((paddr_t)ri->ri_bits) + offset; 317 } 318 319 int 320 smfb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font) 321 { 322 struct smfb_softc *sc = (struct smfb_softc *)v; 323 struct rasops_info *ri = &sc->sc_fb->ri; 324 325 return rasops_load_font(ri, emulcookie, font); 326 } 327 328 int 329 smfb_list_font(void *v, struct wsdisplay_font *font) 330 { 331 struct smfb_softc *sc = (struct smfb_softc *)v; 332 struct rasops_info *ri = &sc->sc_fb->ri; 333 334 return rasops_list_font(ri, font); 335 } 336 337 void 338 smfb_burner(void *v, uint on, uint flg) 339 { 340 struct smfb_softc *sc = (struct smfb_softc *)v; 341 struct smfb *fb = sc->sc_fb; 342 343 if (fb->is5xx) { 344 if (on) { 345 /* 346 * Wait for a few cycles after restoring power, 347 * to prevent white flickering. 348 */ 349 DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL, 350 DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) | PDC_VDD); 351 smfb_wait_panel_vsync(fb, 4); 352 DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL, 353 DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) | PDC_DATA); 354 smfb_wait_panel_vsync(fb, 4); 355 DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL, 356 DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) | 357 (PDC_BIAS | PDC_EN)); 358 } else 359 DCR_WRITE(fb, DCR_PANEL_DISPLAY_CONTROL, 360 DCR_READ(fb, DCR_PANEL_DISPLAY_CONTROL) & 361 ~(PDC_EN | PDC_BIAS | PDC_DATA | PDC_VDD)); 362 } else { 363 if (on) { 364 smfb_vgats_write(fb, 0x31, 365 smfb_vgats_read(fb, 0x31) | 0x01); 366 } else { 367 smfb_vgats_write(fb, 0x21, 368 smfb_vgats_read(fb, 0x21) | 0x30); 369 smfb_vgats_write(fb, 0x31, 370 smfb_vgats_read(fb, 0x31) & ~0x01); 371 } 372 } 373 } 374 375 /* 376 * Frame buffer initialization. 377 */ 378 379 int 380 smfb_setup(struct smfb *fb, bus_space_tag_t memt, bus_space_handle_t memh, 381 bus_space_tag_t mmiot, bus_space_handle_t mmioh) 382 { 383 struct rasops_info *ri; 384 int accel = 0; 385 int rc; 386 387 ri = &fb->ri; 388 switch (sys_platform->system_type) { 389 case LOONGSON_EBT700: 390 ri->ri_width = 800; 391 ri->ri_height = 480; 392 break; 393 case LOONGSON_LYNLOONG: 394 ri->ri_width = 1368; 395 ri->ri_height = 768; 396 break; 397 default: 398 case LOONGSON_GDIUM: 399 case LOONGSON_YEELOONG: 400 ri->ri_width = 1024; 401 ri->ri_height = 600; 402 break; 403 } 404 ri->ri_depth = 16; 405 ri->ri_stride = (ri->ri_width * ri->ri_depth) / 8; 406 ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR; 407 ri->ri_bits = (void *)bus_space_vaddr(memt, memh); 408 ri->ri_hw = fb; 409 410 #ifdef __MIPSEL__ 411 /* swap B and R */ 412 ri->ri_rnum = 5; 413 ri->ri_rpos = 11; 414 ri->ri_gnum = 6; 415 ri->ri_gpos = 5; 416 ri->ri_bnum = 5; 417 ri->ri_bpos = 0; 418 #endif 419 420 rasops_init(ri, 160, 160); 421 422 strlcpy(fb->wsd.name, "std", sizeof(fb->wsd.name)); 423 fb->wsd.ncols = ri->ri_cols; 424 fb->wsd.nrows = ri->ri_rows; 425 fb->wsd.textops = &ri->ri_ops; 426 fb->wsd.fontwidth = ri->ri_font->fontwidth; 427 fb->wsd.fontheight = ri->ri_font->fontheight; 428 fb->wsd.capabilities = ri->ri_caps; 429 430 if (fb->is5xx) { 431 fb->dcrt = mmiot; 432 if ((rc = bus_space_subregion(mmiot, mmioh, SM5XX_DCR_BASE, 433 SM5XX_DCR_SIZE, &fb->dcrh)) != 0) 434 return rc; 435 fb->dprt = mmiot; 436 if ((rc = bus_space_subregion(mmiot, mmioh, SM5XX_DPR_BASE, 437 SMXXX_DPR_SIZE, &fb->dprh)) != 0) 438 return rc; 439 fb->mmiot = mmiot; 440 if ((rc = bus_space_subregion(mmiot, mmioh, SM5XX_MMIO_BASE, 441 SM5XX_MMIO_SIZE, &fb->mmioh)) != 0) 442 return rc; 443 accel = 1; 444 } else { 445 fb->dprt = memt; 446 if ((rc = bus_space_subregion(memt, memh, SM7XX_DPR_BASE, 447 SMXXX_DPR_SIZE, &fb->dprh)) != 0) 448 return rc; 449 fb->mmiot = memt; 450 if ((rc = bus_space_subregion(memt, memh, SM7XX_MMIO_BASE, 451 SM7XX_MMIO_SIZE, &fb->mmioh)) != 0) 452 return rc; 453 accel = 1; 454 } 455 456 /* 457 * Setup 2D acceleration whenever possible 458 */ 459 460 if (accel) { 461 if (smfb_wait(fb) != 0) 462 accel = 0; 463 } 464 if (accel) { 465 DPR_WRITE(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); 466 /* use of width both times is intentional */ 467 DPR_WRITE(fb, DPR_PITCH, 468 DPR_COORDS(ri->ri_width, ri->ri_width)); 469 DPR_WRITE(fb, DPR_SRC_WINDOW, 470 DPR_COORDS(ri->ri_width, ri->ri_width)); 471 DPR_WRITE(fb, DPR_BYTE_BIT_MASK, 0xffffffff); 472 DPR_WRITE(fb, DPR_COLOR_COMPARE_MASK, 0); 473 DPR_WRITE(fb, DPR_COLOR_COMPARE, 0); 474 DPR_WRITE(fb, DPR_SRC_BASE, 0); 475 DPR_WRITE(fb, DPR_DST_BASE, 0); 476 DPR_READ(fb, DPR_DST_BASE); 477 478 ri->ri_ops.copycols = smfb_copycols; 479 ri->ri_ops.copyrows = smfb_copyrows; 480 ri->ri_ops.erasecols = smfb_erasecols; 481 ri->ri_ops.eraserows = smfb_eraserows; 482 } 483 484 return 0; 485 } 486 487 void 488 smfb_copyrect(struct smfb *fb, int sx, int sy, int dx, int dy, int w, int h) 489 { 490 uint32_t dir; 491 492 /* Compute rop direction */ 493 if (sy < dy || (sy == dy && sx <= dx)) { 494 sx += w - 1; 495 dx += w - 1; 496 sy += h - 1; 497 dy += h - 1; 498 dir = DE_CTRL_RTOL; 499 } else 500 dir = 0; 501 502 DPR_WRITE(fb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); 503 DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); 504 DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h)); 505 DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | dir | 506 (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | 507 (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); 508 DPR_READ(fb, DPR_DE_CTRL); 509 510 smfb_wait(fb); 511 } 512 513 void 514 smfb_fillrect(struct smfb *fb, int x, int y, int w, int h, int bg) 515 { 516 struct rasops_info *ri; 517 518 ri = &fb->ri; 519 520 DPR_WRITE(fb, DPR_FG_COLOR, ri->ri_devcmap[bg]); 521 DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(x, y)); 522 DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h)); 523 DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | 524 (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | 525 (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); 526 DPR_READ(fb, DPR_DE_CTRL); 527 528 smfb_wait(fb); 529 } 530 531 int 532 smfb_copyrows(void *cookie, int src, int dst, int num) 533 { 534 struct rasops_info *ri = cookie; 535 struct smfb *fb = ri->ri_hw; 536 struct wsdisplay_font *f = ri->ri_font; 537 538 num *= f->fontheight; 539 src *= f->fontheight; 540 dst *= f->fontheight; 541 542 smfb_copyrect(fb, ri->ri_xorigin, ri->ri_yorigin + src, 543 ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num); 544 545 return 0; 546 } 547 548 int 549 smfb_copycols(void *cookie, int row, int src, int dst, int num) 550 { 551 struct rasops_info *ri = cookie; 552 struct smfb *fb = ri->ri_hw; 553 struct wsdisplay_font *f = ri->ri_font; 554 555 num *= f->fontwidth; 556 src *= f->fontwidth; 557 dst *= f->fontwidth; 558 row *= f->fontheight; 559 560 smfb_copyrect(fb, ri->ri_xorigin + src, ri->ri_yorigin + row, 561 ri->ri_xorigin + dst, ri->ri_yorigin + row, num, f->fontheight); 562 563 return 0; 564 } 565 566 int 567 smfb_erasecols(void *cookie, int row, int col, int num, uint32_t attr) 568 { 569 struct rasops_info *ri = cookie; 570 struct smfb *fb = ri->ri_hw; 571 struct wsdisplay_font *f = ri->ri_font; 572 int bg, fg; 573 574 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 575 576 row *= f->fontheight; 577 col *= f->fontwidth; 578 num *= f->fontwidth; 579 580 smfb_fillrect(fb, ri->ri_xorigin + col, ri->ri_yorigin + row, 581 num, f->fontheight, bg); 582 583 return 0; 584 } 585 586 int 587 smfb_eraserows(void *cookie, int row, int num, uint32_t attr) 588 { 589 struct rasops_info *ri = cookie; 590 struct smfb *fb = ri->ri_hw; 591 struct wsdisplay_font *f = ri->ri_font; 592 int bg, fg; 593 int x, y, w; 594 595 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 596 597 if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) { 598 num = ri->ri_height; 599 x = y = 0; 600 w = ri->ri_width; 601 } else { 602 num *= f->fontheight; 603 x = ri->ri_xorigin; 604 y = ri->ri_yorigin + row * f->fontheight; 605 w = ri->ri_emuwidth; 606 } 607 smfb_fillrect(fb, x, y, w, num, bg); 608 609 return 0; 610 } 611 612 int 613 smfb_wait(struct smfb *fb) 614 { 615 uint32_t reg; 616 int i; 617 618 i = 10000; 619 while (i-- != 0) { 620 if (fb->is5xx) { 621 reg = bus_space_read_4(fb->mmiot, fb->mmioh, 622 VOYAGER_SYSTEM_CONTROL); 623 if ((reg & (VSC_FIFO_EMPTY | VSC_2DENGINE_BUSY)) == 624 VSC_FIFO_EMPTY) 625 return 0; 626 } else { 627 reg = smfb_vgats_read(fb, 0x16); 628 if ((reg & 0x18) == 0x10) 629 return 0; 630 } 631 delay(1); 632 } 633 634 return EBUSY; 635 } 636 637 /* 638 * wait for a few panel vertical retrace cycles (5xx only) 639 */ 640 void 641 smfb_wait_panel_vsync(struct smfb *fb, int ncycles) 642 { 643 while (ncycles-- != 0) { 644 /* wait for end of retrace-in-progress */ 645 while (ISSET(bus_space_read_4(fb->mmiot, fb->mmioh, 646 VOYAGER_COMMANDLIST_STATUS), VCS_SP)) 647 delay(10); 648 /* wait for start of retrace */ 649 while (!ISSET(bus_space_read_4(fb->mmiot, fb->mmioh, 650 VOYAGER_COMMANDLIST_STATUS), VCS_SP)) 651 delay(10); 652 } 653 } 654 655 /* 656 * vga sequencer access through mmio space (non-5xx only) 657 */ 658 659 uint8_t 660 smfb_vgats_read(struct smfb *fb, uint regno) 661 { 662 bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno); 663 return bus_space_read_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA); 664 } 665 666 void 667 smfb_vgats_write(struct smfb *fb, uint regno, uint8_t value) 668 { 669 bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno); 670 bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA, value); 671 } 672 673 /* 674 * Early console code 675 */ 676 677 int smfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t); 678 679 int 680 smfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, pcitag_t tag, 681 pcireg_t id) 682 { 683 uint32_t defattr; 684 struct rasops_info *ri; 685 bus_space_handle_t fbh, mmioh; 686 pcireg_t bar; 687 int rc, is5xx; 688 689 /* filter out unrecognized devices */ 690 switch (id) { 691 default: 692 return ENODEV; 693 case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712): 694 is5xx = 0; 695 break; 696 case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM501): 697 is5xx = 1; 698 break; 699 } 700 701 smfbcn.is5xx = is5xx; 702 703 bar = pci_conf_read_early(tag, PCI_MAPREG_START); 704 if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM) 705 return EINVAL; 706 rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */, 707 BUS_SPACE_MAP_LINEAR, &fbh); 708 if (rc != 0) 709 return rc; 710 711 if (smfbcn.is5xx) { 712 bar = pci_conf_read_early(tag, PCI_MAPREG_START + 0x04); 713 if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM) 714 return EINVAL; 715 rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */, 716 BUS_SPACE_MAP_LINEAR, &mmioh); 717 if (rc != 0) 718 return rc; 719 } else { 720 mmioh = fbh; 721 } 722 723 rc = smfb_setup(&smfbcn, memt, fbh, memt, mmioh); 724 if (rc != 0) 725 return rc; 726 727 ri = &smfbcn.ri; 728 ri->ri_ops.pack_attr(ri, 0, 0, 0, &defattr); 729 wsdisplay_cnattach(&smfbcn.wsd, ri, 0, 0, defattr); 730 731 return 0; 732 } 733 734 int 735 smfb_activate(struct device *self, int act) 736 { 737 struct smfb_softc *sc = (struct smfb_softc *)self; 738 739 switch (act) { 740 case DVACT_SUSPEND: 741 smfb_burner(sc, 0, 0); 742 break; 743 case DVACT_RESUME: 744 smfb_burner(sc, 1, 0); 745 break; 746 } 747 748 return 0; 749 } 750