1 /* $OpenBSD: cfxga.c,v 1.17 2008/11/22 11:35:58 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006, Matthieu Herrb and 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 AUTHORS DISCLAIM ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 * Display driver for the Colorgraphic CompactFlash ``VoyagerVGA'' card. 21 * based upon the Epson S1D13806 graphics chip. 22 * 23 * Our goals are: 24 * - to provide a somewhat usable emulation mode for extra text display. 25 * - to let an application (such as an X server) map the controller registers 26 * in order to do its own display game. 27 * 28 * Driving this card is somewhat a challenge since: 29 * - its video memory is not directly accessible. 30 * - no operation can make use of DMA. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/device.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/conf.h> 39 40 #include <dev/pcmcia/pcmciavar.h> 41 #include <dev/pcmcia/pcmciareg.h> 42 43 #include <dev/wscons/wsconsio.h> 44 #include <dev/wscons/wsdisplayvar.h> 45 #include <dev/rasops/rasops.h> 46 47 #include <dev/pcmcia/cfxgareg.h> 48 49 /* 50 #define CFXGADEBUG 51 #define ENABLE_8BIT_MODES 52 */ 53 54 #ifdef CFXGADEBUG 55 #define DPRINTF(arg) printf arg 56 #else 57 #define DPRINTF(arg) 58 #endif 59 60 struct cfxga_screen; 61 62 #define CFXGA_MODE_640x480x16 0 63 #define CFXGA_MODE_800x600x16 1 64 #ifdef ENABLE_8BIT_MODES 65 #define CFXGA_MODE_640x480x8 2 66 #define CFXGA_MODE_800x600x8 3 67 #define CFXGA_NMODES 4 68 #else 69 #define CFXGA_NMODES 2 70 #endif 71 72 struct cfxga_softc { 73 struct device sc_dev; 74 struct pcmcia_function *sc_pf; 75 int sc_state; 76 #define CS_MAPPED 0x0001 77 #define CS_RESET 0x0002 78 79 struct pcmcia_mem_handle sc_pmemh; 80 int sc_memwin; 81 bus_addr_t sc_offset; 82 83 int sc_mode; 84 85 int sc_nscreens; 86 LIST_HEAD(, cfxga_screen) sc_scr; 87 struct cfxga_screen *sc_active; 88 89 /* wsdisplay glue */ 90 struct wsscreen_descr sc_wsd[CFXGA_NMODES]; 91 struct wsscreen_list sc_wsl; 92 struct wsscreen_descr *sc_scrlist[CFXGA_NMODES]; 93 struct wsdisplay_emulops sc_ops; 94 struct device *sc_wsdisplay; 95 }; 96 97 int cfxga_match(struct device *, void *, void *); 98 void cfxga_attach(struct device *, struct device *, void *); 99 int cfxga_detach(struct device *, int); 100 int cfxga_activate(struct device *, enum devact); 101 102 struct cfattach cfxga_ca = { 103 sizeof(struct cfxga_softc), cfxga_match, cfxga_attach, 104 cfxga_detach, cfxga_activate 105 }; 106 107 struct cfdriver cfxga_cd = { 108 NULL, "cfxga", DV_DULL 109 }; 110 111 int cfxga_alloc_screen(void *, const struct wsscreen_descr *, void **, 112 int *, int *, long *); 113 void cfxga_burner(void *, u_int, u_int); 114 void cfxga_free_screen(void *, void *); 115 int cfxga_ioctl(void *, u_long, caddr_t, int, struct proc *); 116 paddr_t cfxga_mmap(void *, off_t, int); 117 int cfxga_show_screen(void *, void *, int, void (*)(void *, int, int), 118 void *); 119 120 struct wsdisplay_accessops cfxga_accessops = { 121 cfxga_ioctl, 122 cfxga_mmap, 123 cfxga_alloc_screen, 124 cfxga_free_screen, 125 cfxga_show_screen, 126 NULL, 127 NULL, 128 NULL, 129 cfxga_burner 130 }; 131 132 /* 133 * Per-screen structure 134 */ 135 136 struct cfxga_screen { 137 LIST_ENTRY(cfxga_screen) scr_link; 138 struct cfxga_softc *scr_sc; /* parent reference */ 139 struct rasops_info scr_ri; /* raster op glue */ 140 struct wsdisplay_charcell *scr_mem; /* backing memory */ 141 }; 142 143 void cfxga_copycols(void *, int, int, int, int); 144 void cfxga_copyrows(void *, int, int, int); 145 void cfxga_do_cursor(struct rasops_info *); 146 void cfxga_erasecols(void *, int, int, int, long); 147 void cfxga_eraserows(void *, int, int, long); 148 void cfxga_putchar(void *, int, int, u_int, long); 149 150 int cfxga_install_function(struct pcmcia_function *); 151 void cfxga_remove_function(struct pcmcia_function *); 152 153 int cfxga_expand_char(struct cfxga_screen *, u_int, int, int, long); 154 int cfxga_repaint_screen(struct cfxga_screen *); 155 void cfxga_reset_video(struct cfxga_softc *); 156 void cfxga_reset_and_repaint(struct cfxga_softc *); 157 int cfxga_solid_fill(struct cfxga_screen *, int, int, int, int, int32_t); 158 int cfxga_standalone_rop(struct cfxga_screen *, u_int, 159 int, int, int, int, int, int); 160 int cfxga_synchronize(struct cfxga_softc *); 161 u_int cfxga_wait(struct cfxga_softc *, u_int, u_int); 162 163 #define cfxga_clear_screen(scr) \ 164 cfxga_solid_fill(scr, 0, 0, scr->scr_ri.ri_width, \ 165 scr->scr_ri.ri_height, scr->scr_ri.ri_devcmap[WSCOL_BLACK]) 166 167 #define cfxga_read_1(sc, addr) \ 168 bus_space_read_1((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \ 169 (sc)->sc_offset + (addr)) 170 #define cfxga_read_2(sc, addr) \ 171 bus_space_read_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \ 172 (sc)->sc_offset + (addr)) 173 #define cfxga_write_1(sc, addr, val) \ 174 bus_space_write_1((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \ 175 (sc)->sc_offset + (addr), (val)) 176 #define cfxga_write_2(sc, addr, val) \ 177 bus_space_write_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \ 178 (sc)->sc_offset + (addr), (val)) 179 180 #define cfxga_stop_memory_blt(sc) \ 181 (void)cfxga_read_2(sc, CFREG_BITBLT_DATA) 182 183 const char *cfxga_modenames[CFXGA_NMODES] = { 184 "640x480x16", 185 "800x600x16", 186 #ifdef ENABLE_8BIT_MODES 187 "640x480x8", 188 "800x600x8" 189 #endif 190 }; 191 192 /* 193 * This card is very poorly engineered, specificationwise. It does not 194 * provide any CIS information, and has no vendor/product numbers as 195 * well: as such, there is no easy way to differentiate it from any 196 * other cheapo PCMCIA card. 197 * 198 * The best we can do is probe for a chip ID. This is not perfect but better 199 * than matching blindly. Of course this requires us to play some nasty games 200 * behind the PCMCIA framework to be able to do this probe, and correctly fail 201 * if this is not the card we are looking for. 202 * 203 * In shorter words: some card designers ought to be shot, as a service 204 * to the community. 205 */ 206 207 /* 208 * Create the necessary pcmcia function structures to alleviate the lack 209 * of any CIS information on this device. 210 * Actually, we hijack the fake function created by the pcmcia framework. 211 */ 212 int 213 cfxga_install_function(struct pcmcia_function *pf) 214 { 215 struct pcmcia_config_entry *cfe; 216 217 /* Get real. */ 218 pf->pf_flags &= ~PFF_FAKE; 219 220 /* Tell the pcmcia framework where the CCR is. */ 221 pf->ccr_base = 0x800; 222 pf->ccr_mask = 0x67; 223 224 /* Create a simple cfe. */ 225 cfe = (struct pcmcia_config_entry *)malloc(sizeof *cfe, 226 M_DEVBUF, M_NOWAIT | M_ZERO); 227 if (cfe == NULL) { 228 DPRINTF(("%s: cfe allocation failed\n", __func__)); 229 return (ENOMEM); 230 } 231 232 cfe->number = 42; /* have to put some value... */ 233 cfe->flags = PCMCIA_CFE_IO16; 234 cfe->iftype = PCMCIA_IFTYPE_MEMORY; 235 236 SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 237 238 pcmcia_function_init(pf, cfe); 239 return (0); 240 } 241 242 /* 243 * Undo the changes done above. 244 * Such a function is necessary since we need a full-blown pcmcia world 245 * set up in order to do the device probe, but if we don't match the card, 246 * leaving this state will cause trouble during other probes. 247 */ 248 void 249 cfxga_remove_function(struct pcmcia_function *pf) 250 { 251 struct pcmcia_config_entry *cfe; 252 253 /* we are the first and only entry... */ 254 cfe = SIMPLEQ_FIRST(&pf->cfe_head); 255 SIMPLEQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 256 free(cfe, M_DEVBUF); 257 258 /* And we're a figment of the kernel's imagination again. */ 259 pf->pf_flags |= PFF_FAKE; 260 } 261 262 int 263 cfxga_match(struct device *parent, void *match, void *aux) 264 { 265 struct pcmcia_attach_args *pa = aux; 266 struct pcmcia_function *pf = pa->pf; 267 struct pcmcia_mem_handle h; 268 int rc; 269 int win; 270 bus_addr_t ptr; 271 u_int8_t id = 0; 272 273 if (pa->product != PCMCIA_PRODUCT_INVALID || 274 pa->manufacturer != PCMCIA_VENDOR_INVALID) 275 return (0); 276 277 /* Only a card with no CIS will have a fake function... */ 278 if ((pf->pf_flags & PFF_FAKE) == 0) 279 return (0); 280 281 if (cfxga_install_function(pf) != 0) 282 return (0); 283 284 if (pcmcia_function_enable(pf) != 0) { 285 DPRINTF(("%s: function enable failed\n")); 286 return (0); 287 } 288 289 rc = pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &h); 290 if (rc != 0) 291 goto out; 292 293 rc = pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE, 294 &h, &ptr, &win); 295 if (rc != 0) 296 goto out2; 297 298 id = (bus_space_read_1(h.memt, h.memh, ptr + CFREG_REV) & 299 CR_PRODUCT_MASK) >> CR_PRODUCT_SHIFT; 300 301 pcmcia_mem_unmap(pa->pf, win); 302 out2: 303 pcmcia_mem_free(pa->pf, &h); 304 out: 305 pcmcia_function_disable(pf); 306 cfxga_remove_function(pf); 307 308 /* 309 * Be sure to return a value greater than com's if we match, 310 * otherwise it can win due to the way config(8) will order devices... 311 */ 312 return (id == PRODUCT_S1D13806 ? 10 : 0); 313 } 314 315 int 316 cfxga_activate(struct device *dev, enum devact act) 317 { 318 struct cfxga_softc *sc = (void *)dev; 319 320 switch (act) { 321 case DVACT_ACTIVATE: 322 if (pcmcia_function_enable(sc->sc_pf) != 0) { 323 printf("%s: function enable failed\n", 324 sc->sc_dev.dv_xname); 325 } else { 326 cfxga_reset_and_repaint(sc); 327 } 328 break; 329 case DVACT_DEACTIVATE: 330 pcmcia_function_disable(sc->sc_pf); 331 break; 332 } 333 return (0); 334 } 335 336 void 337 cfxga_attach(struct device *parent, struct device *self, void *aux) 338 { 339 struct cfxga_softc *sc = (void *)self; 340 struct pcmcia_attach_args *pa = aux; 341 struct pcmcia_function *pf = pa->pf; 342 struct wsemuldisplaydev_attach_args waa; 343 struct wsscreen_descr *wsd; 344 u_int i; 345 346 LIST_INIT(&sc->sc_scr); 347 sc->sc_nscreens = 0; 348 sc->sc_pf = pf; 349 350 if (cfxga_install_function(pf) != 0) { 351 printf(": pcmcia function setup failed\n"); 352 return; 353 } 354 355 if (pcmcia_function_enable(pf)) { 356 printf(": function enable failed\n"); 357 return; 358 } 359 360 if (pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &sc->sc_pmemh) != 0) { 361 printf(": can't allocate memory space\n"); 362 return; 363 } 364 365 if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE, 366 &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin) != 0) { 367 printf(": can't map frame buffer registers\n"); 368 pcmcia_mem_free(pf, &sc->sc_pmemh); 369 return; 370 } 371 372 SET(sc->sc_state, CS_MAPPED); 373 374 printf("\n"); 375 376 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 377 378 /* 379 * We actually defer real initialization to the creation of the 380 * first wsdisplay screen, since we do not know which mode to pick 381 * yet. 382 */ 383 384 for (wsd = sc->sc_wsd, i = 0; i < CFXGA_NMODES; wsd++, i++) { 385 strlcpy(wsd->name, cfxga_modenames[i], sizeof(wsd->name)); 386 wsd->textops = &sc->sc_ops; 387 sc->sc_scrlist[i] = wsd; 388 } 389 sc->sc_wsl.nscreens = CFXGA_NMODES; 390 sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 391 392 waa.console = 0; 393 waa.scrdata = &sc->sc_wsl; 394 waa.accessops = &cfxga_accessops; 395 waa.accesscookie = sc; 396 waa.defaultscreens = 1; 397 398 if ((sc->sc_wsdisplay = 399 config_found(self, &waa, wsemuldisplaydevprint)) == NULL) { 400 /* otherwise wscons will do this */ 401 if (sc->sc_active != NULL) 402 cfxga_clear_screen(sc->sc_active); 403 else 404 cfxga_burner(sc, 0, 0); 405 } 406 } 407 408 int 409 cfxga_detach(struct device *dev, int flags) 410 { 411 struct cfxga_softc *sc = (void *)dev; 412 413 /* 414 * Detach all children, and hope wsdisplay detach code is correct... 415 */ 416 if (sc->sc_wsdisplay != NULL) { 417 config_detach(sc->sc_wsdisplay, DETACH_FORCE); 418 /* sc->sc_wsdisplay = NULL; */ 419 } 420 421 if (ISSET(sc->sc_state, CS_MAPPED)) { 422 pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin); 423 pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh); 424 /* CLR(sc->sc_state, CS_MAPPED); */ 425 } 426 427 return (0); 428 } 429 430 /* 431 * Wscons operations 432 */ 433 434 int 435 cfxga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 436 int *curxp, int *curyp, long *attrp) 437 { 438 struct cfxga_softc *sc = v; 439 struct cfxga_screen *scr; 440 struct rasops_info *ri; 441 u_int mode, width, height, depth, scrsize; 442 443 scr = malloc(sizeof *scr, M_DEVBUF, 444 (cold ? M_NOWAIT : M_WAITOK) | M_ZERO); 445 if (scr == NULL) 446 return (ENOMEM); 447 448 mode = type - sc->sc_wsd; 449 #ifdef DIAGNOSTIC 450 if (mode >= CFXGA_NMODES) 451 mode = CFXGA_MODE_640x480x16; 452 #endif 453 switch (mode) { 454 default: 455 case CFXGA_MODE_640x480x16: 456 width = 640; 457 height = 480; 458 depth = 16; 459 break; 460 case CFXGA_MODE_800x600x16: 461 width = 800; 462 height = 600; 463 depth = 16; 464 break; 465 #ifdef ENABLE_8BIT_MODES 466 case CFXGA_MODE_640x480x8: 467 width = 640; 468 height = 480; 469 depth = 8; 470 break; 471 case CFXGA_MODE_800x600x8: 472 width = 800; 473 height = 600; 474 depth = 8; 475 break; 476 #endif 477 } 478 479 ri = &scr->scr_ri; 480 ri->ri_hw = (void *)scr; 481 ri->ri_bits = NULL; 482 ri->ri_depth = depth; 483 ri->ri_width = width; 484 ri->ri_height = height; 485 ri->ri_stride = width * depth / 8; 486 ri->ri_flg = 0; 487 488 /* swap B and R at 16 bpp */ 489 if (depth == 16) { 490 ri->ri_rnum = 5; 491 ri->ri_rpos = 11; 492 ri->ri_gnum = 6; 493 ri->ri_gpos = 5; 494 ri->ri_bnum = 5; 495 ri->ri_bpos = 0; 496 } 497 498 if (type->nrows == 0) /* first screen creation */ 499 rasops_init(ri, 100, 100); 500 else 501 rasops_init(ri, type->nrows, type->ncols); 502 503 /* 504 * Allocate backing store to remember non-visible screen contents in 505 * emulation mode. 506 */ 507 scrsize = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell); 508 scr->scr_mem = malloc(scrsize, M_DEVBUF, 509 (cold ? M_NOWAIT : M_WAITOK) | M_ZERO); 510 if (scr->scr_mem == NULL) { 511 free(scr, M_DEVBUF); 512 return (ENOMEM); 513 } 514 515 ri->ri_ops.copycols = cfxga_copycols; 516 ri->ri_ops.copyrows = cfxga_copyrows; 517 ri->ri_ops.erasecols = cfxga_erasecols; 518 ri->ri_ops.eraserows = cfxga_eraserows; 519 ri->ri_ops.putchar = cfxga_putchar; 520 ri->ri_do_cursor = cfxga_do_cursor; 521 522 /* 523 * Finish initializing our screen descriptions, now that we know 524 * the actual console emulation parameters. 525 */ 526 if (type->nrows == 0) { 527 struct wsscreen_descr *wsd = (struct wsscreen_descr *)type; 528 529 wsd->nrows = ri->ri_rows; 530 wsd->ncols = ri->ri_cols; 531 bcopy(&ri->ri_ops, &sc->sc_ops, sizeof(sc->sc_ops)); 532 wsd->fontwidth = ri->ri_font->fontwidth; 533 wsd->fontheight = ri->ri_font->fontheight; 534 wsd->capabilities = ri->ri_caps; 535 } 536 537 scr->scr_sc = sc; 538 LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link); 539 sc->sc_nscreens++; 540 541 ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp); 542 543 *cookiep = ri; 544 *curxp = *curyp = 0; 545 546 return (0); 547 } 548 549 void 550 cfxga_burner(void *v, u_int on, u_int flags) 551 { 552 struct cfxga_softc *sc = (void *)v; 553 u_int8_t mode; 554 555 mode = cfxga_read_1(sc, CFREG_MODE) & LCD_MODE_SWIVEL_BIT_0; 556 557 if (on) 558 cfxga_write_1(sc, CFREG_MODE, mode | MODE_CRT); 559 else 560 cfxga_write_1(sc, CFREG_MODE, mode | MODE_NO_DISPLAY); 561 } 562 563 void 564 cfxga_free_screen(void *v, void *cookie) 565 { 566 struct cfxga_softc *sc = v; 567 struct rasops_info *ri = cookie; 568 struct cfxga_screen *scr = ri->ri_hw; 569 570 LIST_REMOVE(scr, scr_link); 571 sc->sc_nscreens--; 572 573 if (scr == sc->sc_active) { 574 sc->sc_active = NULL; 575 cfxga_burner(sc, 0, 0); 576 } 577 578 free(scr->scr_mem, M_DEVBUF); 579 free(scr, M_DEVBUF); 580 } 581 582 int 583 cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 584 { 585 struct cfxga_softc *sc = v; 586 struct cfxga_screen *scr; 587 struct wsdisplay_fbinfo *wdf; 588 int mode; 589 590 switch (cmd) { 591 case WSDISPLAYIO_GTYPE: 592 *(u_int *)data = WSDISPLAY_TYPE_CFXGA; 593 break; 594 595 case WSDISPLAYIO_GINFO: 596 wdf = (struct wsdisplay_fbinfo *)data; 597 scr = sc->sc_active; 598 if (scr == NULL) { 599 /* try later...after running wsconscfg to add screens */ 600 wdf->height = wdf->width = wdf->depth = wdf->cmsize = 0; 601 } else { 602 wdf->height = scr->scr_ri.ri_height; 603 wdf->width = scr->scr_ri.ri_width; 604 wdf->depth = scr->scr_ri.ri_depth; 605 wdf->cmsize = scr->scr_ri.ri_depth <= 8 ? 606 (1 << scr->scr_ri.ri_depth) : 0; 607 } 608 break; 609 610 case WSDISPLAYIO_SMODE: 611 mode = *(u_int *)data; 612 if (mode == sc->sc_mode) 613 break; 614 switch (mode) { 615 case WSDISPLAYIO_MODE_EMUL: 616 cfxga_reset_and_repaint(sc); 617 break; 618 case WSDISPLAYIO_MODE_MAPPED: 619 break; 620 default: 621 return (EINVAL); 622 } 623 sc->sc_mode = mode; 624 break; 625 626 /* these operations are handled by the wscons code... */ 627 case WSDISPLAYIO_GVIDEO: 628 case WSDISPLAYIO_SVIDEO: 629 break; 630 631 /* these operations are not supported... */ 632 case WSDISPLAYIO_GETCMAP: 633 case WSDISPLAYIO_PUTCMAP: 634 case WSDISPLAYIO_LINEBYTES: 635 case WSDISPLAYIO_GCURPOS: 636 case WSDISPLAYIO_SCURPOS: 637 case WSDISPLAYIO_GCURMAX: 638 case WSDISPLAYIO_GCURSOR: 639 case WSDISPLAYIO_SCURSOR: 640 default: 641 return (-1); 642 } 643 644 return (0); 645 } 646 647 paddr_t 648 cfxga_mmap(void *v, off_t off, int prot) 649 { 650 return (-1); 651 } 652 653 int 654 cfxga_show_screen(void *v, void *cookie, int waitok, 655 void (*cb)(void *, int, int), void *cbarg) 656 { 657 struct cfxga_softc *sc = v; 658 struct rasops_info *ri = cookie; 659 struct cfxga_screen *scr = ri->ri_hw, *old; 660 661 old = sc->sc_active; 662 if (old == scr) 663 return (0); 664 665 sc->sc_active = scr; 666 cfxga_reset_and_repaint(sc); /* will turn video on if scr != NULL */ 667 668 return (0); 669 } 670 671 /* 672 * Real frame buffer operations 673 */ 674 675 void 676 cfxga_reset_video(struct cfxga_softc *sc) 677 { 678 struct cfxga_screen *scr = sc->sc_active; 679 struct rasops_info *ri; 680 #ifdef ENABLE_8BIT_MODES 681 const u_int8_t *cmap; 682 u_int i; 683 #endif 684 685 /* 686 * Reset controller 687 */ 688 689 /* need to write to both REV and MISC at the same time */ 690 cfxga_write_2(sc, CFREG_REV, 0x80 | (CM_REGSEL << 8)); 691 delay(25000); /* maintain reset for a short while */ 692 /* need to write to both REV and MISC at the same time */ 693 cfxga_write_2(sc, CFREG_REV, 0 | (CM_MEMSEL << 8)); 694 delay(25000); 695 /* stop any pending blt operation */ 696 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0); 697 cfxga_stop_memory_blt(sc); 698 cfxga_write_1(sc, CFREG_MODE, 0); /* disable all displays */ 699 700 /* 701 * Setup common video mode parameters. 702 */ 703 704 cfxga_write_2(sc, CFREG_MEMCLK, MEMCLK_SRC_CLK3); 705 #if 0 706 cfxga_write_1(sc, CFREG_LCD_PCLK, LCD_PCLK_SRC_CLKI | LCD_PCLK_DIV_1); 707 cfxga_write_1(sc, CFREG_MPLUG_CLK, 708 MPLUG_PCLK_SRC_CLKI2 | MPLUG_PCLK_DIV_1); 709 #endif 710 cfxga_write_2(sc, CFREG_CRTTV_PCLK, CRT_PCLK_SRC_CLKI | CRT_PCLK_DIV_1); 711 cfxga_write_2(sc, CFREG_WSTATE, WSTATE_MCLK); 712 713 /* MEMCNF and DRAM_RFRSH need to be programmed at the same time */ 714 cfxga_write_2(sc, CFREG_MEMCNF, 715 MEMCNF_SDRAM_INIT | (DRAM_RFRSH_50MHZ << 8)); 716 delay(250); 717 cfxga_write_2(sc, CFREG_DRAM_TIMING, DRAM_TIMING_50MHZ); 718 719 /* 720 * Setup mode-dependent parameters. 721 */ 722 if (scr == NULL) 723 return; 724 725 ri = &scr->scr_ri; 726 switch (scr->scr_ri.ri_width) { 727 default: 728 case 640: 729 cfxga_write_1(sc, CFREG_CRT_HWIDTH, (640 / 8) - 1); 730 /* HNDISP and HSTART need to be programmed at the same time */ 731 cfxga_write_2(sc, CFREG_CRT_HNDISP, 23 | (2 << 8)); 732 cfxga_write_1(sc, CFREG_CRT_HPULSE, 4); 733 cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 480 - 1); 734 /* VNDISP and VSTART need to be programmed at the same time */ 735 cfxga_write_2(sc, CFREG_CRT_VNDISP, 39 | (8 << 8)); 736 cfxga_write_1(sc, CFREG_CRT_VPULSE, 2); 737 break; 738 case 800: 739 cfxga_write_1(sc, CFREG_CRT_HWIDTH, (800 / 8) - 1); 740 /* HNDISP and HSTART need to be programmed at the same time */ 741 cfxga_write_2(sc, CFREG_CRT_HNDISP, 27 | (2 << 8)); 742 cfxga_write_1(sc, CFREG_CRT_HPULSE, 4); 743 cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 600 - 1); 744 /* VNDISP and VSTART need to be programmed at the same time */ 745 cfxga_write_2(sc, CFREG_CRT_VNDISP, 25 | (8 << 8)); 746 cfxga_write_1(sc, CFREG_CRT_VPULSE, 2); 747 break; 748 } 749 cfxga_write_1(sc, CFREG_CRT_MODE, 750 ri->ri_depth == 16 ? CRT_MODE_16BPP : CRT_MODE_8BPP); 751 cfxga_write_2(sc, CFREG_CRT_START_LOW, 0); 752 cfxga_write_1(sc, CFREG_CRT_START_HIGH, 0); 753 cfxga_write_2(sc, CFREG_CRT_MEMORY, ri->ri_width * ri->ri_depth / 16); 754 cfxga_write_1(sc, CFREG_CRT_PANNING, 0); 755 cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_HIGH, 0); 756 cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_LOW, 0); 757 cfxga_write_1(sc, CFREG_CRT_CURSOR_CONTROL, CURSOR_INACTIVE); 758 759 #ifdef ENABLE_8BIT_MODES 760 /* 761 * On 8bpp video modes, program the LUT 762 */ 763 if (ri->ri_depth == 8) { 764 #if 0 765 /* Wait for retrace */ 766 while ((cfxga_read_1(sc, CFREG_CRT_VNDISP) & 767 CRT_VNDISP_STATUS) == 0) 768 delay(1); 769 #endif 770 cfxga_write_1(sc, CFREG_LUT_MODE, LUT_CRT); 771 cfxga_write_1(sc, CFREG_LUT_ADDRESS, 0); /* autoincrements */ 772 cmap = rasops_cmap; 773 for (i = 256 * 3; i != 0; i--) 774 cfxga_write_1(sc, CFREG_LUT_DATA, *cmap++ & 0xf0); 775 } 776 #endif 777 778 cfxga_write_1(sc, CFREG_TV_CONTROL, 779 TV_LUMINANCE_FILTER | TV_SVIDEO_OUTPUT | TV_NTSC_OUTPUT); 780 781 cfxga_write_1(sc, CFREG_POWER_CONF, POWERSAVE_MBO); 782 cfxga_write_1(sc, CFREG_WATCHDOG, 0); 783 784 cfxga_write_1(sc, CFREG_MODE, MODE_CRT); 785 delay(25000); 786 } 787 788 void 789 cfxga_reset_and_repaint(struct cfxga_softc *sc) 790 { 791 cfxga_reset_video(sc); 792 793 if (sc->sc_active != NULL) 794 cfxga_repaint_screen(sc->sc_active); 795 else 796 cfxga_burner(sc, 0, 0); 797 } 798 799 /* 800 * Wait for the blitter to be in a given state. 801 */ 802 u_int 803 cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result) 804 { 805 u_int tries; 806 807 for (tries = 10000; tries != 0; tries--) { 808 if ((cfxga_read_1(sc, CFREG_BITBLT_CONTROL) & mask) == result) 809 break; 810 delay(10); 811 } 812 813 return (tries); 814 } 815 816 /* 817 * Wait for all pending blitter operations to be complete. 818 * Returns non-zero if the blitter got stuck. 819 */ 820 int 821 cfxga_synchronize(struct cfxga_softc *sc) 822 { 823 /* Wait for previous operations to complete */ 824 if (cfxga_wait(sc, BITBLT_ACTIVE, 0) == 0) { 825 DPRINTF(("%s: not ready\n", __func__)); 826 if (ISSET(sc->sc_state, CS_RESET)) 827 return (EAGAIN); 828 else { 829 DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname)); 830 SET(sc->sc_state, CS_RESET); 831 cfxga_reset_and_repaint(sc); 832 CLR(sc->sc_state, CS_RESET); 833 } 834 } 835 cfxga_stop_memory_blt(sc); 836 return (0); 837 } 838 839 /* 840 * Display a character. 841 */ 842 int 843 cfxga_expand_char(struct cfxga_screen *scr, u_int uc, int x, int y, long attr) 844 { 845 struct cfxga_softc *sc = scr->scr_sc; 846 struct rasops_info *ri = &scr->scr_ri; 847 struct wsdisplay_font *font = ri->ri_font; 848 u_int pos, sts, fifo_avail, chunk; 849 u_int8_t *fontbits; 850 int bg, fg, ul; 851 u_int i; 852 int rc; 853 854 pos = (y * ri->ri_width + x) * ri->ri_depth / 8; 855 fontbits = (u_int8_t *)(font->data + (uc - font->firstchar) * 856 ri->ri_fontscale); 857 ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul); 858 859 /* Wait for previous operations to complete */ 860 if ((rc = cfxga_synchronize(sc)) != 0) 861 return (rc); 862 863 cfxga_write_2(sc, CFREG_COLOR_EXPANSION, 864 ((font->fontwidth - 1) & 7) | (OP_COLOR_EXPANSION << 8)); 865 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, font->fontwidth <= 8 ? 0 : 1); 866 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, 0); 867 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos); 868 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16); 869 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 870 ri->ri_width * ri->ri_depth / 16); 871 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, font->fontwidth - 1); 872 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, font->fontheight - 1); 873 cfxga_write_2(sc, CFREG_BITBLT_FG, ri->ri_devcmap[fg]); 874 cfxga_write_2(sc, CFREG_BITBLT_BG, ri->ri_devcmap[bg]); 875 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 876 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 877 878 if (cfxga_wait(sc, BITBLT_ACTIVE, BITBLT_ACTIVE) == 0) 879 goto fail; /* unlikely */ 880 fifo_avail = 0; 881 882 for (i = font->fontheight; i != 0; i--) { 883 /* 884 * Find out how much words we can feed before 885 * a FIFO check is needed. 886 */ 887 if (fifo_avail == 0) { 888 sts = cfxga_read_1(sc, CFREG_BITBLT_CONTROL); 889 if ((sts & BITBLT_FIFO_NOT_EMPTY) == 0) 890 fifo_avail = font->fontwidth <= 8 ? 2 : 1; 891 else if ((sts & BITBLT_FIFO_HALF_FULL) == 0) 892 fifo_avail = font->fontwidth <= 8 ? 1 : 0; 893 else { 894 /* 895 * Let the cheap breathe for a short while. 896 * If this is not enough to free some FIFO 897 * entries, abort the operation. 898 */ 899 if (cfxga_wait(sc, BITBLT_FIFO_FULL, 0) == 0) 900 goto fail; 901 } 902 } 903 904 if (font->fontwidth <= 8) { 905 chunk = *fontbits; 906 if (ul && i == 1) 907 chunk = 0xff; 908 } else { 909 chunk = *(u_int16_t *)fontbits; 910 if (ul && i == 1) 911 chunk = 0xffff; 912 } 913 cfxga_write_2(sc, CFREG_BITBLT_DATA, chunk); 914 fontbits += font->stride; 915 fifo_avail--; 916 } 917 918 return (0); 919 920 fail: 921 DPRINTF(("%s: abort\n", __func__)); 922 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0); 923 cfxga_stop_memory_blt(sc); 924 return (EINTR); 925 } 926 927 /* 928 * Copy a memory bitmap to the frame buffer. 929 * 930 * This is slow - we only use this to repaint the whole frame buffer on 931 * screen switches. 932 */ 933 int 934 cfxga_repaint_screen(struct cfxga_screen *scr) 935 { 936 struct wsdisplay_charcell *cell = scr->scr_mem; 937 struct rasops_info *ri = &scr->scr_ri; 938 int x, y, cx, cy, lx, ly; 939 int fg, bg; 940 int rc; 941 942 cfxga_clear_screen(scr); 943 944 cx = ri->ri_font->fontwidth; 945 cy = ri->ri_font->fontheight; 946 947 for (ly = 0, y = ri->ri_yorigin; ly < ri->ri_rows; ly++, y += cy) { 948 for (lx = 0, x = ri->ri_xorigin; lx < ri->ri_cols; 949 lx++, x += cx) { 950 if (cell->uc == 0 || cell->uc == ' ') { 951 ri->ri_ops.unpack_attr(ri, cell->attr, 952 &fg, &bg, NULL); 953 rc = cfxga_solid_fill(scr, x, y, cx, cy, 954 ri->ri_devcmap[bg]); 955 } else { 956 rc = cfxga_expand_char(scr, cell->uc, 957 x, y, cell->attr); 958 } 959 cell++; 960 if (rc != 0) 961 return (rc); 962 } 963 } 964 965 return (0); 966 } 967 968 /* 969 * Perform a solid fill operation. 970 */ 971 int 972 cfxga_solid_fill(struct cfxga_screen *scr, int x, int y, int cx, int cy, 973 int32_t srccolor) 974 { 975 struct cfxga_softc *sc = scr->scr_sc; 976 struct rasops_info *ri = &scr->scr_ri; 977 u_int pos; 978 int rc; 979 980 pos = (y * ri->ri_width + x) * ri->ri_depth / 8; 981 982 /* Wait for previous operations to complete */ 983 if ((rc = cfxga_synchronize(sc)) != 0) 984 return (rc); 985 986 cfxga_write_2(sc, CFREG_BITBLT_ROP, 0 | (OP_SOLID_FILL << 8)); 987 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, pos); 988 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, pos >> 16); 989 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos); 990 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16); 991 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 992 ri->ri_width * ri->ri_depth / 16); 993 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1); 994 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1); 995 cfxga_write_2(sc, CFREG_BITBLT_FG, (u_int16_t)srccolor); 996 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 997 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 998 999 return (0); 1000 } 1001 1002 /* 1003 * Perform an internal frame buffer operation. 1004 */ 1005 int 1006 cfxga_standalone_rop(struct cfxga_screen *scr, u_int rop, int sx, int sy, 1007 int dx, int dy, int cx, int cy) 1008 { 1009 struct cfxga_softc *sc = scr->scr_sc; 1010 struct rasops_info *ri = &scr->scr_ri; 1011 u_int srcpos, dstpos; 1012 u_int opcode; 1013 int rc; 1014 1015 srcpos = (sy * ri->ri_width + sx) * ri->ri_depth / 8; 1016 dstpos = (dy * ri->ri_width + dx) * ri->ri_depth / 8; 1017 1018 if (dstpos <= srcpos) 1019 opcode = (OP_MOVE_POSITIVE_ROP << 8) | rop; 1020 else 1021 opcode = (OP_MOVE_NEGATIVE_ROP << 8) | rop; 1022 1023 /* Wait for previous operations to complete */ 1024 if ((rc = cfxga_synchronize(sc)) != 0) 1025 return (rc); 1026 1027 cfxga_write_2(sc, CFREG_BITBLT_ROP, opcode); 1028 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, srcpos); 1029 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, srcpos >> 16); 1030 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, dstpos); 1031 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, dstpos >> 16); 1032 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 1033 ri->ri_width * ri->ri_depth / 16); 1034 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1); 1035 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1); 1036 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 1037 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 1038 1039 return (0); 1040 } 1041 1042 /* 1043 * Text console raster operations. 1044 * 1045 * We shadow all these operations on a memory copy of the frame buffer. 1046 * Since we are running in emulation mode only, this could be optimized 1047 * by only storing actual character cell values (a la mda). 1048 */ 1049 1050 void 1051 cfxga_copycols(void *cookie, int row, int src, int dst, int num) 1052 { 1053 struct rasops_info *ri = cookie; 1054 struct cfxga_screen *scr = ri->ri_hw; 1055 int sx, dx, y, cx, cy; 1056 1057 /* Copy columns in backing store. */ 1058 ovbcopy(scr->scr_mem + row * ri->ri_cols + src, 1059 scr->scr_mem + row * ri->ri_cols + dst, 1060 num * sizeof(struct wsdisplay_charcell)); 1061 1062 if (scr != scr->scr_sc->sc_active) 1063 return; 1064 1065 sx = src * ri->ri_font->fontwidth + ri->ri_xorigin; 1066 dx = dst * ri->ri_font->fontwidth + ri->ri_xorigin; 1067 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1068 cx = num * ri->ri_font->fontwidth; 1069 cy = ri->ri_font->fontheight; 1070 cfxga_standalone_rop(scr, ROP_SRC, sx, y, dx, y, cx, cy); 1071 } 1072 1073 void 1074 cfxga_copyrows(void *cookie, int src, int dst, int num) 1075 { 1076 struct rasops_info *ri = cookie; 1077 struct cfxga_screen *scr = ri->ri_hw; 1078 int x, sy, dy, cx, cy; 1079 1080 /* Copy rows in backing store. */ 1081 ovbcopy(scr->scr_mem + src * ri->ri_cols, 1082 scr->scr_mem + dst * ri->ri_cols, 1083 num * ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1084 1085 if (scr != scr->scr_sc->sc_active) 1086 return; 1087 1088 x = ri->ri_xorigin; 1089 sy = src * ri->ri_font->fontheight + ri->ri_yorigin; 1090 dy = dst * ri->ri_font->fontheight + ri->ri_yorigin; 1091 cx = ri->ri_emuwidth; 1092 cy = num * ri->ri_font->fontheight; 1093 cfxga_standalone_rop(scr, ROP_SRC, x, sy, x, dy, cx, cy); 1094 } 1095 1096 void 1097 cfxga_do_cursor(struct rasops_info *ri) 1098 { 1099 struct cfxga_screen *scr = ri->ri_hw; 1100 int x, y, cx, cy; 1101 1102 if (scr != scr->scr_sc->sc_active) 1103 return; 1104 1105 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 1106 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 1107 cx = ri->ri_font->fontwidth; 1108 cy = ri->ri_font->fontheight; 1109 cfxga_standalone_rop(scr, ROP_ONES ^ ROP_SRC /* i.e. not SRC */, 1110 x, y, x, y, cx, cy); 1111 } 1112 1113 void 1114 cfxga_erasecols(void *cookie, int row, int col, int num, long attr) 1115 { 1116 struct rasops_info *ri = cookie; 1117 struct cfxga_screen *scr = ri->ri_hw; 1118 int fg, bg; 1119 int x, y, cx, cy; 1120 1121 /* Erase columns in backing store. */ 1122 for (x = col; x < col + num; x++) { 1123 scr->scr_mem[row * ri->ri_cols + x].uc = 0; 1124 scr->scr_mem[row * ri->ri_cols + x].attr = attr; 1125 } 1126 1127 if (scr != scr->scr_sc->sc_active) 1128 return; 1129 1130 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1131 x = col * ri->ri_font->fontwidth + ri->ri_xorigin; 1132 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1133 cx = num * ri->ri_font->fontwidth; 1134 cy = ri->ri_font->fontheight; 1135 cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1136 } 1137 1138 void 1139 cfxga_eraserows(void *cookie, int row, int num, long attr) 1140 { 1141 struct rasops_info *ri = cookie; 1142 struct cfxga_screen *scr = ri->ri_hw; 1143 int fg, bg; 1144 int x, y, cx, cy; 1145 1146 /* Erase rows in backing store. */ 1147 for (x = 0; x < ri->ri_cols; x++) { 1148 scr->scr_mem[row * ri->ri_cols + x].uc = 0; 1149 scr->scr_mem[row * ri->ri_cols + x].attr = attr; 1150 } 1151 for (y = 1; y < num; y++) 1152 ovbcopy(scr->scr_mem + row * ri->ri_cols, 1153 scr->scr_mem + (row + y) * ri->ri_cols, 1154 ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1155 1156 if (scr != scr->scr_sc->sc_active) 1157 return; 1158 1159 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1160 x = ri->ri_xorigin; 1161 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1162 cx = ri->ri_emuwidth; 1163 cy = num * ri->ri_font->fontheight; 1164 cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1165 } 1166 1167 void 1168 cfxga_putchar(void *cookie, int row, int col, u_int uc, long attr) 1169 { 1170 struct rasops_info *ri = cookie; 1171 struct cfxga_screen *scr = ri->ri_hw; 1172 int x, y; 1173 1174 scr->scr_mem[row * ri->ri_cols + col].uc = uc; 1175 scr->scr_mem[row * ri->ri_cols + col].attr = attr; 1176 1177 if (scr != scr->scr_sc->sc_active) 1178 return; 1179 1180 x = col * ri->ri_font->fontwidth + ri->ri_xorigin; 1181 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1182 1183 if (uc == ' ') { 1184 int cx, cy, fg, bg; 1185 1186 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1187 cx = ri->ri_font->fontwidth; 1188 cy = ri->ri_font->fontheight; 1189 cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1190 } else { 1191 cfxga_expand_char(scr, uc, x, y, attr); 1192 } 1193 } 1194