1 /* $NetBSD: unichromefb.c,v 1.18 2011/01/22 15:14:28 cegger Exp $ */ 2 3 /*- 4 * Copyright (c) 2006, 2008 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright 1998-2006 VIA Technologies, Inc. All Rights Reserved. 31 * Copyright 2001-2006 S3 Graphics, Inc. All Rights Reserved. 32 * 33 * Permission is hereby granted, free of charge, to any person obtaining a 34 * copy of this software and associated documentation files (the "Software"), 35 * to deal in the Software without restriction, including without limitation 36 * the rights to use, copy, modify, merge, publish, distribute, sub license, 37 * and/or sell copies of the Software, and to permit persons to whom the 38 * Software is furnished to do so, subject to the following conditions: 39 * 40 * The above copyright notice and this permission notice (including the 41 * next paragraph) shall be included in all copies or substantial portions 42 * of the Software. 43 * 44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 47 * THE AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 48 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 49 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 50 * DEALINGS IN THE SOFTWARE. 51 */ 52 53 #include <sys/cdefs.h> 54 __KERNEL_RCSID(0, "$NetBSD: unichromefb.c,v 1.18 2011/01/22 15:14:28 cegger Exp $"); 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/device.h> 59 #include <sys/malloc.h> 60 61 #include <sys/bus.h> 62 63 #include <dev/pci/pcivar.h> 64 #include <dev/pci/pcireg.h> 65 #include <dev/pci/pcidevs.h> 66 #include <dev/pci/pciio.h> 67 68 #include <dev/wscons/wsdisplayvar.h> 69 #include <dev/wscons/wsconsio.h> 70 #include <dev/wsfont/wsfont.h> 71 #include <dev/rasops/rasops.h> 72 #include <dev/wscons/wsdisplay_vconsvar.h> 73 #include <dev/pci/wsdisplay_pci.h> 74 75 #include <dev/pci/unichromereg.h> 76 #include <dev/pci/unichromemode.h> 77 #include <dev/pci/unichromehw.h> 78 #include <dev/pci/unichromeconfig.h> 79 #include <dev/pci/unichromeaccel.h> 80 81 #include "vga.h" 82 83 #if NVGA > 0 84 #include <dev/ic/mc6845reg.h> 85 #include <dev/ic/pcdisplayvar.h> 86 #include <dev/ic/vgareg.h> 87 #include <dev/ic/vgavar.h> 88 #endif 89 90 /* XXX */ 91 #define UNICHROMEFB_DEPTH 16 92 #define UNICHROMEFB_MODE VIA_RES_1280X1024 93 #define UNICHROMEFB_WIDTH 1280 94 #define UNICHROMEFB_HEIGHT 1024 95 96 struct unichromefb_softc { 97 device_t sc_dev; 98 struct vcons_data sc_vd; 99 void * sc_fbbase; 100 unsigned int sc_fbaddr; 101 unsigned int sc_fbsize; 102 bus_addr_t sc_mmiobase; 103 bus_size_t sc_mmiosize; 104 105 bus_space_tag_t sc_iot; 106 bus_space_handle_t sc_ioh; 107 108 bus_space_tag_t sc_memt; 109 bus_space_handle_t sc_memh; 110 bus_space_tag_t sc_apmemt; 111 bus_space_handle_t sc_apmemh; 112 113 struct pci_attach_args sc_pa; 114 115 int sc_width; 116 int sc_height; 117 int sc_depth; 118 int sc_stride; 119 120 int sc_wsmode; 121 122 int sc_accel; 123 }; 124 125 static int unichromefb_match(device_t, cfdata_t, void *); 126 static void unichromefb_attach(device_t, device_t, void *); 127 128 static int unichromefb_drm_print(void *, const char *); 129 static int unichromefb_drm_unmap(struct unichromefb_softc *); 130 static int unichromefb_drm_map(struct unichromefb_softc *); 131 132 struct wsscreen_descr unichromefb_stdscreen = { 133 "fb", 134 0, 0, 135 NULL, 136 8, 16, 137 WSSCREEN_WSCOLORS, NULL, 138 }; 139 140 static int unichromefb_ioctl(void *, void *, u_long, void *, int, 141 struct lwp *); 142 static paddr_t unichromefb_mmap(void *, void *, off_t, int); 143 144 static void unichromefb_init_screen(void *, struct vcons_screen *, 145 int, long *); 146 147 /* hardware access */ 148 static uint8_t uni_rd(struct unichromefb_softc *, int, uint8_t); 149 static void uni_wr(struct unichromefb_softc *, int, uint8_t, uint8_t); 150 static void uni_wr_mask(struct unichromefb_softc *, int, uint8_t, 151 uint8_t, uint8_t); 152 static void uni_wr_x(struct unichromefb_softc *, struct io_reg *, int); 153 static void uni_wr_dac(struct unichromefb_softc *, uint8_t, uint8_t, 154 uint8_t, uint8_t); 155 156 /* helpers */ 157 static struct VideoModeTable * uni_getmode(int); 158 static void uni_setmode(struct unichromefb_softc *, int, int); 159 static void uni_crt_lock(struct unichromefb_softc *); 160 static void uni_crt_unlock(struct unichromefb_softc *); 161 static void uni_crt_enable(struct unichromefb_softc *); 162 static void uni_crt_disable(struct unichromefb_softc *); 163 static void uni_screen_enable(struct unichromefb_softc *); 164 static void uni_screen_disable(struct unichromefb_softc *); 165 static void uni_set_start(struct unichromefb_softc *); 166 static void uni_set_crtc(struct unichromefb_softc *, 167 struct crt_mode_table *, int, int, int); 168 static void uni_load_crtc(struct unichromefb_softc *, struct display_timing, 169 int); 170 static void uni_load_reg(struct unichromefb_softc *, int, int, 171 struct io_register *, int); 172 static void uni_fix_crtc(struct unichromefb_softc *); 173 static void uni_load_offset(struct unichromefb_softc *, int, int, int); 174 static void uni_load_fetchcnt(struct unichromefb_softc *, int, int, int); 175 static void uni_load_fifo(struct unichromefb_softc *, int, int, int); 176 static void uni_set_depth(struct unichromefb_softc *, int, int); 177 static uint32_t uni_get_clkval(struct unichromefb_softc *, int); 178 static void uni_set_vclk(struct unichromefb_softc *, uint32_t, int); 179 static void uni_init_dac(struct unichromefb_softc *, int); 180 static void uni_init_accel(struct unichromefb_softc *); 181 static void uni_set_accel_depth(struct unichromefb_softc *); 182 183 /* graphics ops */ 184 static void uni_wait_idle(struct unichromefb_softc *); 185 static void uni_fillrect(struct unichromefb_softc *, 186 int, int, int, int, int); 187 static void uni_rectinvert(struct unichromefb_softc *, 188 int, int, int, int); 189 static void uni_bitblit(struct unichromefb_softc *, int, int, int, int, 190 int, int); 191 static void uni_setup_mono(struct unichromefb_softc *, int, int, int, 192 int, uint32_t, uint32_t); 193 #if notyet 194 static void uni_cursor_show(struct unichromefb_softc *); 195 static void uni_cursor_hide(struct unichromefb_softc *); 196 #endif 197 198 /* rasops glue */ 199 static void uni_copycols(void *, int, int, int, int); 200 static void uni_copyrows(void *, int, int, int); 201 static void uni_erasecols(void *, int, int, int, long); 202 static void uni_eraserows(void *, int, int, long); 203 static void uni_cursor(void *, int, int, int); 204 static void uni_putchar(void *, int, int, u_int, long); 205 206 struct wsdisplay_accessops unichromefb_accessops = { 207 unichromefb_ioctl, 208 unichromefb_mmap, 209 NULL, 210 NULL, 211 NULL, 212 NULL, 213 NULL, 214 NULL, 215 }; 216 217 static struct vcons_screen unichromefb_console_screen; 218 219 const struct wsscreen_descr *_unichromefb_scrlist[] = { 220 &unichromefb_stdscreen, 221 }; 222 223 struct wsscreen_list unichromefb_screenlist = { 224 sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *), 225 _unichromefb_scrlist 226 }; 227 228 CFATTACH_DECL_NEW(unichromefb, sizeof(struct unichromefb_softc), 229 unichromefb_match, unichromefb_attach, NULL, NULL); 230 231 static int 232 unichromefb_match(device_t parent, cfdata_t match, void *opaque) 233 { 234 struct pci_attach_args *pa; 235 236 pa = (struct pci_attach_args *)opaque; 237 238 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY || 239 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA) 240 return 0; 241 242 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH) 243 return 0; 244 245 switch (PCI_PRODUCT(pa->pa_id)) { 246 case PCI_PRODUCT_VIATECH_VT3314_IG: 247 return 10; /* beat vga(4) */ 248 } 249 250 return 0; 251 } 252 253 static void 254 unichromefb_attach(device_t parent, device_t self, void *opaque) 255 { 256 struct unichromefb_softc *sc = device_private(self); 257 struct pci_attach_args *pa; 258 struct rasops_info *ri; 259 struct wsemuldisplaydev_attach_args aa; 260 uint8_t val; 261 long defattr; 262 263 pa = (struct pci_attach_args *)opaque; 264 265 sc->sc_dev = self; 266 sc->sc_width = UNICHROMEFB_WIDTH; 267 sc->sc_height = UNICHROMEFB_HEIGHT; 268 sc->sc_depth = UNICHROMEFB_DEPTH; 269 sc->sc_stride = sc->sc_width * (sc->sc_depth / 8); 270 271 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL; 272 273 sc->sc_iot = pa->pa_iot; 274 sc->sc_pa = *pa; 275 276 #if NVGA > 0 277 /* XXX vga_cnattach claims the I/O registers that we need; 278 * we need to nuke it here so we can take over. 279 */ 280 vga_cndetach(); 281 #endif 282 283 if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) { 284 aprint_error(": failed to map I/O registers\n"); 285 return; 286 } 287 288 sc->sc_apmemt = pa->pa_memt; 289 val = uni_rd(sc, VIASR, SR30); 290 sc->sc_fbaddr = val << 24; 291 val = uni_rd(sc, VIASR, SR39); 292 sc->sc_fbsize = val * (4*1024*1024); 293 if (sc->sc_fbsize < 16*1024*1024 || sc->sc_fbsize > 64*1024*1024) 294 sc->sc_fbsize = 16*1024*1024; 295 if (bus_space_map(sc->sc_apmemt, sc->sc_fbaddr, sc->sc_fbsize, 296 BUS_SPACE_MAP_LINEAR, &sc->sc_apmemh)) { 297 aprint_error(": failed to map aperture at 0x%08x/0x%x\n", 298 sc->sc_fbaddr, sc->sc_fbsize); 299 return; 300 } 301 sc->sc_fbbase = (void *)bus_space_vaddr(sc->sc_apmemt, sc->sc_apmemh); 302 303 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, 304 &sc->sc_memt, &sc->sc_memh, &sc->sc_mmiobase, 305 &sc->sc_mmiosize)) { 306 sc->sc_accel = 0; 307 aprint_error(": failed to map MMIO registers\n"); 308 } else { 309 sc->sc_accel = 1; 310 } 311 312 aprint_naive("\n"); 313 aprint_normal(": VIA UniChrome frame buffer\n"); 314 315 if (sc->sc_accel) 316 aprint_normal_dev(self, "MMIO @0x%08x/0x%x\n", 317 (uint32_t)sc->sc_mmiobase, 318 (uint32_t)sc->sc_mmiosize); 319 320 ri = &unichromefb_console_screen.scr_ri; 321 memset(ri, 0, sizeof(struct rasops_info)); 322 323 vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen, 324 &unichromefb_accessops); 325 sc->sc_vd.init_screen = unichromefb_init_screen; 326 327 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth); 328 329 uni_init_dac(sc, IGA1); 330 if (sc->sc_accel) { 331 uni_init_accel(sc); 332 uni_fillrect(sc, 0, 0, sc->sc_width, sc->sc_height, 0); 333 } 334 335 aprint_normal_dev(self, "FB @0x%08x (%dx%dx%d)\n", 336 sc->sc_fbaddr, sc->sc_width, sc->sc_height, sc->sc_depth); 337 338 unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 339 vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr); 340 341 unichromefb_stdscreen.ncols = ri->ri_cols; 342 unichromefb_stdscreen.nrows = ri->ri_rows; 343 unichromefb_stdscreen.textops = &ri->ri_ops; 344 unichromefb_stdscreen.capabilities = ri->ri_caps; 345 unichromefb_stdscreen.modecookie = NULL; 346 347 wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr); 348 349 aa.console = 1; /* XXX */ 350 aa.scrdata = &unichromefb_screenlist; 351 aa.accessops = &unichromefb_accessops; 352 aa.accesscookie = &sc->sc_vd; 353 354 config_found(self, &aa, wsemuldisplaydevprint); 355 356 config_found_ia(self, "drm", opaque, unichromefb_drm_print); 357 358 return; 359 } 360 361 static int 362 unichromefb_drm_print(void *opaque, const char *pnp) 363 { 364 if (pnp) 365 aprint_normal("drm at %s", pnp); 366 367 return UNCONF; 368 } 369 370 static int 371 unichromefb_drm_unmap(struct unichromefb_softc *sc) 372 { 373 aprint_debug_dev(sc->sc_dev, "releasing bus resources\n"); 374 375 bus_space_unmap(sc->sc_apmemt, sc->sc_apmemh, sc->sc_fbsize); 376 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mmiosize); 377 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0x20); 378 379 return 0; 380 } 381 382 static int 383 unichromefb_drm_map(struct unichromefb_softc *sc) 384 { 385 int rv; 386 387 rv = bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, 388 &sc->sc_ioh); 389 if (rv) { 390 aprint_error_dev(sc->sc_dev, "failed to map I/O registers\n"); 391 return rv; 392 } 393 rv = bus_space_map(sc->sc_apmemt, sc->sc_fbaddr, sc->sc_fbsize, 394 BUS_SPACE_MAP_LINEAR, &sc->sc_apmemh); 395 if (rv) { 396 aprint_error_dev(sc->sc_dev, 397 "failed to map aperture at 0x%08x/0x%x\n", 398 sc->sc_fbaddr, sc->sc_fbsize); 399 return rv; 400 } 401 sc->sc_fbbase = (void *)bus_space_vaddr(sc->sc_apmemt, sc->sc_apmemh); 402 rv = pci_mapreg_map(&sc->sc_pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, 403 &sc->sc_memt, &sc->sc_memh, &sc->sc_mmiobase, 404 &sc->sc_mmiosize); 405 if (rv) { 406 aprint_error_dev(sc->sc_dev, "failed to map MMIO registers\n"); 407 sc->sc_accel = 0; 408 } 409 410 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth); 411 uni_init_dac(sc, IGA1); 412 if (sc->sc_accel) 413 uni_init_accel(sc); 414 415 aprint_debug_dev(sc->sc_dev, "re-acquired bus resources\n"); 416 417 return 0; 418 } 419 420 static int 421 unichromefb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 422 struct lwp *l) 423 { 424 struct vcons_data *vd; 425 struct unichromefb_softc *sc; 426 struct wsdisplay_fbinfo *fb; 427 428 vd = (struct vcons_data *)v; 429 sc = (struct unichromefb_softc *)vd->cookie; 430 431 switch (cmd) { 432 case WSDISPLAYIO_GTYPE: 433 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 434 return 0; 435 case WSDISPLAYIO_GINFO: 436 if (vd->active != NULL) { 437 fb = (struct wsdisplay_fbinfo *)data; 438 fb->width = sc->sc_width; 439 fb->height = sc->sc_height; 440 fb->depth = sc->sc_depth; 441 fb->cmsize = 256; 442 return 0; 443 } else 444 return ENODEV; 445 case WSDISPLAYIO_GVIDEO: 446 return ENODEV; 447 case WSDISPLAYIO_SVIDEO: 448 return ENODEV; 449 case WSDISPLAYIO_GETCMAP: 450 return EINVAL; 451 case WSDISPLAYIO_PUTCMAP: 452 return EINVAL; 453 case WSDISPLAYIO_LINEBYTES: 454 *(u_int *)data = sc->sc_stride; 455 return 0; 456 case WSDISPLAYIO_SMODE: { 457 int new_mode = *(int *)data; 458 if (new_mode != sc->sc_wsmode) { 459 sc->sc_wsmode = new_mode; 460 switch (new_mode) { 461 case WSDISPLAYIO_MODE_EMUL: 462 unichromefb_drm_map(sc); 463 vcons_redraw_screen(vd->active); 464 break; 465 default: 466 unichromefb_drm_unmap(sc); 467 break; 468 } 469 } 470 } 471 return 0; 472 case WSDISPLAYIO_SSPLASH: 473 return ENODEV; 474 case WSDISPLAYIO_SPROGRESS: 475 return ENODEV; 476 477 /* PCI config read/write passthrough. */ 478 case PCI_IOC_CFGREAD: 479 case PCI_IOC_CFGWRITE: 480 return (pci_devioctl(sc->sc_pa.pa_pc, sc->sc_pa.pa_tag, 481 cmd, data, flag, l)); 482 483 case WSDISPLAYIO_GET_BUSID: 484 return wsdisplayio_busid_pci(sc->sc_dev, 485 sc->sc_pa.pa_pc, sc->sc_pa.pa_tag, data); 486 487 } 488 489 return EPASSTHROUGH; 490 } 491 492 static paddr_t 493 unichromefb_mmap(void *v, void *vs, off_t offset, int prot) 494 { 495 return -1; 496 } 497 498 static void 499 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing, 500 long *defattr) 501 { 502 struct unichromefb_softc *sc; 503 struct rasops_info *ri; 504 505 sc = (struct unichromefb_softc *)c; 506 ri = &scr->scr_ri; 507 ri->ri_flg = RI_CENTER; 508 ri->ri_depth = sc->sc_depth; 509 ri->ri_width = sc->sc_width; 510 ri->ri_height = sc->sc_height; 511 ri->ri_stride = sc->sc_stride; 512 ri->ri_bits = sc->sc_fbbase; 513 if (existing) 514 ri->ri_flg |= RI_CLEAR; 515 516 switch (ri->ri_depth) { 517 case 32: 518 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8; 519 ri->ri_rpos = 16; 520 ri->ri_gpos = 8; 521 ri->ri_bpos = 0; 522 break; 523 case 16: 524 ri->ri_rnum = 5; 525 ri->ri_gnum = 6; 526 ri->ri_bnum = 5; 527 ri->ri_rpos = 11; 528 ri->ri_gpos = 5; 529 ri->ri_bpos = 0; 530 break; 531 } 532 533 rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8); 534 ri->ri_caps = WSSCREEN_WSCOLORS; 535 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 536 sc->sc_width / ri->ri_font->fontwidth); 537 538 ri->ri_hw = scr; 539 if (sc->sc_accel) { 540 ri->ri_ops.copyrows = uni_copyrows; 541 ri->ri_ops.copycols = uni_copycols; 542 ri->ri_ops.eraserows = uni_eraserows; 543 ri->ri_ops.erasecols = uni_erasecols; 544 ri->ri_ops.cursor = uni_cursor; 545 ri->ri_ops.putchar = uni_putchar; 546 } 547 548 return; 549 } 550 551 /* 552 * hardware access 553 */ 554 static uint8_t 555 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx) 556 { 557 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx); 558 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1); 559 } 560 561 static void 562 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val) 563 { 564 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx); 565 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val); 566 } 567 568 static void 569 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx, 570 uint8_t val, uint8_t mask) 571 { 572 uint8_t tmp; 573 574 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx); 575 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1); 576 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, 577 ((val & mask) | (tmp & ~mask))); 578 } 579 580 static void 581 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx, 582 uint8_t r, uint8_t g, uint8_t b) 583 { 584 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx); 585 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r); 586 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g); 587 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b); 588 } 589 590 static void 591 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num) 592 { 593 int i; 594 uint8_t tmp; 595 596 for (i = 0; i < num; i++) { 597 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port, 598 tbl[i].index); 599 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 600 tbl[i].port + 1); 601 tmp = (tmp & (~tbl[i].mask)) | tbl[i].value; 602 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1, 603 tmp); 604 } 605 } 606 607 /* 608 * helpers 609 */ 610 static struct VideoModeTable * 611 uni_getmode(int mode) 612 { 613 int i; 614 615 for (i = 0; i < NUM_TOTAL_MODETABLE; i++) 616 if (CLE266Modes[i].ModeIndex == mode) 617 return &CLE266Modes[i]; 618 619 return NULL; 620 } 621 622 static void 623 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp) 624 { 625 struct VideoModeTable *vtbl; 626 struct crt_mode_table *crt; 627 int i; 628 629 /* XXX */ 630 vtbl = uni_getmode(idx); 631 if (vtbl == NULL) 632 panic("%s: unsupported mode: %d\n", 633 device_xname(sc->sc_dev), idx); 634 635 crt = vtbl->crtc; 636 637 uni_screen_disable(sc); 638 639 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus); 640 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0); 641 642 /* XXX assume CN900 for now */ 643 uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs); 644 645 uni_crt_disable(sc); 646 647 /* Fill VPIT params */ 648 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc); 649 650 /* Write sequencer */ 651 for (i = 1; i <= StdSR; i++) { 652 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i); 653 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1, 654 VPIT.SR[i - 1]); 655 } 656 657 uni_set_start(sc); 658 659 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1); 660 661 for (i = 0; i < StdGR; i++) { 662 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i); 663 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1, 664 VPIT.GR[i]); 665 } 666 667 for (i = 0; i < StdAR; i++) { 668 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus); 669 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i); 670 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 671 VPIT.AR[i]); 672 } 673 674 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus); 675 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20); 676 677 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1); 678 /* set crt output path */ 679 uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6); 680 681 uni_crt_enable(sc); 682 uni_screen_enable(sc); 683 684 return; 685 } 686 687 static void 688 uni_crt_lock(struct unichromefb_softc *sc) 689 { 690 uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7); 691 } 692 693 static void 694 uni_crt_unlock(struct unichromefb_softc *sc) 695 { 696 uni_wr_mask(sc, VIACR, CR11, 0, BIT7); 697 uni_wr_mask(sc, VIACR, CR47, 0, BIT0); 698 } 699 700 static void 701 uni_crt_enable(struct unichromefb_softc *sc) 702 { 703 uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4); 704 } 705 706 static void 707 uni_crt_disable(struct unichromefb_softc *sc) 708 { 709 uni_wr_mask(sc, VIACR, CR36, BIT5+BIT4, BIT5+BIT4); 710 } 711 712 static void 713 uni_screen_enable(struct unichromefb_softc *sc) 714 { 715 uni_wr_mask(sc, VIASR, SR01, 0, BIT5); 716 } 717 718 static void 719 uni_screen_disable(struct unichromefb_softc *sc) 720 { 721 uni_wr_mask(sc, VIASR, SR01, 0x20, BIT5); 722 } 723 724 static void 725 uni_set_start(struct unichromefb_softc *sc) 726 { 727 uni_crt_unlock(sc); 728 729 uni_wr(sc, VIACR, CR0C, 0x00); 730 uni_wr(sc, VIACR, CR0D, 0x00); 731 uni_wr(sc, VIACR, CR34, 0x00); 732 uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1); 733 734 uni_wr(sc, VIACR, CR62, 0x00); 735 uni_wr(sc, VIACR, CR63, 0x00); 736 uni_wr(sc, VIACR, CR64, 0x00); 737 uni_wr(sc, VIACR, CRA3, 0x00); 738 739 uni_crt_lock(sc); 740 } 741 742 static void 743 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl, 744 int mode, int bpp_byte, int iga) 745 { 746 struct VideoModeTable *vtbl; 747 struct display_timing crtreg; 748 int i; 749 int index; 750 int haddr, vaddr; 751 uint8_t val; 752 uint32_t pll_d_n; 753 754 index = 0; 755 756 vtbl = uni_getmode(mode); 757 for (i = 0; i < vtbl->mode_array; i++) { 758 index = i; 759 if (ctbl[i].refresh_rate == 60) 760 break; 761 } 762 763 crtreg = ctbl[index].crtc; 764 765 haddr = crtreg.hor_addr; 766 vaddr = crtreg.ver_addr; 767 768 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc); 769 if (ctbl[index].h_sync_polarity == NEGATIVE) { 770 if (ctbl[index].v_sync_polarity == NEGATIVE) 771 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 772 (val & (~(BIT6+BIT7))) | (BIT6+BIT7)); 773 else 774 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 775 (val & (~(BIT6+BIT7))) | (BIT6)); 776 } else { 777 if (ctbl[index].v_sync_polarity == NEGATIVE) 778 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 779 (val & (~(BIT6+BIT7))) | (BIT7)); 780 else 781 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 782 (val & (~(BIT6+BIT7)))); 783 } 784 785 if (iga == IGA1) { 786 uni_crt_unlock(sc); 787 uni_wr(sc, VIACR, CR09, 0x00); 788 uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6); 789 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7); 790 } 791 792 uni_load_crtc(sc, crtreg, iga); 793 uni_fix_crtc(sc); 794 uni_crt_lock(sc); 795 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7); 796 797 uni_load_offset(sc, haddr, bpp_byte, iga); 798 uni_load_fetchcnt(sc, haddr, bpp_byte, iga); 799 uni_load_fifo(sc, iga, haddr, vaddr); 800 801 uni_set_depth(sc, bpp_byte, iga); 802 pll_d_n = uni_get_clkval(sc, ctbl[index].clk); 803 uni_set_vclk(sc, pll_d_n, iga); 804 } 805 806 static void 807 uni_load_crtc(struct unichromefb_softc *sc, 808 struct display_timing device_timing, int iga) 809 { 810 int regnum, val; 811 struct io_register *reg; 812 int i; 813 814 regnum = val = 0; 815 reg = NULL; 816 817 uni_crt_unlock(sc); 818 819 for (i = 0; i < 12; i++) { 820 switch (iga) { 821 case IGA1: 822 switch (i) { 823 case H_TOTAL_INDEX: 824 val = IGA1_HOR_TOTAL_FORMULA( 825 device_timing.hor_total); 826 regnum = iga1_crtc_reg.hor_total.reg_num; 827 reg = iga1_crtc_reg.hor_total.reg; 828 break; 829 case H_ADDR_INDEX: 830 val = IGA1_HOR_ADDR_FORMULA( 831 device_timing.hor_addr); 832 regnum = iga1_crtc_reg.hor_addr.reg_num; 833 reg = iga1_crtc_reg.hor_addr.reg; 834 break; 835 case H_BLANK_START_INDEX: 836 val = IGA1_HOR_BLANK_START_FORMULA( 837 device_timing.hor_blank_start); 838 regnum = iga1_crtc_reg.hor_blank_start.reg_num; 839 reg = iga1_crtc_reg.hor_blank_start.reg; 840 break; 841 case H_BLANK_END_INDEX: 842 val = IGA1_HOR_BLANK_END_FORMULA( 843 device_timing.hor_blank_start, 844 device_timing.hor_blank_end); 845 regnum = iga1_crtc_reg.hor_blank_end.reg_num; 846 reg = iga1_crtc_reg.hor_blank_end.reg; 847 break; 848 case H_SYNC_START_INDEX: 849 val = IGA1_HOR_SYNC_START_FORMULA( 850 device_timing.hor_sync_start); 851 regnum = iga1_crtc_reg.hor_sync_start.reg_num; 852 reg = iga1_crtc_reg.hor_sync_start.reg; 853 break; 854 case H_SYNC_END_INDEX: 855 val = IGA1_HOR_SYNC_END_FORMULA( 856 device_timing.hor_sync_start, 857 device_timing.hor_sync_end); 858 regnum = iga1_crtc_reg.hor_sync_end.reg_num; 859 reg = iga1_crtc_reg.hor_sync_end.reg; 860 break; 861 case V_TOTAL_INDEX: 862 val = IGA1_VER_TOTAL_FORMULA( 863 device_timing.ver_total); 864 regnum = iga1_crtc_reg.ver_total.reg_num; 865 reg = iga1_crtc_reg.ver_total.reg; 866 break; 867 case V_ADDR_INDEX: 868 val = IGA1_VER_ADDR_FORMULA( 869 device_timing.ver_addr); 870 regnum = iga1_crtc_reg.ver_addr.reg_num; 871 reg = iga1_crtc_reg.ver_addr.reg; 872 break; 873 case V_BLANK_START_INDEX: 874 val = IGA1_VER_BLANK_START_FORMULA( 875 device_timing.ver_blank_start); 876 regnum = iga1_crtc_reg.ver_blank_start.reg_num; 877 reg = iga1_crtc_reg.ver_blank_start.reg; 878 break; 879 case V_BLANK_END_INDEX: 880 val = IGA1_VER_BLANK_END_FORMULA( 881 device_timing.ver_blank_start, 882 device_timing.ver_blank_end); 883 regnum = iga1_crtc_reg.ver_blank_end.reg_num; 884 reg = iga1_crtc_reg.ver_blank_end.reg; 885 break; 886 case V_SYNC_START_INDEX: 887 val = IGA1_VER_SYNC_START_FORMULA( 888 device_timing.ver_sync_start); 889 regnum = iga1_crtc_reg.ver_sync_start.reg_num; 890 reg = iga1_crtc_reg.ver_sync_start.reg; 891 break; 892 case V_SYNC_END_INDEX: 893 val = IGA1_VER_SYNC_END_FORMULA( 894 device_timing.ver_sync_start, 895 device_timing.ver_sync_end); 896 regnum = iga1_crtc_reg.ver_sync_end.reg_num; 897 reg = iga1_crtc_reg.ver_sync_end.reg; 898 break; 899 default: 900 aprint_error_dev(sc->sc_dev, 901 "unknown index %d while setting up CRTC\n", 902 i); 903 break; 904 } 905 break; 906 case IGA2: 907 aprint_error_dev(sc->sc_dev, "%s: IGA2 not supported\n", 908 __func__); 909 break; 910 } 911 912 uni_load_reg(sc, val, regnum, reg, VIACR); 913 } 914 915 uni_crt_lock(sc); 916 } 917 918 static void 919 uni_load_reg(struct unichromefb_softc *sc, int timing, int regnum, 920 struct io_register *reg, int type) 921 { 922 int regmask, bitnum, data; 923 int i, j; 924 int shift_next_reg; 925 int startidx, endidx, cridx; 926 uint16_t getbit; 927 928 bitnum = 0; 929 930 for (i = 0; i < regnum; i++) { 931 regmask = data = 0; 932 startidx = reg[i].start_bit; 933 endidx = reg[i].end_bit; 934 cridx = reg[i].io_addr; 935 936 shift_next_reg = bitnum; 937 938 for (j = startidx; j <= endidx; j++) { 939 regmask = regmask | (BIT0 << j); 940 getbit = (timing & (BIT0 << bitnum)); 941 data = data | ((getbit >> shift_next_reg) << startidx); 942 ++bitnum; 943 } 944 945 if (type == VIACR) 946 uni_wr_mask(sc, VIACR, cridx, data, regmask); 947 else 948 uni_wr_mask(sc, VIASR, cridx, data, regmask); 949 } 950 951 return; 952 } 953 954 static void 955 uni_fix_crtc(struct unichromefb_softc *sc) 956 { 957 uni_wr_mask(sc, VIACR, CR03, 0x80, BIT7); 958 uni_wr(sc, VIACR, CR18, 0xff); 959 uni_wr_mask(sc, VIACR, CR07, 0x10, BIT4); 960 uni_wr_mask(sc, VIACR, CR09, 0x40, BIT6); 961 uni_wr_mask(sc, VIACR, CR35, 0x10, BIT4); 962 uni_wr_mask(sc, VIACR, CR33, 0x06, BIT0+BIT1+BIT2); 963 uni_wr(sc, VIACR, CR17, 0xe3); 964 uni_wr(sc, VIACR, CR08, 0x00); 965 uni_wr(sc, VIACR, CR14, 0x00); 966 967 return; 968 } 969 970 static void 971 uni_load_offset(struct unichromefb_softc *sc, int haddr, int bpp, int iga) 972 { 973 974 switch (iga) { 975 case IGA1: 976 uni_load_reg(sc, 977 IGA1_OFFSET_FORMULA(haddr, bpp), 978 offset_reg.iga1_offset_reg.reg_num, 979 offset_reg.iga1_offset_reg.reg, 980 VIACR); 981 break; 982 default: 983 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 984 __func__); 985 break; 986 } 987 988 return; 989 } 990 991 static void 992 uni_load_fetchcnt(struct unichromefb_softc *sc, int haddr, int bpp, int iga) 993 { 994 995 switch (iga) { 996 case IGA1: 997 uni_load_reg(sc, 998 IGA1_FETCH_COUNT_FORMULA(haddr, bpp), 999 fetch_count_reg.iga1_fetch_count_reg.reg_num, 1000 fetch_count_reg.iga1_fetch_count_reg.reg, 1001 VIASR); 1002 break; 1003 default: 1004 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 1005 __func__); 1006 break; 1007 } 1008 1009 return; 1010 } 1011 1012 static void 1013 uni_load_fifo(struct unichromefb_softc *sc, int iga, int horact, int veract) 1014 { 1015 int val, regnum; 1016 struct io_register *reg; 1017 int iga1_fifo_max_depth, iga1_fifo_threshold; 1018 int iga1_fifo_high_threshold, iga1_display_queue_expire_num; 1019 1020 reg = NULL; 1021 iga1_fifo_max_depth = iga1_fifo_threshold = 0; 1022 iga1_fifo_high_threshold = iga1_display_queue_expire_num = 0; 1023 1024 switch (iga) { 1025 case IGA1: 1026 /* XXX if (type == CN900) { */ 1027 iga1_fifo_max_depth = CN900_IGA1_FIFO_MAX_DEPTH; 1028 iga1_fifo_threshold = CN900_IGA1_FIFO_THRESHOLD; 1029 iga1_fifo_high_threshold = CN900_IGA1_FIFO_HIGH_THRESHOLD; 1030 if (horact > 1280 && veract > 1024) 1031 iga1_display_queue_expire_num = 16; 1032 else 1033 iga1_display_queue_expire_num = 1034 CN900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; 1035 /* XXX } */ 1036 1037 /* set display FIFO depth select */ 1038 val = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth); 1039 regnum = 1040 display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num; 1041 reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg; 1042 uni_load_reg(sc, val, regnum, reg, VIASR); 1043 1044 /* set display FIFO threshold select */ 1045 val = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold); 1046 regnum = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg_num; 1047 reg = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg; 1048 uni_load_reg(sc, val, regnum, reg, VIASR); 1049 1050 /* set display FIFO high threshold select */ 1051 val = IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold); 1052 regnum = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg_num; 1053 reg = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg; 1054 uni_load_reg(sc, val, regnum, reg, VIASR); 1055 1056 /* set display queue expire num */ 1057 val = IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(iga1_display_queue_expire_num); 1058 regnum = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg_num; 1059 reg = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg; 1060 uni_load_reg(sc, val, regnum, reg, VIASR); 1061 1062 break; 1063 default: 1064 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 1065 __func__); 1066 break; 1067 } 1068 1069 return; 1070 } 1071 1072 static void 1073 uni_set_depth(struct unichromefb_softc *sc, int bpp, int iga) 1074 { 1075 switch (iga) { 1076 case IGA1: 1077 switch (bpp) { 1078 case MODE_32BPP: 1079 uni_wr_mask(sc, VIASR, SR15, 0xae, 0xfe); 1080 break; 1081 case MODE_16BPP: 1082 uni_wr_mask(sc, VIASR, SR15, 0xb6, 0xfe); 1083 break; 1084 case MODE_8BPP: 1085 uni_wr_mask(sc, VIASR, SR15, 0x22, 0xfe); 1086 break; 1087 default: 1088 aprint_error_dev(sc->sc_dev, 1089 "%s: mode (%d) unsupported\n", __func__, bpp); 1090 } 1091 break; 1092 default: 1093 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 1094 __func__); 1095 break; 1096 } 1097 } 1098 1099 static uint32_t 1100 uni_get_clkval(struct unichromefb_softc *sc, int clk) 1101 { 1102 int i; 1103 1104 for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) { 1105 if (clk == pll_value[i].clk) { 1106 /* XXX only CN900 supported for now */ 1107 return pll_value[i].k800_pll; 1108 } 1109 } 1110 1111 aprint_error_dev(sc->sc_dev, "can't find matching PLL value\n"); 1112 1113 return 0; 1114 } 1115 1116 static void 1117 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga) 1118 { 1119 uint8_t val; 1120 1121 /* hardware reset on */ 1122 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7); 1123 1124 switch (iga) { 1125 case IGA1: 1126 /* XXX only CN900 is supported */ 1127 uni_wr(sc, VIASR, SR44, clk / 0x10000); 1128 uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100); 1129 uni_wr(sc, VIASR, SR46, clk % 0x100); 1130 break; 1131 default: 1132 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 1133 __func__); 1134 break; 1135 } 1136 1137 /* hardware reset off */ 1138 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7); 1139 1140 /* reset pll */ 1141 switch (iga) { 1142 case IGA1: 1143 uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1); 1144 uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1); 1145 break; 1146 } 1147 1148 /* good to go */ 1149 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc); 1150 val |= (BIT2+BIT3); 1151 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val); 1152 1153 return; 1154 } 1155 1156 static void 1157 uni_init_dac(struct unichromefb_softc *sc, int iga) 1158 { 1159 int i; 1160 1161 /* XXX only IGA1 for now */ 1162 uni_wr_mask(sc, VIASR, SR1A, 0x00, BIT0); 1163 uni_wr_mask(sc, VIASR, SR18, 0x00, BIT7+BIT6); 1164 for (i = 0; i < 256; i++) 1165 uni_wr_dac(sc, i, 1166 palLUT_table[i].red, palLUT_table[i].green, palLUT_table[i].blue); 1167 1168 uni_wr_mask(sc, VIASR, SR18, 0xc0, BIT7+BIT6); 1169 1170 return; 1171 } 1172 1173 static void 1174 uni_init_accel(struct unichromefb_softc *sc) 1175 { 1176 1177 /* init 2D engine regs to reset 2D engine */ 1178 MMIO_OUT32(VIA_REG_GEMODE, 0); 1179 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1180 MMIO_OUT32(VIA_REG_DSTPOS, 0); 1181 MMIO_OUT32(VIA_REG_DIMENSION, 0); 1182 MMIO_OUT32(VIA_REG_PATADDR, 0); 1183 MMIO_OUT32(VIA_REG_FGCOLOR, 0); 1184 MMIO_OUT32(VIA_REG_BGCOLOR, 0); 1185 MMIO_OUT32(VIA_REG_CLIPTL, 0); 1186 MMIO_OUT32(VIA_REG_CLIPBR, 0); 1187 MMIO_OUT32(VIA_REG_OFFSET, 0); 1188 MMIO_OUT32(VIA_REG_KEYCONTROL, 0); 1189 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1190 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1191 MMIO_OUT32(VIA_REG_PITCH, 0); 1192 MMIO_OUT32(VIA_REG_MONOPAT1, 0); 1193 1194 /* init AGP and VQ registers */ 1195 MMIO_OUT32(VIA_REG_TRANSET, 0x00100000); 1196 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000); 1197 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00333004); 1198 MMIO_OUT32(VIA_REG_TRANSPACE, 0x60000000); 1199 MMIO_OUT32(VIA_REG_TRANSPACE, 0x61000000); 1200 MMIO_OUT32(VIA_REG_TRANSPACE, 0x62000000); 1201 MMIO_OUT32(VIA_REG_TRANSPACE, 0x63000000); 1202 MMIO_OUT32(VIA_REG_TRANSPACE, 0x64000000); 1203 MMIO_OUT32(VIA_REG_TRANSPACE, 0x7d000000); 1204 1205 MMIO_OUT32(VIA_REG_TRANSET, 0xfe020000); 1206 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000); 1207 1208 /* disable VQ */ 1209 MMIO_OUT32(VIA_REG_TRANSET, 0x00fe0000); 1210 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000004); 1211 MMIO_OUT32(VIA_REG_TRANSPACE, 0x40008c0f); 1212 MMIO_OUT32(VIA_REG_TRANSPACE, 0x44000000); 1213 MMIO_OUT32(VIA_REG_TRANSPACE, 0x45080c04); 1214 MMIO_OUT32(VIA_REG_TRANSPACE, 0x46800408); 1215 1216 uni_set_accel_depth(sc); 1217 1218 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1219 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1220 1221 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1222 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1223 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1224 1225 return; 1226 } 1227 1228 static void 1229 uni_set_accel_depth(struct unichromefb_softc *sc) 1230 { 1231 uint32_t gemode; 1232 1233 gemode = MMIO_IN32(0x04) & 0xfffffcff; 1234 1235 switch (sc->sc_depth) { 1236 case 32: 1237 gemode |= VIA_GEM_32bpp; 1238 break; 1239 case 16: 1240 gemode |= VIA_GEM_16bpp; 1241 break; 1242 default: 1243 gemode |= VIA_GEM_8bpp; 1244 break; 1245 } 1246 1247 /* set colour depth and pitch */ 1248 MMIO_OUT32(VIA_REG_GEMODE, gemode); 1249 1250 return; 1251 } 1252 1253 static void 1254 uni_wait_idle(struct unichromefb_softc *sc) 1255 { 1256 int loop = 0; 1257 1258 while (!(MMIO_IN32(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && 1259 (loop++ < MAXLOOP)) 1260 ; 1261 1262 while ((MMIO_IN32(VIA_REG_STATUS) & 1263 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && 1264 (loop++ < MAXLOOP)) 1265 ; 1266 1267 if (loop >= MAXLOOP) 1268 aprint_error_dev(sc->sc_dev, "engine stall\n"); 1269 1270 return; 1271 } 1272 1273 static void 1274 uni_fillrect(struct unichromefb_softc *sc, int x, int y, int width, 1275 int height, int colour) 1276 { 1277 1278 uni_wait_idle(sc); 1279 1280 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1281 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1282 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1283 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1284 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1285 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1286 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x)); 1287 MMIO_OUT32(VIA_REG_DIMENSION, 1288 (((height - 1) << 16) | (width - 1))); 1289 MMIO_OUT32(VIA_REG_FGCOLOR, colour); 1290 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0xf0 << 24)); 1291 1292 return; 1293 } 1294 1295 static void 1296 uni_rectinvert(struct unichromefb_softc *sc, int x, int y, int width, 1297 int height) 1298 { 1299 1300 uni_wait_idle(sc); 1301 1302 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1303 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1304 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1305 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1306 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1307 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1308 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x)); 1309 MMIO_OUT32(VIA_REG_DIMENSION, 1310 (((height - 1) << 16) | (width - 1))); 1311 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0x55 << 24)); 1312 1313 return; 1314 } 1315 1316 static void 1317 uni_bitblit(struct unichromefb_softc *sc, int xs, int ys, int xd, int yd, int width, int height) 1318 { 1319 uint32_t dir; 1320 1321 dir = 0; 1322 1323 if (ys < yd) { 1324 yd += height - 1; 1325 ys += height - 1; 1326 dir |= 0x4000; 1327 } 1328 1329 if (xs < xd) { 1330 xd += width - 1; 1331 xs += width - 1; 1332 dir |= 0x8000; 1333 } 1334 1335 uni_wait_idle(sc); 1336 1337 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1338 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1339 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1340 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1341 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1342 MMIO_OUT32(VIA_REG_SRCPOS, ys << 16 | xs); 1343 MMIO_OUT32(VIA_REG_DSTPOS, yd << 16 | xd); 1344 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1)); 1345 MMIO_OUT32(VIA_REG_GECMD, (0x01 | dir | (0xcc << 24))); 1346 1347 return; 1348 } 1349 1350 static void 1351 uni_setup_mono(struct unichromefb_softc *sc, int xd, int yd, int width, int height, 1352 uint32_t fg, uint32_t bg) 1353 { 1354 1355 uni_wait_idle(sc); 1356 1357 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1358 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1359 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1360 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1361 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1362 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1363 MMIO_OUT32(VIA_REG_DSTPOS, (yd << 16) | xd); 1364 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1)); 1365 MMIO_OUT32(VIA_REG_FGCOLOR, fg); 1366 MMIO_OUT32(VIA_REG_BGCOLOR, bg); 1367 MMIO_OUT32(VIA_REG_GECMD, 0xcc020142); 1368 1369 return; 1370 } 1371 1372 #if notyet 1373 static void 1374 uni_cursor_show(struct unichromefb_softc *sc) 1375 { 1376 uint32_t val; 1377 1378 val = MMIO_IN32(VIA_REG_CURSOR_MODE); 1379 val |= 1; 1380 MMIO_OUT32(VIA_REG_CURSOR_MODE, val); 1381 1382 return; 1383 } 1384 1385 static void 1386 uni_cursor_hide(struct unichromefb_softc *sc) 1387 { 1388 uint32_t val; 1389 1390 val = MMIO_IN32(VIA_REG_CURSOR_MODE); 1391 val &= 0xfffffffe; 1392 MMIO_OUT32(VIA_REG_CURSOR_MODE, val); 1393 1394 return; 1395 } 1396 #endif 1397 1398 /* 1399 * rasops glue 1400 */ 1401 static void 1402 uni_copycols(void *opaque, int row, int srccol, int dstcol, int ncols) 1403 { 1404 struct rasops_info *ri; 1405 struct vcons_screen *scr; 1406 struct unichromefb_softc *sc; 1407 int xs, xd, y, width, height; 1408 1409 ri = (struct rasops_info *)opaque; 1410 scr = (struct vcons_screen *)ri->ri_hw; 1411 sc = (struct unichromefb_softc *)scr->scr_cookie; 1412 1413 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1414 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1415 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1416 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1417 width = ri->ri_font->fontwidth * ncols; 1418 height = ri->ri_font->fontheight; 1419 uni_bitblit(sc, xs, y, xd, y, width, height); 1420 } 1421 1422 return; 1423 } 1424 1425 static void 1426 uni_copyrows(void *opaque, int srcrow, int dstrow, int nrows) 1427 { 1428 struct rasops_info *ri; 1429 struct vcons_screen *scr; 1430 struct unichromefb_softc *sc; 1431 int x, ys, yd, width, height; 1432 1433 ri = (struct rasops_info *)opaque; 1434 scr = (struct vcons_screen *)ri->ri_hw; 1435 sc = (struct unichromefb_softc *)scr->scr_cookie; 1436 1437 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1438 x = ri->ri_xorigin; 1439 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1440 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1441 width = ri->ri_emuwidth; 1442 height = ri->ri_font->fontheight * nrows; 1443 uni_bitblit(sc, x, ys, x, yd, width, height); 1444 } 1445 1446 return; 1447 } 1448 1449 static void 1450 uni_erasecols(void *opaque, int row, int startcol, int ncols, long fillattr) 1451 { 1452 struct rasops_info *ri; 1453 struct vcons_screen *scr; 1454 struct unichromefb_softc *sc; 1455 int x, y, width, height, fg, bg, ul; 1456 1457 ri = (struct rasops_info *)opaque; 1458 scr = (struct vcons_screen *)ri->ri_hw; 1459 sc = (struct unichromefb_softc *)scr->scr_cookie; 1460 1461 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1462 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1463 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1464 width = ri->ri_font->fontwidth * ncols; 1465 height = ri->ri_font->fontheight; 1466 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1467 uni_fillrect(sc, x, y, width, height, ri->ri_devcmap[bg]); 1468 } 1469 1470 return; 1471 } 1472 1473 static void 1474 uni_eraserows(void *opaque, int row, int nrows, long fillattr) 1475 { 1476 struct rasops_info *ri; 1477 struct vcons_screen *scr; 1478 struct unichromefb_softc *sc; 1479 int x, y, width, height, fg, bg, ul; 1480 1481 ri = (struct rasops_info *)opaque; 1482 scr = (struct vcons_screen *)ri->ri_hw; 1483 sc = (struct unichromefb_softc *)scr->scr_cookie; 1484 1485 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1486 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1487 if ((row == 0) && (nrows == ri->ri_rows)) { 1488 /* clear the whole screen */ 1489 uni_fillrect(sc, 0, 0, ri->ri_width, 1490 ri->ri_height, ri->ri_devcmap[bg]); 1491 } else { 1492 x = ri->ri_xorigin; 1493 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1494 width = ri->ri_emuwidth; 1495 height = ri->ri_font->fontheight * nrows; 1496 uni_fillrect(sc, x, y, width, height, 1497 ri->ri_devcmap[bg]); 1498 } 1499 } 1500 1501 return; 1502 } 1503 1504 static void 1505 uni_cursor(void *opaque, int on, int row, int col) 1506 { 1507 struct rasops_info *ri; 1508 struct vcons_screen *scr; 1509 struct unichromefb_softc *sc; 1510 int x, y, wi, he; 1511 1512 ri = (struct rasops_info *)opaque; 1513 scr = (struct vcons_screen *)ri->ri_hw; 1514 sc = (struct unichromefb_softc *)scr->scr_cookie; 1515 1516 uni_wait_idle(sc); 1517 1518 wi = ri->ri_font->fontwidth; 1519 he = ri->ri_font->fontheight; 1520 1521 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1522 x = ri->ri_ccol * wi + ri->ri_xorigin; 1523 y = ri->ri_crow * he + ri->ri_yorigin; 1524 if (ri->ri_flg & RI_CURSOR) { 1525 uni_rectinvert(sc, x, y, wi, he); 1526 ri->ri_flg &= ~RI_CURSOR; 1527 } 1528 ri->ri_crow = row; 1529 ri->ri_ccol = col; 1530 if (on) { 1531 x = ri->ri_ccol * wi + ri->ri_xorigin; 1532 y = ri->ri_crow * he + ri->ri_yorigin; 1533 uni_rectinvert(sc, x, y, wi, he); 1534 ri->ri_flg |= RI_CURSOR; 1535 } 1536 } else { 1537 ri->ri_flg &= ~RI_CURSOR; 1538 ri->ri_crow = row; 1539 ri->ri_ccol = col; 1540 } 1541 1542 return; 1543 } 1544 1545 static void 1546 uni_putchar(void *opaque, int row, int col, u_int c, long attr) 1547 { 1548 struct rasops_info *ri; 1549 struct vcons_screen *scr; 1550 struct unichromefb_softc *sc; 1551 1552 ri = (struct rasops_info *)opaque; 1553 scr = (struct vcons_screen *)ri->ri_hw; 1554 sc = (struct unichromefb_softc *)scr->scr_cookie; 1555 1556 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1557 uint32_t *data; 1558 int fg, bg, ul, uc, i; 1559 int x, y, wi, he; 1560 1561 wi = ri->ri_font->fontwidth; 1562 he = ri->ri_font->fontheight; 1563 1564 if (!CHAR_IN_FONT(c, ri->ri_font)) 1565 return; 1566 1567 rasops_unpack_attr(attr, &fg, &bg, &ul); 1568 x = ri->ri_xorigin + col * wi; 1569 y = ri->ri_yorigin + row * he; 1570 if (c == 0x20) 1571 uni_fillrect(sc, x, y, wi, he, ri->ri_devcmap[bg]); 1572 else { 1573 uc = c - ri->ri_font->firstchar; 1574 data = (uint32_t *)((uint8_t *)ri->ri_font->data + 1575 uc * ri->ri_fontscale); 1576 uni_setup_mono(sc, x, y, wi, he, 1577 ri->ri_devcmap[fg], ri->ri_devcmap[bg]); 1578 for (i = 0; i < (wi * he) / 4; i++) { 1579 MMIO_OUT32(VIA_MMIO_BLTBASE, *data); 1580 data++; 1581 } 1582 } 1583 } 1584 1585 return; 1586 } 1587