1 /* $OpenBSD: cfxga.c,v 1.31 2020/05/25 09:55:49 jsg 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 *, uint32_t *); 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, uint32_t); 148 int cfxga_eraserows(void *, int, int, uint32_t); 149 int cfxga_putchar(void *, int, int, u_int, uint32_t); 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, uint32_t); 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, uint32_t *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 scr->scr_mem = mallocarray(ri->ri_rows, 505 ri->ri_cols * sizeof(struct wsdisplay_charcell), 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 scrsize = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell); 512 513 ri->ri_ops.copycols = cfxga_copycols; 514 ri->ri_ops.copyrows = cfxga_copyrows; 515 ri->ri_ops.erasecols = cfxga_erasecols; 516 ri->ri_ops.eraserows = cfxga_eraserows; 517 ri->ri_ops.putchar = cfxga_putchar; 518 ri->ri_do_cursor = cfxga_do_cursor; 519 520 /* 521 * Finish initializing our screen descriptions, now that we know 522 * the actual console emulation parameters. 523 */ 524 if (type->nrows == 0) { 525 struct wsscreen_descr *wsd = (struct wsscreen_descr *)type; 526 527 wsd->nrows = ri->ri_rows; 528 wsd->ncols = ri->ri_cols; 529 bcopy(&ri->ri_ops, &sc->sc_ops, sizeof(sc->sc_ops)); 530 wsd->fontwidth = ri->ri_font->fontwidth; 531 wsd->fontheight = ri->ri_font->fontheight; 532 wsd->capabilities = ri->ri_caps; 533 } 534 535 scr->scr_sc = sc; 536 LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link); 537 sc->sc_nscreens++; 538 539 ri->ri_ops.pack_attr(ri, 0, 0, 0, attrp); 540 541 *cookiep = ri; 542 *curxp = *curyp = 0; 543 544 return (0); 545 } 546 547 void 548 cfxga_burner(void *v, u_int on, u_int flags) 549 { 550 struct cfxga_softc *sc = (void *)v; 551 u_int8_t mode; 552 553 mode = cfxga_read_1(sc, CFREG_MODE) & LCD_MODE_SWIVEL_BIT_0; 554 555 if (on) 556 cfxga_write_1(sc, CFREG_MODE, mode | MODE_CRT); 557 else 558 cfxga_write_1(sc, CFREG_MODE, mode | MODE_NO_DISPLAY); 559 } 560 561 void 562 cfxga_free_screen(void *v, void *cookie) 563 { 564 struct cfxga_softc *sc = v; 565 struct rasops_info *ri = cookie; 566 struct cfxga_screen *scr = ri->ri_hw; 567 568 LIST_REMOVE(scr, scr_link); 569 sc->sc_nscreens--; 570 571 if (scr == sc->sc_active) { 572 sc->sc_active = NULL; 573 cfxga_burner(sc, 0, 0); 574 } 575 576 free(scr->scr_mem, M_DEVBUF, 0); 577 free(scr, M_DEVBUF, 0); 578 } 579 580 int 581 cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 582 { 583 struct cfxga_softc *sc = v; 584 struct cfxga_screen *scr; 585 struct wsdisplay_fbinfo *wdf; 586 int mode; 587 588 switch (cmd) { 589 case WSDISPLAYIO_GTYPE: 590 *(u_int *)data = WSDISPLAY_TYPE_CFXGA; 591 break; 592 593 case WSDISPLAYIO_GINFO: 594 wdf = (struct wsdisplay_fbinfo *)data; 595 scr = sc->sc_active; 596 if (scr == NULL) { 597 /* try later...after running wsconscfg to add screens */ 598 wdf->height = wdf->width = wdf->depth = wdf->cmsize = 0; 599 } else { 600 wdf->height = scr->scr_ri.ri_height; 601 wdf->width = scr->scr_ri.ri_width; 602 wdf->depth = scr->scr_ri.ri_depth; 603 wdf->cmsize = scr->scr_ri.ri_depth <= 8 ? 604 (1 << scr->scr_ri.ri_depth) : 0; 605 } 606 break; 607 608 case WSDISPLAYIO_SMODE: 609 mode = *(u_int *)data; 610 if (mode == sc->sc_mode) 611 break; 612 switch (mode) { 613 case WSDISPLAYIO_MODE_EMUL: 614 cfxga_reset_and_repaint(sc); 615 break; 616 case WSDISPLAYIO_MODE_MAPPED: 617 break; 618 default: 619 return (EINVAL); 620 } 621 sc->sc_mode = mode; 622 break; 623 624 /* these operations are handled by the wscons code... */ 625 case WSDISPLAYIO_GVIDEO: 626 case WSDISPLAYIO_SVIDEO: 627 break; 628 629 /* these operations are not supported... */ 630 case WSDISPLAYIO_GETCMAP: 631 case WSDISPLAYIO_PUTCMAP: 632 case WSDISPLAYIO_LINEBYTES: 633 case WSDISPLAYIO_GCURPOS: 634 case WSDISPLAYIO_SCURPOS: 635 case WSDISPLAYIO_GCURMAX: 636 case WSDISPLAYIO_GCURSOR: 637 case WSDISPLAYIO_SCURSOR: 638 default: 639 return (-1); 640 } 641 642 return (0); 643 } 644 645 paddr_t 646 cfxga_mmap(void *v, off_t off, int prot) 647 { 648 return (-1); 649 } 650 651 int 652 cfxga_show_screen(void *v, void *cookie, int waitok, 653 void (*cb)(void *, int, int), void *cbarg) 654 { 655 struct cfxga_softc *sc = v; 656 struct rasops_info *ri = cookie; 657 struct cfxga_screen *scr = ri->ri_hw, *old; 658 659 old = sc->sc_active; 660 if (old == scr) 661 return (0); 662 663 sc->sc_active = scr; 664 cfxga_reset_and_repaint(sc); /* will turn video on if scr != NULL */ 665 666 return (0); 667 } 668 669 int 670 cfxga_load_font(void *v, void *emulcookie, struct wsdisplay_font *font) 671 { 672 struct cfxga_softc *sc = v; 673 struct cfxga_screen *scr = sc->sc_active; 674 675 if (scr == NULL) 676 return ENXIO; 677 678 return rasops_load_font(&scr->scr_ri, emulcookie, font); 679 } 680 681 int 682 cfxga_list_font(void *v, struct wsdisplay_font *font) 683 { 684 struct cfxga_softc *sc = v; 685 struct cfxga_screen *scr = sc->sc_active; 686 687 if (scr == NULL) 688 return ENXIO; 689 690 return rasops_list_font(&scr->scr_ri, font); 691 } 692 693 /* 694 * Real frame buffer operations 695 */ 696 697 void 698 cfxga_reset_video(struct cfxga_softc *sc) 699 { 700 struct cfxga_screen *scr = sc->sc_active; 701 struct rasops_info *ri; 702 #ifdef ENABLE_8BIT_MODES 703 const u_int8_t *cmap; 704 u_int i; 705 #endif 706 707 /* 708 * Reset controller 709 */ 710 711 /* need to write to both REV and MISC at the same time */ 712 cfxga_write_2(sc, CFREG_REV, 0x80 | (CM_REGSEL << 8)); 713 delay(25000); /* maintain reset for a short while */ 714 /* need to write to both REV and MISC at the same time */ 715 cfxga_write_2(sc, CFREG_REV, 0 | (CM_MEMSEL << 8)); 716 delay(25000); 717 /* stop any pending blt operation */ 718 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0); 719 cfxga_stop_memory_blt(sc); 720 cfxga_write_1(sc, CFREG_MODE, 0); /* disable all displays */ 721 722 /* 723 * Setup common video mode parameters. 724 */ 725 726 cfxga_write_2(sc, CFREG_MEMCLK, MEMCLK_SRC_CLK3); 727 #if 0 728 cfxga_write_1(sc, CFREG_LCD_PCLK, LCD_PCLK_SRC_CLKI | LCD_PCLK_DIV_1); 729 cfxga_write_1(sc, CFREG_MPLUG_CLK, 730 MPLUG_PCLK_SRC_CLKI2 | MPLUG_PCLK_DIV_1); 731 #endif 732 cfxga_write_2(sc, CFREG_CRTTV_PCLK, CRT_PCLK_SRC_CLKI | CRT_PCLK_DIV_1); 733 cfxga_write_2(sc, CFREG_WSTATE, WSTATE_MCLK); 734 735 /* MEMCNF and DRAM_RFRSH need to be programmed at the same time */ 736 cfxga_write_2(sc, CFREG_MEMCNF, 737 MEMCNF_SDRAM_INIT | (DRAM_RFRSH_50MHZ << 8)); 738 delay(250); 739 cfxga_write_2(sc, CFREG_DRAM_TIMING, DRAM_TIMING_50MHZ); 740 741 /* 742 * Setup mode-dependent parameters. 743 */ 744 if (scr == NULL) 745 return; 746 747 ri = &scr->scr_ri; 748 switch (scr->scr_ri.ri_width) { 749 default: 750 case 640: 751 cfxga_write_1(sc, CFREG_CRT_HWIDTH, (640 / 8) - 1); 752 /* HNDISP and HSTART need to be programmed at the same time */ 753 cfxga_write_2(sc, CFREG_CRT_HNDISP, 23 | (2 << 8)); 754 cfxga_write_1(sc, CFREG_CRT_HPULSE, 4); 755 cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 480 - 1); 756 /* VNDISP and VSTART need to be programmed at the same time */ 757 cfxga_write_2(sc, CFREG_CRT_VNDISP, 39 | (8 << 8)); 758 cfxga_write_1(sc, CFREG_CRT_VPULSE, 2); 759 break; 760 case 800: 761 cfxga_write_1(sc, CFREG_CRT_HWIDTH, (800 / 8) - 1); 762 /* HNDISP and HSTART need to be programmed at the same time */ 763 cfxga_write_2(sc, CFREG_CRT_HNDISP, 27 | (2 << 8)); 764 cfxga_write_1(sc, CFREG_CRT_HPULSE, 4); 765 cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 600 - 1); 766 /* VNDISP and VSTART need to be programmed at the same time */ 767 cfxga_write_2(sc, CFREG_CRT_VNDISP, 25 | (8 << 8)); 768 cfxga_write_1(sc, CFREG_CRT_VPULSE, 2); 769 break; 770 } 771 cfxga_write_1(sc, CFREG_CRT_MODE, 772 ri->ri_depth == 16 ? CRT_MODE_16BPP : CRT_MODE_8BPP); 773 cfxga_write_2(sc, CFREG_CRT_START_LOW, 0); 774 cfxga_write_1(sc, CFREG_CRT_START_HIGH, 0); 775 cfxga_write_2(sc, CFREG_CRT_MEMORY, ri->ri_width * ri->ri_depth / 16); 776 cfxga_write_1(sc, CFREG_CRT_PANNING, 0); 777 cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_HIGH, 0); 778 cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_LOW, 0); 779 cfxga_write_1(sc, CFREG_CRT_CURSOR_CONTROL, CURSOR_INACTIVE); 780 781 #ifdef ENABLE_8BIT_MODES 782 /* 783 * On 8bpp video modes, program the LUT 784 */ 785 if (ri->ri_depth == 8) { 786 #if 0 787 /* Wait for retrace */ 788 while ((cfxga_read_1(sc, CFREG_CRT_VNDISP) & 789 CRT_VNDISP_STATUS) == 0) 790 delay(1); 791 #endif 792 cfxga_write_1(sc, CFREG_LUT_MODE, LUT_CRT); 793 cfxga_write_1(sc, CFREG_LUT_ADDRESS, 0); /* autoincrements */ 794 cmap = rasops_cmap; 795 for (i = 256 * 3; i != 0; i--) 796 cfxga_write_1(sc, CFREG_LUT_DATA, *cmap++ & 0xf0); 797 } 798 #endif 799 800 cfxga_write_1(sc, CFREG_TV_CONTROL, 801 TV_LUMINANCE_FILTER | TV_SVIDEO_OUTPUT | TV_NTSC_OUTPUT); 802 803 cfxga_write_1(sc, CFREG_POWER_CONF, POWERSAVE_MBO); 804 cfxga_write_1(sc, CFREG_WATCHDOG, 0); 805 806 cfxga_write_1(sc, CFREG_MODE, MODE_CRT); 807 delay(25000); 808 } 809 810 void 811 cfxga_reset_and_repaint(struct cfxga_softc *sc) 812 { 813 cfxga_reset_video(sc); 814 815 if (sc->sc_active != NULL) 816 cfxga_repaint_screen(sc->sc_active); 817 else 818 cfxga_burner(sc, 0, 0); 819 } 820 821 /* 822 * Wait for the blitter to be in a given state. 823 */ 824 u_int 825 cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result) 826 { 827 u_int tries; 828 829 for (tries = 10000; tries != 0; tries--) { 830 if ((cfxga_read_1(sc, CFREG_BITBLT_CONTROL) & mask) == result) 831 break; 832 delay(10); 833 } 834 835 return (tries); 836 } 837 838 /* 839 * Wait for all pending blitter operations to be complete. 840 * Returns non-zero if the blitter got stuck. 841 */ 842 int 843 cfxga_synchronize(struct cfxga_softc *sc) 844 { 845 /* Wait for previous operations to complete */ 846 if (cfxga_wait(sc, BITBLT_ACTIVE, 0) == 0) { 847 DPRINTF(("%s: not ready\n", __func__)); 848 if (ISSET(sc->sc_state, CS_RESET)) 849 return (EAGAIN); 850 else { 851 DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname)); 852 SET(sc->sc_state, CS_RESET); 853 cfxga_reset_and_repaint(sc); 854 CLR(sc->sc_state, CS_RESET); 855 } 856 } 857 cfxga_stop_memory_blt(sc); 858 return (0); 859 } 860 861 /* 862 * Display a character. 863 */ 864 int 865 cfxga_expand_char(struct cfxga_screen *scr, u_int uc, int x, int y, 866 uint32_t attr) 867 { 868 struct cfxga_softc *sc = scr->scr_sc; 869 struct rasops_info *ri = &scr->scr_ri; 870 struct wsdisplay_font *font = ri->ri_font; 871 u_int pos, sts, fifo_avail, chunk; 872 u_int8_t *fontbits; 873 int bg, fg, ul; 874 u_int i; 875 int rc; 876 877 pos = (y * ri->ri_width + x) * ri->ri_depth / 8; 878 fontbits = (u_int8_t *)(font->data + (uc - font->firstchar) * 879 ri->ri_fontscale); 880 ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul); 881 882 /* Wait for previous operations to complete */ 883 if ((rc = cfxga_synchronize(sc)) != 0) 884 return (rc); 885 886 cfxga_write_2(sc, CFREG_COLOR_EXPANSION, 887 ((font->fontwidth - 1) & 7) | (OP_COLOR_EXPANSION << 8)); 888 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, font->fontwidth <= 8 ? 0 : 1); 889 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, 0); 890 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos); 891 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16); 892 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 893 ri->ri_width * ri->ri_depth / 16); 894 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, font->fontwidth - 1); 895 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, font->fontheight - 1); 896 cfxga_write_2(sc, CFREG_BITBLT_FG, ri->ri_devcmap[fg]); 897 cfxga_write_2(sc, CFREG_BITBLT_BG, ri->ri_devcmap[bg]); 898 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 899 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 900 901 if (cfxga_wait(sc, BITBLT_ACTIVE, BITBLT_ACTIVE) == 0) 902 goto fail; /* unlikely */ 903 fifo_avail = 0; 904 905 for (i = font->fontheight; i != 0; i--) { 906 /* 907 * Find out how much words we can feed before 908 * a FIFO check is needed. 909 */ 910 if (fifo_avail == 0) { 911 sts = cfxga_read_1(sc, CFREG_BITBLT_CONTROL); 912 if ((sts & BITBLT_FIFO_NOT_EMPTY) == 0) 913 fifo_avail = font->fontwidth <= 8 ? 2 : 1; 914 else if ((sts & BITBLT_FIFO_HALF_FULL) == 0) 915 fifo_avail = font->fontwidth <= 8 ? 1 : 0; 916 else { 917 /* 918 * Let the cheap breathe for a short while. 919 * If this is not enough to free some FIFO 920 * entries, abort the operation. 921 */ 922 if (cfxga_wait(sc, BITBLT_FIFO_FULL, 0) == 0) 923 goto fail; 924 } 925 } 926 927 if (font->fontwidth <= 8) { 928 chunk = *fontbits; 929 if (ul && i == 1) 930 chunk = 0xff; 931 } else { 932 chunk = *(u_int16_t *)fontbits; 933 if (ul && i == 1) 934 chunk = 0xffff; 935 } 936 cfxga_write_2(sc, CFREG_BITBLT_DATA, chunk); 937 fontbits += font->stride; 938 fifo_avail--; 939 } 940 941 return (0); 942 943 fail: 944 DPRINTF(("%s: abort\n", __func__)); 945 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0); 946 cfxga_stop_memory_blt(sc); 947 return (EINTR); 948 } 949 950 /* 951 * Copy a memory bitmap to the frame buffer. 952 * 953 * This is slow - we only use this to repaint the whole frame buffer on 954 * screen switches. 955 */ 956 int 957 cfxga_repaint_screen(struct cfxga_screen *scr) 958 { 959 struct wsdisplay_charcell *cell = scr->scr_mem; 960 struct rasops_info *ri = &scr->scr_ri; 961 int x, y, cx, cy, lx, ly; 962 int fg, bg; 963 int rc; 964 965 cfxga_clear_screen(scr); 966 967 cx = ri->ri_font->fontwidth; 968 cy = ri->ri_font->fontheight; 969 970 for (ly = 0, y = ri->ri_yorigin; ly < ri->ri_rows; ly++, y += cy) { 971 for (lx = 0, x = ri->ri_xorigin; lx < ri->ri_cols; 972 lx++, x += cx) { 973 if (cell->uc == 0 || cell->uc == ' ') { 974 ri->ri_ops.unpack_attr(ri, cell->attr, 975 &fg, &bg, NULL); 976 rc = cfxga_solid_fill(scr, x, y, cx, cy, 977 ri->ri_devcmap[bg]); 978 } else { 979 rc = cfxga_expand_char(scr, cell->uc, 980 x, y, cell->attr); 981 } 982 cell++; 983 if (rc != 0) 984 return (rc); 985 } 986 } 987 988 return (0); 989 } 990 991 /* 992 * Perform a solid fill operation. 993 */ 994 int 995 cfxga_solid_fill(struct cfxga_screen *scr, int x, int y, int cx, int cy, 996 int32_t srccolor) 997 { 998 struct cfxga_softc *sc = scr->scr_sc; 999 struct rasops_info *ri = &scr->scr_ri; 1000 u_int pos; 1001 int rc; 1002 1003 pos = (y * ri->ri_width + x) * ri->ri_depth / 8; 1004 1005 /* Wait for previous operations to complete */ 1006 if ((rc = cfxga_synchronize(sc)) != 0) 1007 return (rc); 1008 1009 cfxga_write_2(sc, CFREG_BITBLT_ROP, 0 | (OP_SOLID_FILL << 8)); 1010 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, pos); 1011 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, pos >> 16); 1012 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos); 1013 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16); 1014 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 1015 ri->ri_width * ri->ri_depth / 16); 1016 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1); 1017 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1); 1018 cfxga_write_2(sc, CFREG_BITBLT_FG, (u_int16_t)srccolor); 1019 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 1020 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 1021 1022 return (0); 1023 } 1024 1025 /* 1026 * Perform an internal frame buffer operation. 1027 */ 1028 int 1029 cfxga_standalone_rop(struct cfxga_screen *scr, u_int rop, int sx, int sy, 1030 int dx, int dy, int cx, int cy) 1031 { 1032 struct cfxga_softc *sc = scr->scr_sc; 1033 struct rasops_info *ri = &scr->scr_ri; 1034 u_int srcpos, dstpos; 1035 u_int opcode; 1036 int rc; 1037 1038 srcpos = (sy * ri->ri_width + sx) * ri->ri_depth / 8; 1039 dstpos = (dy * ri->ri_width + dx) * ri->ri_depth / 8; 1040 1041 if (dstpos <= srcpos) 1042 opcode = (OP_MOVE_POSITIVE_ROP << 8) | rop; 1043 else 1044 opcode = (OP_MOVE_NEGATIVE_ROP << 8) | rop; 1045 1046 /* Wait for previous operations to complete */ 1047 if ((rc = cfxga_synchronize(sc)) != 0) 1048 return (rc); 1049 1050 cfxga_write_2(sc, CFREG_BITBLT_ROP, opcode); 1051 cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, srcpos); 1052 cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, srcpos >> 16); 1053 cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, dstpos); 1054 cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, dstpos >> 16); 1055 cfxga_write_2(sc, CFREG_BITBLT_OFFSET, 1056 ri->ri_width * ri->ri_depth / 16); 1057 cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1); 1058 cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1); 1059 cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE | 1060 (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8)); 1061 1062 return (0); 1063 } 1064 1065 /* 1066 * Text console raster operations. 1067 * 1068 * We shadow all these operations on a memory copy of the frame buffer. 1069 * Since we are running in emulation mode only, this could be optimized 1070 * by only storing actual character cell values (a la mda). 1071 */ 1072 1073 int 1074 cfxga_copycols(void *cookie, int row, int src, int dst, int num) 1075 { 1076 struct rasops_info *ri = cookie; 1077 struct cfxga_screen *scr = ri->ri_hw; 1078 int sx, dx, y, cx, cy; 1079 1080 /* Copy columns in backing store. */ 1081 memmove(scr->scr_mem + row * ri->ri_cols + dst, 1082 scr->scr_mem + row * ri->ri_cols + src, 1083 num * sizeof(struct wsdisplay_charcell)); 1084 1085 if (scr != scr->scr_sc->sc_active) 1086 return 0; 1087 1088 sx = src * ri->ri_font->fontwidth + ri->ri_xorigin; 1089 dx = dst * ri->ri_font->fontwidth + ri->ri_xorigin; 1090 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1091 cx = num * ri->ri_font->fontwidth; 1092 cy = ri->ri_font->fontheight; 1093 return cfxga_standalone_rop(scr, ROP_SRC, sx, y, dx, y, cx, cy); 1094 } 1095 1096 int 1097 cfxga_copyrows(void *cookie, int src, int dst, int num) 1098 { 1099 struct rasops_info *ri = cookie; 1100 struct cfxga_screen *scr = ri->ri_hw; 1101 int x, sy, dy, cx, cy; 1102 1103 /* Copy rows in backing store. */ 1104 memmove(scr->scr_mem + dst * ri->ri_cols, 1105 scr->scr_mem + src * ri->ri_cols, 1106 num * ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1107 1108 if (scr != scr->scr_sc->sc_active) 1109 return 0; 1110 1111 x = ri->ri_xorigin; 1112 sy = src * ri->ri_font->fontheight + ri->ri_yorigin; 1113 dy = dst * ri->ri_font->fontheight + ri->ri_yorigin; 1114 cx = ri->ri_emuwidth; 1115 cy = num * ri->ri_font->fontheight; 1116 return cfxga_standalone_rop(scr, ROP_SRC, x, sy, x, dy, cx, cy); 1117 } 1118 1119 int 1120 cfxga_do_cursor(struct rasops_info *ri) 1121 { 1122 struct cfxga_screen *scr = ri->ri_hw; 1123 int x, y, cx, cy; 1124 1125 if (scr != scr->scr_sc->sc_active) 1126 return 0; 1127 1128 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 1129 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 1130 cx = ri->ri_font->fontwidth; 1131 cy = ri->ri_font->fontheight; 1132 return cfxga_standalone_rop(scr, ROP_ONES ^ ROP_SRC /* i.e. not SRC */, 1133 x, y, x, y, cx, cy); 1134 } 1135 1136 int 1137 cfxga_erasecols(void *cookie, int row, int col, int num, uint32_t attr) 1138 { 1139 struct rasops_info *ri = cookie; 1140 struct cfxga_screen *scr = ri->ri_hw; 1141 int fg, bg; 1142 int x, y, cx, cy; 1143 1144 /* Erase columns in backing store. */ 1145 for (x = col; x < col + num; x++) { 1146 scr->scr_mem[row * ri->ri_cols + x].uc = 0; 1147 scr->scr_mem[row * ri->ri_cols + x].attr = attr; 1148 } 1149 1150 if (scr != scr->scr_sc->sc_active) 1151 return 0; 1152 1153 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1154 x = col * ri->ri_font->fontwidth + ri->ri_xorigin; 1155 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1156 cx = num * ri->ri_font->fontwidth; 1157 cy = ri->ri_font->fontheight; 1158 return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1159 } 1160 1161 int 1162 cfxga_eraserows(void *cookie, int row, int num, uint32_t attr) 1163 { 1164 struct rasops_info *ri = cookie; 1165 struct cfxga_screen *scr = ri->ri_hw; 1166 int fg, bg; 1167 int x, y, cx, cy; 1168 1169 /* Erase rows in backing store. */ 1170 for (x = 0; x < ri->ri_cols; x++) { 1171 scr->scr_mem[row * ri->ri_cols + x].uc = 0; 1172 scr->scr_mem[row * ri->ri_cols + x].attr = attr; 1173 } 1174 for (y = 1; y < num; y++) 1175 memmove(scr->scr_mem + (row + y) * ri->ri_cols, 1176 scr->scr_mem + row * ri->ri_cols, 1177 ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1178 1179 if (scr != scr->scr_sc->sc_active) 1180 return 0; 1181 1182 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1183 x = ri->ri_xorigin; 1184 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1185 cx = ri->ri_emuwidth; 1186 cy = num * ri->ri_font->fontheight; 1187 return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1188 } 1189 1190 int 1191 cfxga_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr) 1192 { 1193 struct rasops_info *ri = cookie; 1194 struct cfxga_screen *scr = ri->ri_hw; 1195 int x, y; 1196 1197 scr->scr_mem[row * ri->ri_cols + col].uc = uc; 1198 scr->scr_mem[row * ri->ri_cols + col].attr = attr; 1199 1200 if (scr != scr->scr_sc->sc_active) 1201 return 0; 1202 1203 x = col * ri->ri_font->fontwidth + ri->ri_xorigin; 1204 y = row * ri->ri_font->fontheight + ri->ri_yorigin; 1205 1206 if (uc == ' ') { 1207 int cx, cy, fg, bg; 1208 1209 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 1210 cx = ri->ri_font->fontwidth; 1211 cy = ri->ri_font->fontheight; 1212 return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]); 1213 } else { 1214 return cfxga_expand_char(scr, uc, x, y, attr); 1215 } 1216 } 1217