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