1 /* $NetBSD: ffb.c,v 1.41 2011/05/09 09:06:28 jdc Exp $ */ 2 /* $OpenBSD: creator.c,v 1.20 2002/07/30 19:48:15 jason Exp $ */ 3 4 /* 5 * Copyright (c) 2002 Jason L. Wright (jason@thought.net) 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Jason L. Wright 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: ffb.c,v 1.41 2011/05/09 09:06:28 jdc Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/device.h> 43 #include <sys/conf.h> 44 #include <sys/ioctl.h> 45 #include <sys/malloc.h> 46 #include <sys/mman.h> 47 48 #include <machine/bus.h> 49 #include <machine/autoconf.h> 50 #include <machine/openfirm.h> 51 #include <machine/vmparam.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/sun/fbio.h> 55 #include <dev/sun/fbvar.h> 56 57 #include <dev/wsfont/wsfont.h> 58 #include <dev/wscons/wsdisplay_vconsvar.h> 59 60 #include <dev/i2c/i2cvar.h> 61 #include <dev/i2c/i2c_bitbang.h> 62 #include <dev/i2c/ddcvar.h> 63 64 #include <sparc64/dev/ffbreg.h> 65 #include <sparc64/dev/ffbvar.h> 66 67 #include "opt_wsdisplay_compat.h" 68 #include "opt_ffb.h" 69 70 #ifndef WS_DEFAULT_BG 71 /* Sun -> background should be white */ 72 #define WS_DEFAULT_BG 0xf 73 #endif 74 75 #ifdef FFB_SYNC 76 #define SYNC ffb_ras_wait(sc) 77 #else 78 #define SYNC 79 #endif 80 81 /* Debugging */ 82 #if !defined FFB_DEBUG 83 #define FFB_DEBUG 0 84 #endif 85 #define DPRINTF(x) if (ffb_debug) printf x 86 /* Patchable */ 87 extern int ffb_debug; 88 #if FFB_DEBUG > 0 89 int ffb_debug = 1; 90 #else 91 int ffb_debug = 0; 92 #endif 93 94 extern struct cfdriver ffb_cd; 95 96 struct wsscreen_descr ffb_stdscreen = { 97 "sunffb", 98 0, 0, /* will be filled in -- XXX shouldn't, it's global. */ 99 0, 100 0, 0, 101 WSSCREEN_REVERSE | WSSCREEN_WSCOLORS, 102 NULL /* modecookie */ 103 }; 104 105 const struct wsscreen_descr *ffb_scrlist[] = { 106 &ffb_stdscreen, 107 /* XXX other formats? */ 108 }; 109 110 struct wsscreen_list ffb_screenlist = { 111 sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *), 112 ffb_scrlist 113 }; 114 115 static struct vcons_screen ffb_console_screen; 116 117 int ffb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 118 static int ffb_blank(struct ffb_softc *, u_long, u_int *); 119 paddr_t ffb_mmap(void *, void *, off_t, int); 120 void ffb_ras_fifo_wait(struct ffb_softc *, int); 121 void ffb_ras_wait(struct ffb_softc *); 122 void ffb_ras_init(struct ffb_softc *); 123 void ffb_ras_copyrows(void *, int, int, int); 124 void ffb_ras_erasecols(void *, int, int, int, long int); 125 void ffb_ras_eraserows(void *, int, int, long int); 126 void ffb_ras_do_cursor(struct rasops_info *); 127 void ffb_ras_fill(struct ffb_softc *); 128 static void ffb_ras_setfg(struct ffb_softc *, int32_t); 129 static void ffb_ras_setbg(struct ffb_softc *, int32_t); 130 131 void ffb_clearscreen(struct ffb_softc *); 132 int ffb_load_font(void *, void *, struct wsdisplay_font *); 133 void ffb_init_screen(void *, struct vcons_screen *, int, 134 long *); 135 int ffb_allocattr(void *, int, int, int, long *); 136 void ffb_putchar(void *, int, int, u_int, long); 137 void ffb_cursor(void *, int, int, int); 138 139 /* frame buffer generic driver */ 140 static void ffbfb_unblank(struct device*); 141 dev_type_open(ffbfb_open); 142 dev_type_close(ffbfb_close); 143 dev_type_ioctl(ffbfb_ioctl); 144 dev_type_mmap(ffbfb_mmap); 145 146 static struct fbdriver ffb_fbdriver = { 147 ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll, 148 ffbfb_mmap, nokqfilter 149 }; 150 151 struct wsdisplay_accessops ffb_accessops = { 152 .ioctl = ffb_ioctl, 153 .mmap = ffb_mmap, 154 }; 155 156 /* I2C glue */ 157 static int ffb_i2c_acquire_bus(void *, int); 158 static void ffb_i2c_release_bus(void *, int); 159 static int ffb_i2c_send_start(void *, int); 160 static int ffb_i2c_send_stop(void *, int); 161 static int ffb_i2c_initiate_xfer(void *, i2c_addr_t, int); 162 static int ffb_i2c_read_byte(void *, uint8_t *, int); 163 static int ffb_i2c_write_byte(void *, uint8_t, int); 164 165 /* I2C bitbang glue */ 166 static void ffb_i2cbb_set_bits(void *, uint32_t); 167 static void ffb_i2cbb_set_dir(void *, uint32_t); 168 static uint32_t ffb_i2cbb_read(void *); 169 170 static const struct i2c_bitbang_ops ffb_i2cbb_ops = { 171 ffb_i2cbb_set_bits, 172 ffb_i2cbb_set_dir, 173 ffb_i2cbb_read, 174 { 175 FFB_DAC_CFG_MPDATA_SDA, 176 FFB_DAC_CFG_MPDATA_SCL, 177 0, 178 0 179 } 180 }; 181 182 void ffb_attach_i2c(struct ffb_softc *); 183 184 /* Video mode setting */ 185 int ffb_tgc_disable(struct ffb_softc *); 186 void ffb_get_pclk(int, uint32_t *, int *); 187 int ffb_set_vmode(struct ffb_softc *, struct videomode *, int, int *, int *); 188 189 190 void 191 ffb_attach(struct ffb_softc *sc) 192 { 193 struct wsemuldisplaydev_attach_args waa; 194 struct rasops_info *ri; 195 long defattr; 196 const char *model, *out_dev; 197 int btype; 198 uint32_t dac; 199 int maxrow, maxcol; 200 u_int blank = WSDISPLAYIO_VIDEO_ON; 201 char buf[6+1]; 202 int i, try_edid; 203 204 printf(":"); 205 206 if (sc->sc_type == FFB_CREATOR) { 207 btype = prom_getpropint(sc->sc_node, "board_type", 0); 208 if ((btype & 7) == 3) 209 printf(" Creator3D"); 210 else 211 printf(" Creator"); 212 } else { 213 printf(" Elite3D"); 214 btype = 0; 215 } 216 217 model = prom_getpropstring(sc->sc_node, "model"); 218 if (model == NULL || strlen(model) == 0) 219 model = "unknown"; 220 221 sc->sc_depth = 24; 222 sc->sc_linebytes = 8192; 223 /* We might alter these during EDID mode setting */ 224 sc->sc_height = prom_getpropint(sc->sc_node, "height", 0); 225 sc->sc_width = prom_getpropint(sc->sc_node, "width", 0); 226 227 sc->sc_locked = 0; 228 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 229 230 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0) 231 ? strtoul(buf, NULL, 10) 232 : 80; 233 234 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0) 235 ? strtoul(buf, NULL, 10) 236 : 34; 237 238 /* collect DAC version, as Elite3D cursor enable bit is reversed */ 239 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_DEVID); 240 dac = DAC_READ(sc, FFB_DAC_VALUE); 241 sc->sc_dacrev = (dac >> 28) & 0xf; 242 243 if (sc->sc_type == FFB_AFB) { 244 sc->sc_dacrev = 10; 245 sc->sc_needredraw = 0; 246 } else { 247 /* see what kind of DAC we have */ 248 int pnum = (dac & 0x0ffff000) >> 12; 249 if (pnum == 0x236e) { 250 sc->sc_needredraw = 0; 251 } else { 252 sc->sc_needredraw = 1; 253 } 254 } 255 printf(", model %s, dac %u\n", model, sc->sc_dacrev); 256 if (sc->sc_needredraw) 257 printf("%s: found old DAC, enabling redraw on unblank\n", 258 device_xname(&sc->sc_dv)); 259 260 /* Check if a console resolution "<device>:r<res>" is set. */ 261 if (sc->sc_console) { 262 out_dev = prom_getpropstring(sc->sc_node, "output_device"); 263 if (out_dev != NULL && strlen(out_dev) != 0 && 264 strstr(out_dev, ":r") != NULL) 265 try_edid = 0; 266 else 267 try_edid = 1; 268 } else 269 try_edid = 1; 270 271 ffb_attach_i2c(sc); 272 273 /* Need to set asynchronous blank during DDC write/read */ 274 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL); 275 dac = DAC_READ(sc, FFB_DAC_VALUE); 276 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL); 277 DAC_WRITE(sc, FFB_DAC_VALUE, dac | FFB_DAC_USR_CTRL_BLANK); 278 279 /* Some monitors don't respond first time */ 280 i = 0; 281 while (sc->sc_edid_data[1] == 0 && i++ < 3) 282 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, EDID_DATA_LEN); 283 284 /* Remove asynchronous blank */ 285 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL); 286 DAC_WRITE(sc, FFB_DAC_VALUE, dac); 287 288 if (edid_parse(&sc->sc_edid_data[0], &sc->sc_edid_info) != -1) { 289 sort_modes(sc->sc_edid_info.edid_modes, 290 &sc->sc_edid_info.edid_preferred_mode, 291 sc->sc_edid_info.edid_nmodes); 292 DPRINTF(("%s: EDID data:\n ", device_xname(&sc->sc_dv))); 293 for (i = 0; i < EDID_DATA_LEN; i++) { 294 if (i && !(i % 32)) 295 DPRINTF(("\n ")); 296 if (i && !(i % 4)) 297 DPRINTF((" ")); 298 DPRINTF(("%02x", sc->sc_edid_data[i])); 299 } 300 DPRINTF(("\n")); 301 if (ffb_debug) 302 edid_print(&sc->sc_edid_info); 303 304 if (try_edid) 305 for (i = 0; i < sc->sc_edid_info.edid_nmodes; i++) { 306 if (ffb_set_vmode(sc, 307 &(sc->sc_edid_info.edid_modes[i]), btype, 308 &(sc->sc_width), &(sc->sc_height))) 309 break; 310 } 311 } else { 312 DPRINTF(("%s: No EDID data.\n", device_xname(&sc->sc_dv))); 313 } 314 315 ffb_ras_init(sc); 316 317 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank); 318 319 sc->sc_accel = ((device_cfdata(&sc->sc_dv)->cf_flags & 320 FFB_CFFLAG_NOACCEL) == 0); 321 322 wsfont_init(); 323 324 vcons_init(&sc->vd, sc, &ffb_stdscreen, &ffb_accessops); 325 sc->vd.init_screen = ffb_init_screen; 326 327 /* we mess with ffb_console_screen only once */ 328 if (sc->sc_console) { 329 vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr); 330 SCREEN_VISIBLE((&ffb_console_screen)); 331 /* 332 * XXX we shouldn't use a global variable for the console 333 * screen 334 */ 335 sc->vd.active = &ffb_console_screen; 336 ffb_console_screen.scr_flags = VCONS_SCREEN_IS_STATIC; 337 } else { 338 if (ffb_console_screen.scr_ri.ri_rows == 0) { 339 /* do some minimal setup to avoid weirdnesses later */ 340 vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr); 341 } 342 } 343 ri = &ffb_console_screen.scr_ri; 344 345 ffb_stdscreen.nrows = ri->ri_rows; 346 ffb_stdscreen.ncols = ri->ri_cols; 347 ffb_stdscreen.textops = &ri->ri_ops; 348 ffb_stdscreen.capabilities = ri->ri_caps; 349 350 sc->sc_fb.fb_driver = &ffb_fbdriver; 351 sc->sc_fb.fb_type.fb_cmsize = 0; 352 sc->sc_fb.fb_type.fb_size = maxrow * sc->sc_linebytes; 353 sc->sc_fb.fb_type.fb_type = FBTYPE_CREATOR; 354 sc->sc_fb.fb_type.fb_width = sc->sc_width; 355 sc->sc_fb.fb_type.fb_depth = sc->sc_depth; 356 sc->sc_fb.fb_type.fb_height = sc->sc_height; 357 sc->sc_fb.fb_device = &sc->sc_dv; 358 fb_attach(&sc->sc_fb, sc->sc_console); 359 360 ffb_clearscreen(sc); 361 362 if (sc->sc_console) { 363 wsdisplay_cnattach(&ffb_stdscreen, ri, 0, 0, defattr); 364 vcons_replay_msgbuf(&ffb_console_screen); 365 } 366 367 waa.console = sc->sc_console; 368 waa.scrdata = &ffb_screenlist; 369 waa.accessops = &ffb_accessops; 370 waa.accesscookie = &sc->vd; 371 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint); 372 } 373 374 void 375 ffb_attach_i2c(struct ffb_softc *sc) 376 { 377 378 /* Fill in the i2c tag */ 379 sc->sc_i2c.ic_cookie = sc; 380 sc->sc_i2c.ic_acquire_bus = ffb_i2c_acquire_bus; 381 sc->sc_i2c.ic_release_bus = ffb_i2c_release_bus; 382 sc->sc_i2c.ic_send_start = ffb_i2c_send_start; 383 sc->sc_i2c.ic_send_stop = ffb_i2c_send_stop; 384 sc->sc_i2c.ic_initiate_xfer = ffb_i2c_initiate_xfer; 385 sc->sc_i2c.ic_read_byte = ffb_i2c_read_byte; 386 sc->sc_i2c.ic_write_byte = ffb_i2c_write_byte; 387 sc->sc_i2c.ic_exec = NULL; 388 } 389 390 int 391 ffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, struct lwp *l) 392 { 393 struct vcons_data *vd = v; 394 struct ffb_softc *sc = vd->cookie; 395 struct wsdisplay_fbinfo *wdf; 396 struct vcons_screen *ms = vd->active; 397 398 DPRINTF(("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n", 399 device_xname(&sc->sc_dv), 400 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "", 401 (char)IOCGROUP(cmd), cmd & 0xff)); 402 403 switch (cmd) { 404 case FBIOGTYPE: 405 *(struct fbtype *)data = sc->sc_fb.fb_type; 406 break; 407 case FBIOGATTR: 408 #define fba ((struct fbgattr *)data) 409 fba->real_type = sc->sc_fb.fb_type.fb_type; 410 fba->owner = 0; /* XXX ??? */ 411 fba->fbtype = sc->sc_fb.fb_type; 412 fba->sattr.flags = 0; 413 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 414 fba->sattr.dev_specific[0] = -1; 415 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 416 fba->emu_types[1] = -1; 417 #undef fba 418 break; 419 420 case FBIOGETCMAP: 421 case FBIOPUTCMAP: 422 return EIO; 423 424 case FBIOGVIDEO: 425 case FBIOSVIDEO: 426 return ffb_blank(sc, cmd == FBIOGVIDEO? 427 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO, 428 (u_int *)data); 429 break; 430 case FBIOGCURSOR: 431 case FBIOSCURSOR: 432 /* the console driver is not using the hardware cursor */ 433 break; 434 case FBIOGCURPOS: 435 printf("%s: FBIOGCURPOS not implemented\n", device_xname(&sc->sc_dv)); 436 return EIO; 437 case FBIOSCURPOS: 438 printf("%s: FBIOSCURPOS not implemented\n", device_xname(&sc->sc_dv)); 439 return EIO; 440 case FBIOGCURMAX: 441 printf("%s: FBIOGCURMAX not implemented\n", device_xname(&sc->sc_dv)); 442 return EIO; 443 444 case WSDISPLAYIO_GTYPE: 445 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB; 446 break; 447 case WSDISPLAYIO_SMODE: 448 { 449 if (sc->sc_mode != *(u_int *)data) { 450 sc->sc_mode = *(u_int *)data; 451 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) && 452 (sc->sc_locked == 0)) { 453 ffb_ras_init(sc); 454 vcons_redraw_screen(ms); 455 } 456 } 457 } 458 break; 459 case WSDISPLAYIO_GINFO: 460 wdf = (void *)data; 461 wdf->height = sc->sc_height; 462 wdf->width = sc->sc_width; 463 wdf->depth = 32; 464 wdf->cmsize = 256; /* XXX */ 465 break; 466 #ifdef WSDISPLAYIO_LINEBYTES 467 case WSDISPLAYIO_LINEBYTES: 468 *(u_int *)data = sc->sc_linebytes; 469 break; 470 #endif 471 case WSDISPLAYIO_GETCMAP: 472 break;/* XXX */ 473 474 case WSDISPLAYIO_PUTCMAP: 475 break;/* XXX */ 476 477 case WSDISPLAYIO_SVIDEO: 478 case WSDISPLAYIO_GVIDEO: 479 return(ffb_blank(sc, cmd, (u_int *)data)); 480 break; 481 case WSDISPLAYIO_GCURPOS: 482 case WSDISPLAYIO_SCURPOS: 483 case WSDISPLAYIO_GCURMAX: 484 case WSDISPLAYIO_GCURSOR: 485 case WSDISPLAYIO_SCURSOR: 486 return EIO; /* not supported yet */ 487 default: 488 return EPASSTHROUGH; 489 } 490 491 return (0); 492 } 493 494 /* blank/unblank the screen */ 495 static int 496 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data) 497 { 498 struct vcons_screen *ms = sc->vd.active; 499 u_int val; 500 501 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 502 val = DAC_READ(sc, FFB_DAC_VALUE); 503 504 switch (cmd) { 505 case WSDISPLAYIO_GVIDEO: 506 *data = val & 1; 507 return(0); 508 break; 509 case WSDISPLAYIO_SVIDEO: 510 if (*data == WSDISPLAYIO_VIDEO_OFF) 511 val &= ~1; 512 else if (*data == WSDISPLAYIO_VIDEO_ON) 513 val |= 1; 514 else 515 return(EINVAL); 516 break; 517 default: 518 return(EINVAL); 519 } 520 521 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 522 DAC_WRITE(sc, FFB_DAC_VALUE, val); 523 524 if ((val & 1) && sc->sc_needredraw) { 525 if (ms != NULL) { 526 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) && 527 (sc->sc_locked == 0)) { 528 ffb_ras_init(sc); 529 vcons_redraw_screen(ms); 530 } 531 } 532 } 533 534 return(0); 535 } 536 537 paddr_t 538 ffb_mmap(void *vsc, void *vs, off_t off, int prot) 539 { 540 struct vcons_data *vd = vsc; 541 struct ffb_softc *sc = vd->cookie; 542 int i; 543 544 switch (sc->sc_mode) { 545 case WSDISPLAYIO_MODE_MAPPED: 546 for (i = 0; i < sc->sc_nreg; i++) { 547 /* Before this set? */ 548 if (off < sc->sc_addrs[i]) 549 continue; 550 /* After this set? */ 551 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i])) 552 continue; 553 554 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i], 555 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR)); 556 } 557 break; 558 #ifdef WSDISPLAYIO_MODE_DUMBFB 559 case WSDISPLAYIO_MODE_DUMBFB: 560 if (sc->sc_nreg < FFB_REG_DFB24) 561 break; 562 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24]) 563 return (bus_space_mmap(sc->sc_bt, 564 sc->sc_addrs[FFB_REG_DFB24], off, prot, 565 BUS_SPACE_MAP_LINEAR)); 566 break; 567 #endif 568 } 569 return (-1); 570 } 571 572 void 573 ffb_ras_fifo_wait(struct ffb_softc *sc, int n) 574 { 575 int32_t cache = sc->sc_fifo_cache; 576 577 if (cache < n) { 578 do { 579 cache = FBC_READ(sc, FFB_FBC_UCSR); 580 cache = (cache & FBC_UCSR_FIFO_MASK) - 8; 581 } while (cache < n); 582 } 583 sc->sc_fifo_cache = cache - n; 584 } 585 586 void 587 ffb_ras_wait(struct ffb_softc *sc) 588 { 589 uint32_t ucsr, r; 590 591 while (1) { 592 ucsr = FBC_READ(sc, FFB_FBC_UCSR); 593 if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0) 594 break; 595 r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL); 596 if (r != 0) 597 FBC_WRITE(sc, FFB_FBC_UCSR, r); 598 } 599 } 600 601 void 602 ffb_ras_init(struct ffb_softc *sc) 603 { 604 uint32_t fbc; 605 606 if (sc->sc_width > 1280) { 607 DPRINTF(("ffb_ras_init: high resolution.\n")); 608 fbc = FFB_FBC_WB_B | FFB_FBC_WM_COMBINED | FFB_FBC_WE_FORCEON | 609 FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF | FFB_FBC_XE_ON; 610 } else { 611 DPRINTF(("ffb_ras_init: standard resolution.\n")); 612 fbc = FFB_FBC_XE_OFF; 613 } 614 ffb_ras_fifo_wait(sc, 7); 615 FBC_WRITE(sc, FFB_FBC_PPC, 616 FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 617 FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST); 618 FBC_WRITE(sc, FFB_FBC_FBC, 619 FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH | 620 FFB_FBC_RGBE_MASK | fbc); 621 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 622 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 623 FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff); 624 FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000); 625 sc->sc_fg_cache = 0; 626 FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache); 627 ffb_ras_wait(sc); 628 } 629 630 void 631 ffb_ras_eraserows(void *cookie, int row, int n, long attr) 632 { 633 struct rasops_info *ri = cookie; 634 struct vcons_screen *scr = ri->ri_hw; 635 struct ffb_softc *sc = scr->scr_cookie; 636 637 if (row < 0) { 638 n += row; 639 row = 0; 640 } 641 if (row + n > ri->ri_rows) 642 n = ri->ri_rows - row; 643 if (n <= 0) 644 return; 645 646 ffb_ras_fill(sc); 647 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]); 648 ffb_ras_fifo_wait(sc, 4); 649 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 650 FBC_WRITE(sc, FFB_FBC_BY, 0); 651 FBC_WRITE(sc, FFB_FBC_BX, 0); 652 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height); 653 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width); 654 } else { 655 row *= ri->ri_font->fontheight; 656 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row); 657 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin); 658 FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight); 659 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth); 660 } 661 SYNC; 662 } 663 664 void 665 ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr) 666 { 667 struct rasops_info *ri = cookie; 668 struct vcons_screen *scr = ri->ri_hw; 669 struct ffb_softc *sc = scr->scr_cookie; 670 671 if ((row < 0) || (row >= ri->ri_rows)) 672 return; 673 if (col < 0) { 674 n += col; 675 col = 0; 676 } 677 if (col + n > ri->ri_cols) 678 n = ri->ri_cols - col; 679 if (n <= 0) 680 return; 681 n *= ri->ri_font->fontwidth; 682 col *= ri->ri_font->fontwidth; 683 row *= ri->ri_font->fontheight; 684 685 ffb_ras_fill(sc); 686 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]); 687 ffb_ras_fifo_wait(sc, 4); 688 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row); 689 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col); 690 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight); 691 FBC_WRITE(sc, FFB_FBC_BW, n - 1); 692 SYNC; 693 } 694 695 void 696 ffb_ras_fill(struct ffb_softc *sc) 697 { 698 ffb_ras_fifo_wait(sc, 2); 699 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 700 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 701 SYNC; 702 } 703 704 void 705 ffb_ras_copyrows(void *cookie, int src, int dst, int n) 706 { 707 struct rasops_info *ri = cookie; 708 struct vcons_screen *scr = ri->ri_hw; 709 struct ffb_softc *sc = scr->scr_cookie; 710 711 if (dst == src) 712 return; 713 if (src < 0) { 714 n += src; 715 src = 0; 716 } 717 if ((src + n) > ri->ri_rows) 718 n = ri->ri_rows - src; 719 if (dst < 0) { 720 n += dst; 721 dst = 0; 722 } 723 if ((dst + n) > ri->ri_rows) 724 n = ri->ri_rows - dst; 725 if (n <= 0) 726 return; 727 n *= ri->ri_font->fontheight; 728 src *= ri->ri_font->fontheight; 729 dst *= ri->ri_font->fontheight; 730 731 ffb_ras_fifo_wait(sc, 8); 732 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8)); 733 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL); 734 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src); 735 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin); 736 FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst); 737 FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin); 738 FBC_WRITE(sc, FFB_FBC_BH, n); 739 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth); 740 SYNC; 741 } 742 743 static void 744 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg) 745 { 746 ffb_ras_fifo_wait(sc, 1); 747 if (fg == sc->sc_fg_cache) 748 return; 749 sc->sc_fg_cache = fg; 750 FBC_WRITE(sc, FFB_FBC_FG, fg); 751 SYNC; 752 } 753 754 static void 755 ffb_ras_setbg(struct ffb_softc *sc, int32_t bg) 756 { 757 ffb_ras_fifo_wait(sc, 1); 758 if (bg == sc->sc_bg_cache) 759 return; 760 sc->sc_bg_cache = bg; 761 FBC_WRITE(sc, FFB_FBC_BG, bg); 762 SYNC; 763 } 764 765 /* frame buffer generic driver support functions */ 766 static void 767 ffbfb_unblank(struct device *dev) 768 { 769 struct ffb_softc *sc = device_private(dev); 770 struct vcons_screen *ms = sc->vd.active; 771 u_int on = 1; 772 int redraw = 0; 773 774 ffb_ras_init(sc); 775 if (sc->sc_locked) { 776 sc->sc_locked = 0; 777 redraw = 1; 778 } 779 780 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &on); 781 #if 0 782 if ((sc->vd.active != &ffb_console_screen) && 783 (ffb_console_screen.scr_flags & VCONS_SCREEN_IS_STATIC)) { 784 /* 785 * force-switch to the console screen. 786 * Caveat: the higher layer will think we're still on the 787 * other screen 788 */ 789 790 SCREEN_INVISIBLE(sc->vd.active); 791 sc->vd.active = &ffb_console_screen; 792 SCREEN_VISIBLE(sc->vd.active); 793 ms = sc->vd.active; 794 redraw = 1; 795 } 796 #endif 797 if (redraw) { 798 vcons_redraw_screen(ms); 799 } 800 } 801 802 int 803 ffbfb_open(dev_t dev, int flags, int mode, struct lwp *l) 804 { 805 struct ffb_softc *sc; 806 807 sc = device_lookup_private(&ffb_cd, minor(dev)); 808 if (sc == NULL) 809 return ENXIO; 810 811 sc->sc_locked = 1; 812 return 0; 813 } 814 815 int 816 ffbfb_close(dev_t dev, int flags, int mode, struct lwp *l) 817 { 818 struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev)); 819 struct vcons_screen *ms = sc->vd.active; 820 821 sc->sc_locked = 0; 822 if (ms != NULL) { 823 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) && 824 (sc->sc_locked == 0)) { 825 ffb_ras_init(sc); 826 vcons_redraw_screen(ms); 827 } 828 } 829 return 0; 830 } 831 832 int 833 ffbfb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 834 { 835 struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev)); 836 837 return ffb_ioctl(&sc->vd, NULL, cmd, data, flags, l); 838 } 839 840 paddr_t 841 ffbfb_mmap(dev_t dev, off_t off, int prot) 842 { 843 struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev)); 844 uint64_t size; 845 int i, reg; 846 off_t o; 847 848 /* 849 * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h), 850 * which we map to an index into the "reg" property, and use 851 * our copy of the firmware data as arguments for the real 852 * mapping. 853 */ 854 static struct { unsigned long voff; int reg; } map[] = { 855 { 0x00000000, FFB_REG_SFB8R }, 856 { 0x00400000, FFB_REG_SFB8G }, 857 { 0x00800000, FFB_REG_SFB8B }, 858 { 0x00c00000, FFB_REG_SFB8X }, 859 { 0x01000000, FFB_REG_SFB32 }, 860 { 0x02000000, FFB_REG_SFB64 }, 861 { 0x04000000, FFB_REG_FBC }, 862 { 0x04004000, FFB_REG_DFB8R }, 863 { 0x04404000, FFB_REG_DFB8G }, 864 { 0x04804000, FFB_REG_DFB8B }, 865 { 0x04c04000, FFB_REG_DFB8X }, 866 { 0x05004000, FFB_REG_DFB24 }, 867 { 0x06004000, FFB_REG_DFB32 }, 868 { 0x07004000, FFB_REG_DFB422A }, 869 { 0x0bc06000, FFB_REG_DAC }, 870 { 0x0bc08000, FFB_REG_PROM }, 871 { 0x0bc18000, 0 } 872 }; 873 874 /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */ 875 if (off == 0x0bc18000) 876 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM], 877 0x00200000, prot, BUS_SPACE_MAP_LINEAR); 878 879 /* 880 * FFB_VOFF_FBC_KREGS - used by afbinit to upload firmware. We should 881 * probably mmap them only on afb boards 882 */ 883 if ((off >= 0x0bc04000) && (off < 0x0bc06000)) 884 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM], 885 0x00610000 + (off - 0x0bc04000), prot, 886 BUS_SPACE_MAP_LINEAR); 887 888 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0])) 889 890 /* the map is ordered by voff */ 891 for (i = 0; i < NELEMS(map)-1; i++) { 892 reg = map[i].reg; 893 /* the number of entries in reg seems to vary */ 894 if (reg < sc->sc_nreg) { 895 size = min((map[i + 1].voff - map[i].voff), 896 sc->sc_sizes[reg]); 897 if ((off >= map[i].voff) && 898 (off < (map[i].voff + size))) { 899 o = off - map[i].voff; 900 return bus_space_mmap(sc->sc_bt, 901 sc->sc_addrs[reg], o, prot, 902 BUS_SPACE_MAP_LINEAR); 903 } 904 } 905 } 906 907 return -1; 908 } 909 910 void 911 ffb_clearscreen(struct ffb_softc *sc) 912 { 913 struct rasops_info *ri = &ffb_console_screen.scr_ri; 914 ffb_ras_fill(sc); 915 ffb_ras_setfg(sc, ri->ri_devcmap[WS_DEFAULT_BG]); 916 ffb_ras_fifo_wait(sc, 4); 917 FBC_WRITE(sc, FFB_FBC_BY, 0); 918 FBC_WRITE(sc, FFB_FBC_BX, 0); 919 FBC_WRITE(sc, FFB_FBC_BH, sc->sc_height); 920 FBC_WRITE(sc, FFB_FBC_BW, sc->sc_width); 921 } 922 923 void 924 ffb_cursor(void *cookie, int on, int row, int col) 925 { 926 struct rasops_info *ri = cookie; 927 struct vcons_screen *scr; 928 struct ffb_softc *sc; 929 int x, y, wi, he, coffset; 930 931 if (cookie != NULL) { 932 scr = ri->ri_hw; 933 sc = scr->scr_cookie; 934 935 wi = ri->ri_font->fontwidth; 936 he = ri->ri_font->fontheight; 937 938 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 939 x = ri->ri_ccol * wi + ri->ri_xorigin; 940 y = ri->ri_crow * he + ri->ri_yorigin; 941 942 if (ri->ri_flg & RI_CURSOR) { 943 /* remove cursor */ 944 coffset = ri->ri_ccol + (ri->ri_crow * 945 ri->ri_cols); 946 #ifdef WSDISPLAY_SCROLLSUPPORT 947 coffset += scr->scr_offset_to_zero; 948 #endif 949 ffb_ras_wait(sc); 950 ffb_putchar(cookie, ri->ri_crow, 951 ri->ri_ccol, scr->scr_chars[coffset], 952 scr->scr_attrs[coffset]); 953 ri->ri_flg &= ~RI_CURSOR; 954 } 955 ri->ri_crow = row; 956 ri->ri_ccol = col; 957 if (on) 958 { 959 long attr, revattr; 960 x = ri->ri_ccol * wi + ri->ri_xorigin; 961 y = ri->ri_crow * he + ri->ri_yorigin; 962 coffset = col + (row * ri->ri_cols); 963 #ifdef WSDISPLAY_SCROLLSUPPORT 964 coffset += scr->scr_offset_to_zero; 965 #endif 966 attr = scr->scr_attrs[coffset]; 967 #ifdef FFB_CURSOR_SWAP_COLOURS 968 revattr=((attr >> 8 ) & 0x000f0000) | ((attr & 969 0x000f0000)<<8) | (attr & 0x0000ffff); 970 #else 971 revattr = attr ^ 0xffff0000; 972 #endif 973 ffb_ras_wait(sc); 974 ffb_putchar(cookie, ri->ri_crow, ri->ri_ccol, 975 scr->scr_chars[coffset], revattr); 976 ri->ri_flg |= RI_CURSOR; 977 } 978 } else { 979 ri->ri_crow = row; 980 ri->ri_ccol = col; 981 ri->ri_flg &= ~RI_CURSOR; 982 } 983 } 984 } 985 986 void 987 ffb_putchar(void *cookie, int row, int col, u_int c, long attr) 988 { 989 struct rasops_info *ri = cookie; 990 struct vcons_screen *scr = ri->ri_hw; 991 struct wsdisplay_font *font = PICK_FONT(ri, c); 992 struct ffb_softc *sc = scr->scr_cookie; 993 994 /* 995 * font operations don't use the blitter so we have to wait here 996 * in case we were scrolling 997 */ 998 999 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1000 void *data; 1001 uint32_t fg, bg; 1002 int uc, i; 1003 int x, y, wi, he; 1004 1005 wi = font->fontwidth; 1006 he = font->fontheight; 1007 1008 if (!CHAR_IN_FONT(c, font)) 1009 return; 1010 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1011 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1012 x = ri->ri_xorigin + col * wi; 1013 y = ri->ri_yorigin + row * he; 1014 1015 uc = c - font->firstchar; 1016 data = (uint8_t *)font->data + uc * ri->ri_fontscale; 1017 1018 ffb_ras_setbg(sc, bg); 1019 ffb_ras_setfg(sc, fg); 1020 ffb_ras_fifo_wait(sc, 3); 1021 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 1022 FBC_WRITE(sc, FFB_FBC_FONTXY, (y << 16) | x); 1023 FBC_WRITE(sc, FFB_FBC_FONTW, wi); 1024 1025 switch (ri->ri_font->stride) { 1026 case 1: { 1027 uint8_t *data8 = data; 1028 uint32_t reg; 1029 for (i = 0; i < he; i++) { 1030 reg = *data8; 1031 FBC_WRITE(sc, FFB_FBC_FONT, reg << 24); 1032 data8++; 1033 } 1034 break; 1035 } 1036 case 2: { 1037 uint16_t *data16 = data; 1038 uint32_t reg; 1039 for (i = 0; i < he; i++) { 1040 reg = *data16; 1041 FBC_WRITE(sc, FFB_FBC_FONT, reg << 16); 1042 data16++; 1043 } 1044 break; 1045 } 1046 } 1047 } 1048 } 1049 1050 int 1051 ffb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 1052 { 1053 if ((fg == 0) && (bg == 0)) 1054 { 1055 fg = WS_DEFAULT_FG; 1056 bg = WS_DEFAULT_BG; 1057 } 1058 if (flags & WSATTR_REVERSE) { 1059 *attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 | 1060 (flags & 0xff); 1061 } else 1062 *attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 | 1063 (flags & 0xff); 1064 return 0; 1065 } 1066 1067 void 1068 ffb_init_screen(void *cookie, struct vcons_screen *scr, 1069 int existing, long *defattr) 1070 { 1071 struct ffb_softc *sc = cookie; 1072 struct rasops_info *ri = &scr->scr_ri; 1073 1074 ri->ri_depth = 32; 1075 ri->ri_width = sc->sc_width; 1076 ri->ri_height = sc->sc_height; 1077 ri->ri_stride = sc->sc_linebytes; 1078 ri->ri_flg = RI_CENTER; 1079 1080 /* 1081 * we can't accelerate copycols() so instead of falling back to 1082 * software use vcons' putchar() based implementation 1083 */ 1084 scr->scr_flags |= VCONS_NO_COPYCOLS; 1085 1086 DPRINTF(("ffb_init_screen: addr: %08lx\n",(ulong)ri->ri_bits)); 1087 1088 rasops_init(ri, sc->sc_height/8, sc->sc_width/8); 1089 ri->ri_caps = WSSCREEN_WSCOLORS; 1090 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 1091 sc->sc_width / ri->ri_font->fontwidth); 1092 1093 /* enable acceleration */ 1094 ri->ri_ops.copyrows = ffb_ras_copyrows; 1095 ri->ri_ops.eraserows = ffb_ras_eraserows; 1096 ri->ri_ops.erasecols = ffb_ras_erasecols; 1097 ri->ri_ops.cursor = ffb_cursor; 1098 ri->ri_ops.allocattr = ffb_allocattr; 1099 ri->ri_ops.putchar = ffb_putchar; 1100 } 1101 1102 /* I2C bitbanging */ 1103 static void ffb_i2cbb_set_bits(void *cookie, uint32_t bits) 1104 { 1105 struct ffb_softc *sc = cookie; 1106 1107 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_CFG_MPDATA); 1108 DAC_WRITE(sc, FFB_DAC_VALUE, bits); 1109 } 1110 1111 static void ffb_i2cbb_set_dir(void *cookie, uint32_t dir) 1112 { 1113 /* Nothing to do */ 1114 } 1115 1116 static uint32_t ffb_i2cbb_read(void *cookie) 1117 { 1118 struct ffb_softc *sc = cookie; 1119 uint32_t bits; 1120 1121 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_CFG_MPSENSE); 1122 bits = DAC_READ(sc, FFB_DAC_VALUE); 1123 1124 return bits; 1125 } 1126 1127 /* higher level I2C stuff */ 1128 static int 1129 ffb_i2c_acquire_bus(void *cookie, int flags) 1130 { 1131 /* private bus */ 1132 return (0); 1133 } 1134 1135 static void 1136 ffb_i2c_release_bus(void *cookie, int flags) 1137 { 1138 /* private bus */ 1139 } 1140 1141 static int 1142 ffb_i2c_send_start(void *cookie, int flags) 1143 { 1144 return (i2c_bitbang_send_start(cookie, flags, &ffb_i2cbb_ops)); 1145 } 1146 1147 static int 1148 ffb_i2c_send_stop(void *cookie, int flags) 1149 { 1150 1151 return (i2c_bitbang_send_stop(cookie, flags, &ffb_i2cbb_ops)); 1152 } 1153 1154 static int 1155 ffb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 1156 { 1157 /* 1158 * for some reason i2c_bitbang_initiate_xfer left-shifts 1159 * the I2C-address and then sets the direction bit 1160 */ 1161 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, 1162 &ffb_i2cbb_ops)); 1163 } 1164 1165 static int 1166 ffb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 1167 { 1168 return (i2c_bitbang_read_byte(cookie, valp, flags, &ffb_i2cbb_ops)); 1169 } 1170 1171 static int 1172 ffb_i2c_write_byte(void *cookie, uint8_t val, int flags) 1173 { 1174 return (i2c_bitbang_write_byte(cookie, val, flags, &ffb_i2cbb_ops)); 1175 } 1176 1177 1178 #define TVC_READ_LIMIT 100000 1179 int 1180 ffb_tgc_disable(struct ffb_softc *sc) 1181 { 1182 int i; 1183 1184 /* Is the timing generator disabled? */ 1185 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 1186 if (!(DAC_READ(sc, FFB_DAC_VALUE) & FFB_DAC_TGC_TIMING_ENABLE)) 1187 return 1; 1188 1189 /* If not, disable it when the vertical counter reaches 0 */ 1190 for (i = 0; i < TVC_READ_LIMIT; i++) { 1191 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TVC); 1192 if (!DAC_READ(sc, FFB_DAC_VALUE)) { 1193 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 1194 DAC_WRITE(sc, FFB_DAC_VALUE, 0); 1195 return 1; 1196 } 1197 } 1198 return 0; 1199 } 1200 1201 /* 1202 * PLL Control Register values: 1203 * M)ultiplier = bits 0:6 + 1 1204 * D)ivisor = bits 7:10 + 1 1205 * P)ost divisor = bits 11:13 (000 = 1, 001 = 2, 010 = 4, 011 = 8) 1206 * Frequency = 13.5 * M / D / P 1207 */ 1208 #define FFB_PLL_FREQ 13500000 1209 void 1210 ffb_get_pclk(int request, uint32_t *pll, int *diff) 1211 { 1212 int m, d, p, f, hex = 0, curdiff; 1213 1214 *diff = 100000000; 1215 1216 for (m = 32; m <= 80; m++) { 1217 for (d = 4; d <= 11; d++) { 1218 for (p = 1; p <= 8; p = p << 1) { 1219 switch (p) { 1220 case 1: 1221 hex = 0x4000 + (d << 7) + m; 1222 break; 1223 case 2: 1224 hex = 0x4800 + (d << 7) + m; 1225 break; 1226 case 4: 1227 hex = 0x5000 + (d << 7) + m; 1228 break; 1229 case 8: 1230 hex = 0x6000 + (d << 7) + m; 1231 break; 1232 } 1233 f = 13500000 * m / d / p; 1234 if (f == request) { 1235 *diff = 0; 1236 *pll = hex; 1237 return; 1238 } else { 1239 curdiff = abs(request - f); 1240 if (curdiff < *diff) { 1241 *diff = curdiff; 1242 *pll = hex; 1243 } 1244 } 1245 } 1246 } 1247 } 1248 } 1249 1250 /* 1251 * Details of the FFB RAMDAC are contained in the Brooktree BT497/498 1252 * and in the Connexant BT497A/498A documentation. 1253 * 1254 * VESA timings to FFB register conversion: 1255 * If interleave = 4/2:1 then x = 2, if interleave = 8/2:1 then x = 4 1256 * VBE = VBS - vres = (sync pulse - 1) + back porch 1257 * VBS = VSS - front porch = (sync pulse - 1) + back porch + vres 1258 * VSE = sync pulse - 1 1259 * VSS = (sync pulse - 1) + back porch + vres + front porch 1260 * HRE = HSS - HSE - 1 1261 * HBE = (sync pulse + back porch) / x - 1 1262 * HBS = (sync pulse + back porch + hres) / x - 1 1263 * HSE = sync pulse / x - 1 1264 * HSS = (sync pulse + back porch + hres + front porch) / x - 1 1265 * HCE = HBS - 4 1266 * HCS = HBE - 4 1267 * EPE = EIE = EIS = 0 (for all non-interlaced modes) 1268 * 1269 * Note, that 8/2:1 Single Buffered Interleaving is only supported by the 1270 * double-buffered FFB (Creator3D), and at higher resolutions than 1280x1024 1271 * 1272 * Note, that the timing generator should be disabled and re-enabled when the 1273 * the timing parameter registers are being programmed. Stopping the timing 1274 * generator should only be done when the vertical counter is zero. 1275 */ 1276 #define DIVIDE(x,y) (((x) + ((y) / 2)) / (y)) 1277 int 1278 ffb_set_vmode(struct ffb_softc *sc, struct videomode *mode, int btype, 1279 int *hres, int *vres) 1280 { 1281 int diff; 1282 uint32_t fp, sp, bp, x; 1283 uint32_t pll, pfc, ucl, dcl, tgc; 1284 uint32_t vbe, vbs, vse, vss, hre, hbe, hbs, hse, hss, hce, hcs; 1285 uint32_t epe, eie, eis; 1286 uint32_t fbcfg0; 1287 1288 DPRINTF(("ffb_set_vmode: %dx%d@%d", mode->hdisplay, mode->vdisplay, 1289 DIVIDE(DIVIDE(mode->dot_clock * 1000, 1290 mode->htotal), mode->vtotal))); 1291 DPRINTF((" (%d %d %d %d %d %d %d", 1292 mode->dot_clock, mode->hsync_start, mode->hsync_end, mode->htotal, 1293 mode->vsync_start, mode->vsync_end, mode->vtotal)); 1294 DPRINTF((" %s%sH %s%sV)\n", 1295 mode->flags & VID_PHSYNC ? "+" : "", 1296 mode->flags & VID_NHSYNC ? "-" : "", 1297 mode->flags & VID_PVSYNC ? "+" : "", 1298 mode->flags & VID_NVSYNC ? "-" : "")); 1299 1300 /* We don't handle interlaced or doublescan (yet) */ 1301 if ((mode->flags & VID_INTERLACE) || (mode->flags & VID_DBLSCAN)) 1302 return 0; 1303 1304 /* Only Creator3D can be set to > 1280x1024 */ 1305 if(((sc->sc_type == FFB_CREATOR && !((btype & 7) == 3)) || 1306 sc->sc_type == FFB_AFB) 1307 && (mode->hdisplay > 1280 || mode->vdisplay > 1024)) 1308 return 0; 1309 /* Creator3D can be set to <= 1920x1360 */ 1310 if (mode->hdisplay > 1920 || mode->vdisplay > 1360) 1311 return 0; 1312 1313 /* 1314 * Look for a matching pixel clock and set PLL Control. 1315 * XXX: 640x480@60 is 25175000 in modelines but 25125000 in the 1316 * FFB PROM, and the closest match to 25175000 (0x4da9/25159090) 1317 * does not work. So, use the PROM value instead. 1318 */ 1319 if (mode->hdisplay == 640 && mode->vdisplay == 480 && 1320 mode->dot_clock == 25175) { 1321 DPRINTF(("ffb_set_vmode: 640x480@60: adjusted dot clock\n")); 1322 mode->dot_clock = 25125; 1323 } 1324 ffb_get_pclk(mode->dot_clock * 1000, &pll, &diff); 1325 if (diff > 250000) 1326 return 0; 1327 1328 /* Pixel Format Control, User Control and FBC Configuration. */ 1329 if (mode->hdisplay > 1280) { 1330 pfc = FFB_DAC_PIX_FMT_821; 1331 ucl = FFB_DAC_USR_CTRL_OVERLAY | FFB_DAC_USR_CTRL_WMODE_C; 1332 x = 4; 1333 fbcfg0 = FBC_READ(sc, FFB_FBC_FBCFG0) | FBC_CFG0_DOUBLE_BUF; 1334 } else { 1335 pfc = FFB_DAC_PIX_FMT_421; 1336 /* Only Creator3D and Elite3D can have double-buffer */ 1337 if ((sc->sc_type == FFB_CREATOR && !((btype & 7) == 3))) 1338 ucl = 0; 1339 else 1340 ucl = FFB_DAC_USR_CTRL_DOUBLE; 1341 ucl |= (FFB_DAC_USR_CTRL_OVERLAY | FFB_DAC_USR_CTRL_WMODE_S8); 1342 x = 2; 1343 fbcfg0 = FBC_READ(sc, FFB_FBC_FBCFG0) | FBC_CFG0_SINGLE_BUF; 1344 } 1345 1346 /* DAC Control and Timing Generator Control */ 1347 if (mode->flags & VID_PHSYNC) { 1348 dcl = FFB_DAC_DAC_CTRL_POS_SYNC; 1349 if (mode->flags & VID_NVSYNC) { 1350 dcl |= FFB_DAC_DAC_CTRL_VSYNC_REV; 1351 tgc = 0; 1352 } else { 1353 tgc = FFB_DAC_TGC_EQUAL_DISABLE; 1354 } 1355 } else { 1356 dcl = 0; 1357 if (mode->flags & VID_PVSYNC) { 1358 dcl |= FFB_DAC_DAC_CTRL_VSYNC_REV; 1359 tgc = 0; 1360 } else { 1361 tgc = FFB_DAC_TGC_EQUAL_DISABLE; 1362 } 1363 } 1364 #define EDID_VID_INP sc->sc_edid_info.edid_video_input 1365 if (!(EDID_VID_INP & EDID_VIDEO_INPUT_COMPOSITE_SYNC)) { 1366 dcl |= FFB_DAC_DAC_CTRL_SYNC_G; 1367 if (EDID_VID_INP & EDID_VIDEO_INPUT_SEPARATE_SYNCS) 1368 tgc |= FFB_DAC_TGC_VSYNC_DISABLE; 1369 } 1370 if (EDID_VID_INP & EDID_VIDEO_INPUT_BLANK_TO_BLACK) 1371 dcl |= FFB_DAC_DAC_CTRL_PED_ENABLE; 1372 tgc |= (FFB_DAC_TGC_VIDEO_ENABLE | FFB_DAC_TGC_TIMING_ENABLE | 1373 FFB_DAC_TGC_MASTER_ENABLE); 1374 1375 /* Vertical timing */ 1376 fp = mode->vsync_start - mode->vdisplay; 1377 sp = mode->vsync_end - mode->vsync_start; 1378 bp = mode->vtotal - mode->vsync_end; 1379 1380 vbe = sp - 1 + bp; 1381 vbs = sp - 1 + bp + mode->vdisplay; 1382 vse = sp - 1; 1383 vss = sp - 1 + bp + mode->vdisplay + fp; 1384 1385 /* Horizontal timing */ 1386 fp = mode->hsync_start - mode->hdisplay; 1387 sp = mode->hsync_end - mode->hsync_start; 1388 bp = mode->htotal - mode->hsync_end; 1389 1390 hbe = (sp + bp) / x - 1; 1391 hbs = (sp + bp + mode->hdisplay) / x - 1; 1392 hse = sp / x - 1; 1393 hss = (sp + bp + mode->hdisplay + fp) / x -1; 1394 hre = hss - hse - 1; 1395 hce = hbs - 4; 1396 hcs = hbe - 4; 1397 1398 /* Equalisation (interlaced modes) */ 1399 epe = 0; 1400 eie = 0; 1401 eis = 0; 1402 1403 DPRINTF(("ffb_set_vmode: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", 1404 pll, pfc, ucl, dcl, tgc)); 1405 DPRINTF(("\t0x%04x 0x%04x 0x%04x 0x%04x\n", vbe, vbs, vse, vss)); 1406 DPRINTF(("\t0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", 1407 hre, hbe, hbs, hse, hss, hce, hcs)); 1408 DPRINTF(("\t0x%04x 0x%04x 0x%04x\n", epe, eie, eis)); 1409 1410 if (!ffb_tgc_disable(sc)) { 1411 DPRINTF(("ffb_set_vmode: failed to disable TGC register\n")); 1412 return 0; 1413 } 1414 1415 /* 1416 * Program the mode registers. 1417 * Program the timing generator last, as that re-enables output. 1418 * Note, that a read to/write from a register increments the 1419 * register address to the next register automatically. 1420 */ 1421 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_PLL_CTRL); 1422 DAC_WRITE(sc, FFB_DAC_VALUE, pll); 1423 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_PIX_FMT); 1424 DAC_WRITE(sc, FFB_DAC_VALUE, pfc); 1425 DAC_WRITE(sc, FFB_DAC_VALUE, ucl); 1426 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_DAC_CTRL); 1427 DAC_WRITE(sc, FFB_DAC_VALUE, dcl); 1428 1429 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_VBE); 1430 DAC_WRITE(sc, FFB_DAC_VALUE, vbe); 1431 DAC_WRITE(sc, FFB_DAC_VALUE, vbs); 1432 DAC_WRITE(sc, FFB_DAC_VALUE, vse); 1433 DAC_WRITE(sc, FFB_DAC_VALUE, vss); 1434 1435 DAC_WRITE(sc, FFB_DAC_VALUE, hre); 1436 DAC_WRITE(sc, FFB_DAC_VALUE, hbe); 1437 DAC_WRITE(sc, FFB_DAC_VALUE, hbs); 1438 DAC_WRITE(sc, FFB_DAC_VALUE, hse); 1439 DAC_WRITE(sc, FFB_DAC_VALUE, hss); 1440 DAC_WRITE(sc, FFB_DAC_VALUE, hce); 1441 DAC_WRITE(sc, FFB_DAC_VALUE, hcs); 1442 1443 DAC_WRITE(sc, FFB_DAC_VALUE, epe); 1444 DAC_WRITE(sc, FFB_DAC_VALUE, eie); 1445 DAC_WRITE(sc, FFB_DAC_VALUE, eis); 1446 1447 FBC_WRITE(sc, FFB_FBC_FBCFG0, fbcfg0); 1448 1449 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 1450 DAC_WRITE(sc, FFB_DAC_VALUE, tgc); 1451 1452 *hres = mode->hdisplay; 1453 *vres = mode->vdisplay; 1454 1455 printf("%s: video mode set to %d x %d @ %dHz\n", 1456 device_xname(&sc->sc_dv), 1457 mode->hdisplay, mode->vdisplay, 1458 DIVIDE(DIVIDE(mode->dot_clock * 1000, 1459 mode->htotal), mode->vtotal)); 1460 1461 return 1; 1462 } 1463