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