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