1 /* $OpenBSD: cfxga.c,v 1.21 2011/07/03 15:47:17 matthew 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 *, int); 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 int cfxga_copycols(void *, int, int, int, int); 144 int cfxga_copyrows(void *, int, int, int); 145 int cfxga_do_cursor(struct rasops_info *); 146 int cfxga_erasecols(void *, int, int, int, long); 147 int cfxga_eraserows(void *, int, int, long); 148 int 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, int act) 317 { 318 struct cfxga_softc *sc = (void *)dev; 319 320 switch (act) { 321 case DVACT_DEACTIVATE: 322 pcmcia_function_disable(sc->sc_pf); 323 break; 324 } 325 return (0); 326 } 327 328 void 329 cfxga_attach(struct device *parent, struct device *self, void *aux) 330 { 331 struct cfxga_softc *sc = (void *)self; 332 struct pcmcia_attach_args *pa = aux; 333 struct pcmcia_function *pf = pa->pf; 334 struct wsemuldisplaydev_attach_args waa; 335 struct wsscreen_descr *wsd; 336 u_int i; 337 338 LIST_INIT(&sc->sc_scr); 339 sc->sc_nscreens = 0; 340 sc->sc_pf = pf; 341 342 if (cfxga_install_function(pf) != 0) { 343 printf(": pcmcia function setup failed\n"); 344 return; 345 } 346 347 if (pcmcia_function_enable(pf)) { 348 printf(": function enable failed\n"); 349 return; 350 } 351 352 if (pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &sc->sc_pmemh) != 0) { 353 printf(": can't allocate memory space\n"); 354 return; 355 } 356 357 if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE, 358 &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin) != 0) { 359 printf(": can't map frame buffer registers\n"); 360 pcmcia_mem_free(pf, &sc->sc_pmemh); 361 return; 362 } 363 364 SET(sc->sc_state, CS_MAPPED); 365 366 printf("\n"); 367 368 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 369 370 /* 371 * We actually defer real initialization to the creation of the 372 * first wsdisplay screen, since we do not know which mode to pick 373 * yet. 374 */ 375 376 for (wsd = sc->sc_wsd, i = 0; i < CFXGA_NMODES; wsd++, i++) { 377 strlcpy(wsd->name, cfxga_modenames[i], sizeof(wsd->name)); 378 wsd->textops = &sc->sc_ops; 379 sc->sc_scrlist[i] = wsd; 380 } 381 sc->sc_wsl.nscreens = CFXGA_NMODES; 382 sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 383 384 waa.console = 0; 385 waa.scrdata = &sc->sc_wsl; 386 waa.accessops = &cfxga_accessops; 387 waa.accesscookie = sc; 388 waa.defaultscreens = 1; 389 390 if ((sc->sc_wsdisplay = 391 config_found(self, &waa, wsemuldisplaydevprint)) == NULL) { 392 /* otherwise wscons will do this */ 393 if (sc->sc_active != NULL) 394 cfxga_clear_screen(sc->sc_active); 395 else 396 cfxga_burner(sc, 0, 0); 397 } 398 } 399 400 int 401 cfxga_detach(struct device *dev, int flags) 402 { 403 struct cfxga_softc *sc = (void *)dev; 404 405 /* 406 * Detach all children, and hope wsdisplay detach code is correct... 407 */ 408 if (sc->sc_wsdisplay != NULL) { 409 config_detach(sc->sc_wsdisplay, DETACH_FORCE); 410 /* sc->sc_wsdisplay = NULL; */ 411 } 412 413 if (ISSET(sc->sc_state, CS_MAPPED)) { 414 pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin); 415 pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh); 416 /* CLR(sc->sc_state, CS_MAPPED); */ 417 } 418 419 return (0); 420 } 421 422 /* 423 * Wscons operations 424 */ 425 426 int 427 cfxga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 428 int *curxp, int *curyp, long *attrp) 429 { 430 struct cfxga_softc *sc = v; 431 struct cfxga_screen *scr; 432 struct rasops_info *ri; 433 u_int mode, width, height, depth, scrsize; 434 435 scr = malloc(sizeof *scr, M_DEVBUF, 436 (cold ? M_NOWAIT : M_WAITOK) | M_ZERO); 437 if (scr == NULL) 438 return (ENOMEM); 439 440 mode = type - sc->sc_wsd; 441 #ifdef DIAGNOSTIC 442 if (mode >= CFXGA_NMODES) 443 mode = CFXGA_MODE_640x480x16; 444 #endif 445 switch (mode) { 446 default: 447 case CFXGA_MODE_640x480x16: 448 width = 640; 449 height = 480; 450 depth = 16; 451 break; 452 case CFXGA_MODE_800x600x16: 453 width = 800; 454 height = 600; 455 depth = 16; 456 break; 457 #ifdef ENABLE_8BIT_MODES 458 case CFXGA_MODE_640x480x8: 459 width = 640; 460 height = 480; 461 depth = 8; 462 break; 463 case CFXGA_MODE_800x600x8: 464 width = 800; 465 height = 600; 466 depth = 8; 467 break; 468 #endif 469 } 470 471 ri = &scr->scr_ri; 472 ri->ri_hw = (void *)scr; 473 ri->ri_bits = NULL; 474 ri->ri_depth = depth; 475 ri->ri_width = width; 476 ri->ri_height = height; 477 ri->ri_stride = width * depth / 8; 478 ri->ri_flg = 0; 479 480 /* swap B and R at 16 bpp */ 481 if (depth == 16) { 482 ri->ri_rnum = 5; 483 ri->ri_rpos = 11; 484 ri->ri_gnum = 6; 485 ri->ri_gpos = 5; 486 ri->ri_bnum = 5; 487 ri->ri_bpos = 0; 488 } 489 490 if (type->nrows == 0) /* first screen creation */ 491 rasops_init(ri, 100, 100); 492 else 493 rasops_init(ri, type->nrows, type->ncols); 494 495 /* 496 * Allocate backing store to remember non-visible screen contents in 497 * emulation mode. 498 */ 499 scrsize = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell); 500 scr->scr_mem = malloc(scrsize, M_DEVBUF, 501 (cold ? M_NOWAIT : M_WAITOK) | M_ZERO); 502 if (scr->scr_mem == NULL) { 503 free(scr, M_DEVBUF); 504 return (ENOMEM); 505 } 506 507 ri->ri_ops.copycols = cfxga_copycols; 508 ri->ri_ops.copyrows = cfxga_copyrows; 509 ri->ri_ops.erasecols = cfxga_erasecols; 510 ri->ri_ops.eraserows = cfxga_eraserows; 511 ri->ri_ops.putchar = cfxga_putchar; 512 ri->ri_do_cursor = cfxga_do_cursor; 513 514 /* 515 * Finish initializing our screen descriptions, now that we know 516 * the actual console emulation parameters. 517 */ 518 if (type->nrows == 0) { 519 struct wsscreen_descr *wsd = (struct wsscreen_descr *)type; 520 521 wsd->nrows = ri->ri_rows; 522 wsd->ncols = ri->ri_cols; 523 bcopy(&ri->ri_ops, &sc->sc_ops, sizeof(sc->sc_ops)); 524 wsd->fontwidth = ri->ri_font->fontwidth; 525 wsd->fontheight = ri->ri_font->fontheight; 526 wsd->capabilities = ri->ri_caps; 527 } 528 529 scr->scr_sc = sc; 530 LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link); 531 sc->sc_nscreens++; 532 533 ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp); 534 535 *cookiep = ri; 536 *curxp = *curyp = 0; 537 538 return (0); 539 } 540 541 void 542 cfxga_burner(void *v, u_int on, u_int flags) 543 { 544 struct cfxga_softc *sc = (void *)v; 545 u_int8_t mode; 546 547 mode = cfxga_read_1(sc, CFREG_MODE) & LCD_MODE_SWIVEL_BIT_0; 548 549 if (on) 550 cfxga_write_1(sc, CFREG_MODE, mode | MODE_CRT); 551 else 552 cfxga_write_1(sc, CFREG_MODE, mode | MODE_NO_DISPLAY); 553 } 554 555 void 556 cfxga_free_screen(void *v, void *cookie) 557 { 558 struct cfxga_softc *sc = v; 559 struct rasops_info *ri = cookie; 560 struct cfxga_screen *scr = ri->ri_hw; 561 562 LIST_REMOVE(scr, scr_link); 563 sc->sc_nscreens--; 564 565 if (scr == sc->sc_active) { 566 sc->sc_active = NULL; 567 cfxga_burner(sc, 0, 0); 568 } 569 570 free(scr->scr_mem, M_DEVBUF); 571 free(scr, M_DEVBUF); 572 } 573 574 int 575 cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 576 { 577 struct cfxga_softc *sc = v; 578 struct cfxga_screen *scr; 579 struct wsdisplay_fbinfo *wdf; 580 int mode; 581 582 switch (cmd) { 583 case WSDISPLAYIO_GTYPE: 584 *(u_int *)data = WSDISPLAY_TYPE_CFXGA; 585 break; 586 587 case WSDISPLAYIO_GINFO: 588 wdf = (struct wsdisplay_fbinfo *)data; 589 scr = sc->sc_active; 590 if (scr == NULL) { 591 /* try later...after running wsconscfg to add screens */ 592 wdf->height = wdf->width = wdf->depth = wdf->cmsize = 0; 593 } else { 594 wdf->height = scr->scr_ri.ri_height; 595 wdf->width = scr->scr_ri.ri_width; 596 wdf->depth = scr->scr_ri.ri_depth; 597 wdf->cmsize = scr->scr_ri.ri_depth <= 8 ? 598 (1 << scr->scr_ri.ri_depth) : 0; 599 } 600 break; 601 602 case WSDISPLAYIO_SMODE: 603 mode = *(u_int *)data; 604 if (mode == sc->sc_mode) 605 break; 606 switch (mode) { 607 case WSDISPLAYIO_MODE_EMUL: 608 cfxga_reset_and_repaint(sc); 609 break; 610 case WSDISPLAYIO_MODE_MAPPED: 611 break; 612 default: 613 return (EINVAL); 614 } 615 sc->sc_mode = mode; 616 break; 617 618 /* these operations are handled by the wscons code... */ 619 case WSDISPLAYIO_GVIDEO: 620 case WSDISPLAYIO_SVIDEO: 621 break; 622 623 /* these operations are not supported... */ 624 case WSDISPLAYIO_GETCMAP: 625 case WSDISPLAYIO_PUTCMAP: 626 case WSDISPLAYIO_LINEBYTES: 627 case WSDISPLAYIO_GCURPOS: 628 case WSDISPLAYIO_SCURPOS: 629 case WSDISPLAYIO_GCURMAX: 630 case WSDISPLAYIO_GCURSOR: 631 case WSDISPLAYIO_SCURSOR: 632 default: 633 return (-1); 634 } 635 636 return (0); 637 } 638 639 paddr_t 640 cfxga_mmap(void *v, off_t off, int prot) 641 { 642 return (-1); 643 } 644 645 int 646 cfxga_show_screen(void *v, void *cookie, int waitok, 647 void (*cb)(void *, int, int), void *cbarg) 648 { 649 struct cfxga_softc *sc = v; 650 struct rasops_info *ri = cookie; 651 struct cfxga_screen *scr = ri->ri_hw, *old; 652 653 old = sc->sc_active; 654 if (old == scr) 655 return (0); 656 657 sc->sc_active = scr; 658 cfxga_reset_and_repaint(sc); /* will turn video on if scr != NULL */ 659 660 return (0); 661 } 662 663 /* 664 * Real frame buffer operations 665 */ 666 667 void 668 cfxga_reset_video(struct cfxga_softc *sc) 669 { 670 struct cfxga_screen *scr = sc->sc_active; 671 struct rasops_info *ri; 672 #ifdef ENABLE_8BIT_MODES 673 const u_int8_t *cmap; 674 u_int i; 675 #endif 676 677 /* 678 * Reset controller 679 */ 680 681 /* need to write to both REV and MISC at the same time */ 682 cfxga_write_2(sc, CFREG_REV, 0x80 | (CM_REGSEL << 8)); 683 delay(25000); /* maintain reset for a short while */ 684 /* need to write to both REV and MISC at the same time */ 685 cfxga_write_2(sc, CFREG_REV, 0 | (CM_MEMSEL << 8)); 686 delay(25000); 687 /* stop any pending blt operation */ 688 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0); 689 cfxga_stop_memory_blt(sc); 690 cfxga_write_1(sc, CFREG_MODE, 0); /* disable all displays */ 691 692 /* 693 * Setup common video mode parameters. 694 */ 695 696 cfxga_write_2(sc, CFREG_MEMCLK, MEMCLK_SRC_CLK3); 697 #if 0 698 cfxga_write_1(sc, CFREG_LCD_PCLK, LCD_PCLK_SRC_CLKI | LCD_PCLK_DIV_1); 699 cfxga_write_1(sc, CFREG_MPLUG_CLK, 700 MPLUG_PCLK_SRC_CLKI2 | MPLUG_PCLK_DIV_1); 701 #endif 702 cfxga_write_2(sc, CFREG_CRTTV_PCLK, CRT_PCLK_SRC_CLKI | CRT_PCLK_DIV_1); 703 cfxga_write_2(sc, CFREG_WSTATE, WSTATE_MCLK); 704 705 /* MEMCNF and DRAM_RFRSH need to be programmed at the same time */ 706 cfxga_write_2(sc, CFREG_MEMCNF, 707 MEMCNF_SDRAM_INIT | (DRAM_RFRSH_50MHZ << 8)); 708 delay(250); 709 cfxga_write_2(sc, CFREG_DRAM_TIMING, DRAM_TIMING_50MHZ); 710 711 /* 712 * Setup mode-dependent parameters. 713 */ 714 if (scr == NULL) 715 return; 716 717 ri = &scr->scr_ri; 718 switch (scr->scr_ri.ri_width) { 719 default: 720 case 640: 721 cfxga_write_1(sc, CFREG_CRT_HWIDTH, (640 / 8) - 1); 722 /* HNDISP and HSTART need to be programmed at the same time */ 723 cfxga_write_2(sc, CFREG_CRT_HNDISP, 23 | (2 << 8)); 724 cfxga_write_1(sc, CFREG_CRT_HPULSE, 4); 725 cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 480 - 1); 726 /* VNDISP and VSTART need to be programmed at the same time */ 727 cfxga_write_2(sc, CFREG_CRT_VNDISP, 39 | (8 << 8)); 728 cfxga_write_1(sc, CFREG_CRT_VPULSE, 2); 729 break; 730 case 800: 731 cfxga_write_1(sc, CFREG_CRT_HWIDTH, (800 / 8) - 1); 732 /* HNDISP and HSTART need to be programmed at the same time */ 733 cfxga_write_2(sc, CFREG_CRT_HNDISP, 27 | (2 << 8)); 734 cfxga_write_1(sc, CFREG_CRT_HPULSE, 4); 735 cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 600 - 1); 736 /* VNDISP and VSTART need to be programmed at the same time */ 737 cfxga_write_2(sc, CFREG_CRT_VNDISP, 25 | (8 << 8)); 738 cfxga_write_1(sc, CFREG_CRT_VPULSE, 2); 739 break; 740 } 741 cfxga_write_1(sc, CFREG_CRT_MODE, 742 ri->ri_depth == 16 ? CRT_MODE_16BPP : CRT_MODE_8BPP); 743 cfxga_write_2(sc, CFREG_CRT_START_LOW, 0); 744 cfxga_write_1(sc, CFREG_CRT_START_HIGH, 0); 745 cfxga_write_2(sc, CFREG_CRT_MEMORY, ri->ri_width * ri->ri_depth / 16); 746 cfxga_write_1(sc, CFREG_CRT_PANNING, 0); 747 cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_HIGH, 0); 748 cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_LOW, 0); 749 cfxga_write_1(sc, CFREG_CRT_CURSOR_CONTROL, CURSOR_INACTIVE); 750 751 #ifdef ENABLE_8BIT_MODES 752 /* 753 * On 8bpp video modes, program the LUT 754 */ 755 if (ri->ri_depth == 8) { 756 #if 0 757 /* Wait for retrace */ 758 while ((cfxga_read_1(sc, CFREG_CRT_VNDISP) & 759 CRT_VNDISP_STATUS) == 0) 760 delay(1); 761 #endif 762 cfxga_write_1(sc, CFREG_LUT_MODE, LUT_CRT); 763 cfxga_write_1(sc, CFREG_LUT_ADDRESS, 0); /* autoincrements */ 764 cmap = rasops_cmap; 765 for (i = 256 * 3; i != 0; i--) 766 cfxga_write_1(sc, CFREG_LUT_DATA, *cmap++ & 0xf0); 767 } 768 #endif 769 770 cfxga_write_1(sc, CFREG_TV_CONTROL, 771 TV_LUMINANCE_FILTER | TV_SVIDEO_OUTPUT | TV_NTSC_OUTPUT); 772 773 cfxga_write_1(sc, CFREG_POWER_CONF, POWERSAVE_MBO); 774 cfxga_write_1(sc, CFREG_WATCHDOG, 0); 775 776 cfxga_write_1(sc, CFREG_MODE, MODE_CRT); 777 delay(25000); 778 } 779 780 void 781 cfxga_reset_and_repaint(struct cfxga_softc *sc) 782 { 783 cfxga_reset_video(sc); 784 785 if (sc->sc_active != NULL) 786 cfxga_repaint_screen(sc->sc_active); 787 else 788 cfxga_burner(sc, 0, 0); 789 } 790 791 /* 792 * Wait for the blitter to be in a given state. 793 */ 794 u_int 795 cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result) 796 { 797 u_int tries; 798 799 for (tries = 10000; tries != 0; tries--) { 800 if ((cfxga_read_1(sc, CFREG_BITBLT_CONTROL) & mask) == result) 801 break; 802 delay(10); 803 } 804 805 return (tries); 806 } 807 808 /* 809 * Wait for all pending blitter operations to be complete. 810 * Returns non-zero if the blitter got stuck. 811 */ 812 int 813 cfxga_synchronize(struct cfxga_softc *sc) 814 { 815 /* Wait for previous operations to complete */ 816 if (cfxga_wait(sc, BITBLT_ACTIVE, 0) == 0) { 817 DPRINTF(("%s: not ready\n", __func__)); 818 if (ISSET(sc->sc_state, CS_RESET)) 819 return (EAGAIN); 820 else { 821 DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname)); 822 SET(sc->sc_state, CS_RESET); 823 cfxga_reset_and_repaint(sc); 824 CLR(sc->sc_state, CS_RESET); 825 } 826 } 827 cfxga_stop_memory_blt(sc); 828 return (0); 829 } 830 831 /* 832 * Display a character. 833 */ 834 int 835 cfxga_expand_char(struct cfxga_screen *scr, u_int uc, int x, int y, long attr) 836 { 837 struct cfxga_softc *sc = scr->scr_sc; 838 struct rasops_info *ri = &scr->scr_ri; 839 struct wsdisplay_font *font = ri->ri_font; 840 u_int pos, sts, fifo_avail, chunk; 841 u_int8_t *fontbits; 842 int bg, fg, ul; 843 u_int i; 844 int rc; 845 846 pos = (y * ri->ri_width + x) * ri->ri_depth / 8; 847 fontbits = (u_int8_t *)(font->data + (uc - font->firstchar) * 848 ri->ri_fontscale); 849 ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul); 850 851 /* Wait for previous operations to complete */ 852 if ((rc = cfxga_synchronize(sc)) != 0) 853 return (rc); 854 855 cfxga_write_2(sc, CFREG_COLOR_EXPANSION, 856 ((font->fontwidth - 1) & 7) | (OP_COLOR_EXPANSION << 8)); 857 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, font->fontwidth <= 8 ? 0 : 1); 858 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, 0); 859 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos); 860 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16); 861 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 862 ri->ri_width * ri->ri_depth / 16); 863 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, font->fontwidth - 1); 864 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, font->fontheight - 1); 865 cfxga_write_2(sc, CFREG_BITBLT_FG, ri->ri_devcmap[fg]); 866 cfxga_write_2(sc, CFREG_BITBLT_BG, ri->ri_devcmap[bg]); 867 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 868 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 869 870 if (cfxga_wait(sc, BITBLT_ACTIVE, BITBLT_ACTIVE) == 0) 871 goto fail; /* unlikely */ 872 fifo_avail = 0; 873 874 for (i = font->fontheight; i != 0; i--) { 875 /* 876 * Find out how much words we can feed before 877 * a FIFO check is needed. 878 */ 879 if (fifo_avail == 0) { 880 sts = cfxga_read_1(sc, CFREG_BITBLT_CONTROL); 881 if ((sts & BITBLT_FIFO_NOT_EMPTY) == 0) 882 fifo_avail = font->fontwidth <= 8 ? 2 : 1; 883 else if ((sts & BITBLT_FIFO_HALF_FULL) == 0) 884 fifo_avail = font->fontwidth <= 8 ? 1 : 0; 885 else { 886 /* 887 * Let the cheap breathe for a short while. 888 * If this is not enough to free some FIFO 889 * entries, abort the operation. 890 */ 891 if (cfxga_wait(sc, BITBLT_FIFO_FULL, 0) == 0) 892 goto fail; 893 } 894 } 895 896 if (font->fontwidth <= 8) { 897 chunk = *fontbits; 898 if (ul && i == 1) 899 chunk = 0xff; 900 } else { 901 chunk = *(u_int16_t *)fontbits; 902 if (ul && i == 1) 903 chunk = 0xffff; 904 } 905 cfxga_write_2(sc, CFREG_BITBLT_DATA, chunk); 906 fontbits += font->stride; 907 fifo_avail--; 908 } 909 910 return (0); 911 912 fail: 913 DPRINTF(("%s: abort\n", __func__)); 914 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0); 915 cfxga_stop_memory_blt(sc); 916 return (EINTR); 917 } 918 919 /* 920 * Copy a memory bitmap to the frame buffer. 921 * 922 * This is slow - we only use this to repaint the whole frame buffer on 923 * screen switches. 924 */ 925 int 926 cfxga_repaint_screen(struct cfxga_screen *scr) 927 { 928 struct wsdisplay_charcell *cell = scr->scr_mem; 929 struct rasops_info *ri = &scr->scr_ri; 930 int x, y, cx, cy, lx, ly; 931 int fg, bg; 932 int rc; 933 934 cfxga_clear_screen(scr); 935 936 cx = ri->ri_font->fontwidth; 937 cy = ri->ri_font->fontheight; 938 939 for (ly = 0, y = ri->ri_yorigin; ly < ri->ri_rows; ly++, y += cy) { 940 for (lx = 0, x = ri->ri_xorigin; lx < ri->ri_cols; 941 lx++, x += cx) { 942 if (cell->uc == 0 || cell->uc == ' ') { 943 ri->ri_ops.unpack_attr(ri, cell->attr, 944 &fg, &bg, NULL); 945 rc = cfxga_solid_fill(scr, x, y, cx, cy, 946 ri->ri_devcmap[bg]); 947 } else { 948 rc = cfxga_expand_char(scr, cell->uc, 949 x, y, cell->attr); 950 } 951 cell++; 952 if (rc != 0) 953 return (rc); 954 } 955 } 956 957 return (0); 958 } 959 960 /* 961 * Perform a solid fill operation. 962 */ 963 int 964 cfxga_solid_fill(struct cfxga_screen *scr, int x, int y, int cx, int cy, 965 int32_t srccolor) 966 { 967 struct cfxga_softc *sc = scr->scr_sc; 968 struct rasops_info *ri = &scr->scr_ri; 969 u_int pos; 970 int rc; 971 972 pos = (y * ri->ri_width + x) * ri->ri_depth / 8; 973 974 /* Wait for previous operations to complete */ 975 if ((rc = cfxga_synchronize(sc)) != 0) 976 return (rc); 977 978 cfxga_write_2(sc, CFREG_BITBLT_ROP, 0 | (OP_SOLID_FILL << 8)); 979 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, pos); 980 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, pos >> 16); 981 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos); 982 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16); 983 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 984 ri->ri_width * ri->ri_depth / 16); 985 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1); 986 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1); 987 cfxga_write_2(sc, CFREG_BITBLT_FG, (u_int16_t)srccolor); 988 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 989 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 990 991 return (0); 992 } 993 994 /* 995 * Perform an internal frame buffer operation. 996 */ 997 int 998 cfxga_standalone_rop(struct cfxga_screen *scr, u_int rop, int sx, int sy, 999 int dx, int dy, int cx, int cy) 1000 { 1001 struct cfxga_softc *sc = scr->scr_sc; 1002 struct rasops_info *ri = &scr->scr_ri; 1003 u_int srcpos, dstpos; 1004 u_int opcode; 1005 int rc; 1006 1007 srcpos = (sy * ri->ri_width + sx) * ri->ri_depth / 8; 1008 dstpos = (dy * ri->ri_width + dx) * ri->ri_depth / 8; 1009 1010 if (dstpos <= srcpos) 1011 opcode = (OP_MOVE_POSITIVE_ROP << 8) | rop; 1012 else 1013 opcode = (OP_MOVE_NEGATIVE_ROP << 8) | rop; 1014 1015 /* Wait for previous operations to complete */ 1016 if ((rc = cfxga_synchronize(sc)) != 0) 1017 return (rc); 1018 1019 cfxga_write_2(sc, CFREG_BITBLT_ROP, opcode); 1020 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, srcpos); 1021 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, srcpos >> 16); 1022 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, dstpos); 1023 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, dstpos >> 16); 1024 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 1025 ri->ri_width * ri->ri_depth / 16); 1026 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1); 1027 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1); 1028 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 1029 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 1030 1031 return (0); 1032 } 1033 1034 /* 1035 * Text console raster operations. 1036 * 1037 * We shadow all these operations on a memory copy of the frame buffer. 1038 * Since we are running in emulation mode only, this could be optimized 1039 * by only storing actual character cell values (a la mda). 1040 */ 1041 1042 int 1043 cfxga_copycols(void *cookie, int row, int src, int dst, int num) 1044 { 1045 struct rasops_info *ri = cookie; 1046 struct cfxga_screen *scr = ri->ri_hw; 1047 int sx, dx, y, cx, cy; 1048 1049 /* Copy columns in backing store. */ 1050 ovbcopy(scr->scr_mem + row * ri->ri_cols + src, 1051 scr->scr_mem + row * ri->ri_cols + dst, 1052 num * sizeof(struct wsdisplay_charcell)); 1053 1054 if (scr != scr->scr_sc->sc_active) 1055 return 0; 1056 1057 sx = src * ri->ri_font->fontwidth + ri->ri_xorigin; 1058 dx = dst * ri->ri_font->fontwidth + ri->ri_xorigin; 1059 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1060 cx = num * ri->ri_font->fontwidth; 1061 cy = ri->ri_font->fontheight; 1062 return cfxga_standalone_rop(scr, ROP_SRC, sx, y, dx, y, cx, cy); 1063 } 1064 1065 int 1066 cfxga_copyrows(void *cookie, int src, int dst, int num) 1067 { 1068 struct rasops_info *ri = cookie; 1069 struct cfxga_screen *scr = ri->ri_hw; 1070 int x, sy, dy, cx, cy; 1071 1072 /* Copy rows in backing store. */ 1073 ovbcopy(scr->scr_mem + src * ri->ri_cols, 1074 scr->scr_mem + dst * ri->ri_cols, 1075 num * ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1076 1077 if (scr != scr->scr_sc->sc_active) 1078 return 0; 1079 1080 x = ri->ri_xorigin; 1081 sy = src * ri->ri_font->fontheight + ri->ri_yorigin; 1082 dy = dst * ri->ri_font->fontheight + ri->ri_yorigin; 1083 cx = ri->ri_emuwidth; 1084 cy = num * ri->ri_font->fontheight; 1085 return cfxga_standalone_rop(scr, ROP_SRC, x, sy, x, dy, cx, cy); 1086 } 1087 1088 int 1089 cfxga_do_cursor(struct rasops_info *ri) 1090 { 1091 struct cfxga_screen *scr = ri->ri_hw; 1092 int x, y, cx, cy; 1093 1094 if (scr != scr->scr_sc->sc_active) 1095 return 0; 1096 1097 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 1098 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 1099 cx = ri->ri_font->fontwidth; 1100 cy = ri->ri_font->fontheight; 1101 return cfxga_standalone_rop(scr, ROP_ONES ^ ROP_SRC /* i.e. not SRC */, 1102 x, y, x, y, cx, cy); 1103 } 1104 1105 int 1106 cfxga_erasecols(void *cookie, int row, int col, int num, long attr) 1107 { 1108 struct rasops_info *ri = cookie; 1109 struct cfxga_screen *scr = ri->ri_hw; 1110 int fg, bg; 1111 int x, y, cx, cy; 1112 1113 /* Erase columns in backing store. */ 1114 for (x = col; x < col + num; x++) { 1115 scr->scr_mem[row * ri->ri_cols + x].uc = 0; 1116 scr->scr_mem[row * ri->ri_cols + x].attr = attr; 1117 } 1118 1119 if (scr != scr->scr_sc->sc_active) 1120 return 0; 1121 1122 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1123 x = col * ri->ri_font->fontwidth + ri->ri_xorigin; 1124 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1125 cx = num * ri->ri_font->fontwidth; 1126 cy = ri->ri_font->fontheight; 1127 return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1128 } 1129 1130 int 1131 cfxga_eraserows(void *cookie, int row, int num, long attr) 1132 { 1133 struct rasops_info *ri = cookie; 1134 struct cfxga_screen *scr = ri->ri_hw; 1135 int fg, bg; 1136 int x, y, cx, cy; 1137 1138 /* Erase rows in backing store. */ 1139 for (x = 0; x < ri->ri_cols; x++) { 1140 scr->scr_mem[row * ri->ri_cols + x].uc = 0; 1141 scr->scr_mem[row * ri->ri_cols + x].attr = attr; 1142 } 1143 for (y = 1; y < num; y++) 1144 ovbcopy(scr->scr_mem + row * ri->ri_cols, 1145 scr->scr_mem + (row + y) * ri->ri_cols, 1146 ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1147 1148 if (scr != scr->scr_sc->sc_active) 1149 return 0; 1150 1151 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1152 x = ri->ri_xorigin; 1153 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1154 cx = ri->ri_emuwidth; 1155 cy = num * ri->ri_font->fontheight; 1156 return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1157 } 1158 1159 int 1160 cfxga_putchar(void *cookie, int row, int col, u_int uc, long attr) 1161 { 1162 struct rasops_info *ri = cookie; 1163 struct cfxga_screen *scr = ri->ri_hw; 1164 int x, y; 1165 1166 scr->scr_mem[row * ri->ri_cols + col].uc = uc; 1167 scr->scr_mem[row * ri->ri_cols + col].attr = attr; 1168 1169 if (scr != scr->scr_sc->sc_active) 1170 return 0; 1171 1172 x = col * ri->ri_font->fontwidth + ri->ri_xorigin; 1173 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1174 1175 if (uc == ' ') { 1176 int cx, cy, fg, bg; 1177 1178 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1179 cx = ri->ri_font->fontwidth; 1180 cy = ri->ri_font->fontheight; 1181 return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1182 } else { 1183 return cfxga_expand_char(scr, uc, x, y, attr); 1184 } 1185 } 1186