1 /* $NetBSD: unichromefb.c,v 1.16 2009/05/06 10:34:33 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.16 2009/05/06 10:34:33 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 74 #include <dev/pci/unichromereg.h> 75 #include <dev/pci/unichromemode.h> 76 #include <dev/pci/unichromehw.h> 77 #include <dev/pci/unichromeconfig.h> 78 #include <dev/pci/unichromeaccel.h> 79 80 #include "vga.h" 81 82 #if NVGA > 0 83 #include <dev/ic/mc6845reg.h> 84 #include <dev/ic/pcdisplayvar.h> 85 #include <dev/ic/vgareg.h> 86 #include <dev/ic/vgavar.h> 87 #endif 88 89 /* XXX */ 90 #define UNICHROMEFB_DEPTH 16 91 #define UNICHROMEFB_MODE VIA_RES_1280X1024 92 #define UNICHROMEFB_WIDTH 1280 93 #define UNICHROMEFB_HEIGHT 1024 94 95 struct unichromefb_softc { 96 device_t sc_dev; 97 struct vcons_data sc_vd; 98 void * sc_fbbase; 99 unsigned int sc_fbaddr; 100 unsigned int sc_fbsize; 101 bus_addr_t sc_mmiobase; 102 bus_size_t sc_mmiosize; 103 104 bus_space_tag_t sc_iot; 105 bus_space_handle_t sc_ioh; 106 107 bus_space_tag_t sc_memt; 108 bus_space_handle_t sc_memh; 109 bus_space_tag_t sc_apmemt; 110 bus_space_handle_t sc_apmemh; 111 112 struct pci_attach_args sc_pa; 113 114 int sc_width; 115 int sc_height; 116 int sc_depth; 117 int sc_stride; 118 119 int sc_wsmode; 120 121 int sc_accel; 122 }; 123 124 static int unichromefb_match(device_t, cfdata_t, void *); 125 static void unichromefb_attach(device_t, device_t, void *); 126 127 static int unichromefb_drm_print(void *, const char *); 128 static int unichromefb_drm_unmap(struct unichromefb_softc *); 129 static int unichromefb_drm_map(struct unichromefb_softc *); 130 131 struct wsscreen_descr unichromefb_stdscreen = { 132 "fb", 133 0, 0, 134 NULL, 135 8, 16, 136 WSSCREEN_WSCOLORS, NULL, 137 }; 138 139 static int unichromefb_ioctl(void *, void *, u_long, void *, int, 140 struct lwp *); 141 static paddr_t unichromefb_mmap(void *, void *, off_t, int); 142 143 static void unichromefb_init_screen(void *, struct vcons_screen *, 144 int, long *); 145 146 /* hardware access */ 147 static uint8_t uni_rd(struct unichromefb_softc *, int, uint8_t); 148 static void uni_wr(struct unichromefb_softc *, int, uint8_t, uint8_t); 149 static void uni_wr_mask(struct unichromefb_softc *, int, uint8_t, 150 uint8_t, uint8_t); 151 static void uni_wr_x(struct unichromefb_softc *, struct io_reg *, int); 152 static void uni_wr_dac(struct unichromefb_softc *, uint8_t, uint8_t, 153 uint8_t, uint8_t); 154 155 /* helpers */ 156 static struct VideoModeTable * uni_getmode(int); 157 static void uni_setmode(struct unichromefb_softc *, int, int); 158 static void uni_crt_lock(struct unichromefb_softc *); 159 static void uni_crt_unlock(struct unichromefb_softc *); 160 static void uni_crt_enable(struct unichromefb_softc *); 161 static void uni_crt_disable(struct unichromefb_softc *); 162 static void uni_screen_enable(struct unichromefb_softc *); 163 static void uni_screen_disable(struct unichromefb_softc *); 164 static void uni_set_start(struct unichromefb_softc *); 165 static void uni_set_crtc(struct unichromefb_softc *, 166 struct crt_mode_table *, int, int, int); 167 static void uni_load_crtc(struct unichromefb_softc *, struct display_timing, 168 int); 169 static void uni_load_reg(struct unichromefb_softc *, int, int, 170 struct io_register *, int); 171 static void uni_fix_crtc(struct unichromefb_softc *); 172 static void uni_load_offset(struct unichromefb_softc *, int, int, int); 173 static void uni_load_fetchcnt(struct unichromefb_softc *, int, int, int); 174 static void uni_load_fifo(struct unichromefb_softc *, int, int, int); 175 static void uni_set_depth(struct unichromefb_softc *, int, int); 176 static uint32_t uni_get_clkval(struct unichromefb_softc *, int); 177 static void uni_set_vclk(struct unichromefb_softc *, uint32_t, int); 178 static void uni_init_dac(struct unichromefb_softc *, int); 179 static void uni_init_accel(struct unichromefb_softc *); 180 static void uni_set_accel_depth(struct unichromefb_softc *); 181 182 /* graphics ops */ 183 static void uni_wait_idle(struct unichromefb_softc *); 184 static void uni_fillrect(struct unichromefb_softc *, 185 int, int, int, int, int); 186 static void uni_rectinvert(struct unichromefb_softc *, 187 int, int, int, int); 188 static void uni_bitblit(struct unichromefb_softc *, int, int, int, int, 189 int, int); 190 static void uni_setup_mono(struct unichromefb_softc *, int, int, int, 191 int, uint32_t, uint32_t); 192 #if notyet 193 static void uni_cursor_show(struct unichromefb_softc *); 194 static void uni_cursor_hide(struct unichromefb_softc *); 195 #endif 196 197 /* rasops glue */ 198 static void uni_copycols(void *, int, int, int, int); 199 static void uni_copyrows(void *, int, int, int); 200 static void uni_erasecols(void *, int, int, int, long); 201 static void uni_eraserows(void *, int, int, long); 202 static void uni_cursor(void *, int, int, int); 203 static void uni_putchar(void *, int, int, u_int, long); 204 205 struct wsdisplay_accessops unichromefb_accessops = { 206 unichromefb_ioctl, 207 unichromefb_mmap, 208 NULL, 209 NULL, 210 NULL, 211 NULL, 212 NULL, 213 NULL, 214 }; 215 216 static struct vcons_screen unichromefb_console_screen; 217 218 const struct wsscreen_descr *_unichromefb_scrlist[] = { 219 &unichromefb_stdscreen, 220 }; 221 222 struct wsscreen_list unichromefb_screenlist = { 223 sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *), 224 _unichromefb_scrlist 225 }; 226 227 CFATTACH_DECL_NEW(unichromefb, sizeof(struct unichromefb_softc), 228 unichromefb_match, unichromefb_attach, NULL, NULL); 229 230 static int 231 unichromefb_match(device_t parent, cfdata_t match, void *opaque) 232 { 233 struct pci_attach_args *pa; 234 235 pa = (struct pci_attach_args *)opaque; 236 237 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY || 238 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA) 239 return 0; 240 241 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH) 242 return 0; 243 244 switch (PCI_PRODUCT(pa->pa_id)) { 245 case PCI_PRODUCT_VIATECH_VT3314_IG: 246 return 10; /* beat vga(4) */ 247 } 248 249 return 0; 250 } 251 252 static void 253 unichromefb_attach(device_t parent, device_t self, void *opaque) 254 { 255 struct unichromefb_softc *sc = device_private(self); 256 struct pci_attach_args *pa; 257 struct rasops_info *ri; 258 struct wsemuldisplaydev_attach_args aa; 259 uint8_t val; 260 long defattr; 261 262 pa = (struct pci_attach_args *)opaque; 263 264 sc->sc_dev = self; 265 sc->sc_width = UNICHROMEFB_WIDTH; 266 sc->sc_height = UNICHROMEFB_HEIGHT; 267 sc->sc_depth = UNICHROMEFB_DEPTH; 268 sc->sc_stride = sc->sc_width * (sc->sc_depth / 8); 269 270 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL; 271 272 sc->sc_iot = pa->pa_iot; 273 sc->sc_pa = *pa; 274 275 #if NVGA > 0 276 /* XXX vga_cnattach claims the I/O registers that we need; 277 * we need to nuke it here so we can take over. 278 */ 279 vga_cndetach(); 280 #endif 281 282 if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) { 283 aprint_error(": failed to map I/O registers\n"); 284 return; 285 } 286 287 sc->sc_apmemt = pa->pa_memt; 288 val = uni_rd(sc, VIASR, SR30); 289 sc->sc_fbaddr = val << 24; 290 val = uni_rd(sc, VIASR, SR39); 291 sc->sc_fbsize = val * (4*1024*1024); 292 if (sc->sc_fbsize < 16*1024*1024 || sc->sc_fbsize > 64*1024*1024) 293 sc->sc_fbsize = 16*1024*1024; 294 if (bus_space_map(sc->sc_apmemt, sc->sc_fbaddr, sc->sc_fbsize, 295 BUS_SPACE_MAP_LINEAR, &sc->sc_apmemh)) { 296 aprint_error(": failed to map aperture at 0x%08x/0x%x\n", 297 sc->sc_fbaddr, sc->sc_fbsize); 298 return; 299 } 300 sc->sc_fbbase = (void *)bus_space_vaddr(sc->sc_apmemt, sc->sc_apmemh); 301 302 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, 303 &sc->sc_memt, &sc->sc_memh, &sc->sc_mmiobase, 304 &sc->sc_mmiosize)) { 305 sc->sc_accel = 0; 306 aprint_error(": failed to map MMIO registers\n"); 307 } else { 308 sc->sc_accel = 1; 309 } 310 311 aprint_naive("\n"); 312 aprint_normal(": VIA UniChrome frame buffer\n"); 313 314 if (sc->sc_accel) 315 aprint_normal_dev(self, "MMIO @0x%08x/0x%x\n", 316 (uint32_t)sc->sc_mmiobase, 317 (uint32_t)sc->sc_mmiosize); 318 319 ri = &unichromefb_console_screen.scr_ri; 320 memset(ri, 0, sizeof(struct rasops_info)); 321 322 vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen, 323 &unichromefb_accessops); 324 sc->sc_vd.init_screen = unichromefb_init_screen; 325 326 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth); 327 328 uni_init_dac(sc, IGA1); 329 if (sc->sc_accel) { 330 uni_init_accel(sc); 331 uni_fillrect(sc, 0, 0, sc->sc_width, sc->sc_height, 0); 332 } 333 334 aprint_normal_dev(self, "FB @0x%08x (%dx%dx%d)\n", 335 sc->sc_fbaddr, sc->sc_width, sc->sc_height, sc->sc_depth); 336 337 unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 338 vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr); 339 340 unichromefb_stdscreen.ncols = ri->ri_cols; 341 unichromefb_stdscreen.nrows = ri->ri_rows; 342 unichromefb_stdscreen.textops = &ri->ri_ops; 343 unichromefb_stdscreen.capabilities = ri->ri_caps; 344 unichromefb_stdscreen.modecookie = NULL; 345 346 wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr); 347 348 aa.console = 1; /* XXX */ 349 aa.scrdata = &unichromefb_screenlist; 350 aa.accessops = &unichromefb_accessops; 351 aa.accesscookie = &sc->sc_vd; 352 353 config_found(self, &aa, wsemuldisplaydevprint); 354 355 config_found_ia(self, "drm", opaque, unichromefb_drm_print); 356 357 return; 358 } 359 360 static int 361 unichromefb_drm_print(void *opaque, const char *pnp) 362 { 363 if (pnp) 364 aprint_normal("drm at %s", pnp); 365 366 return UNCONF; 367 } 368 369 static int 370 unichromefb_drm_unmap(struct unichromefb_softc *sc) 371 { 372 aprint_debug_dev(sc->sc_dev, "releasing bus resources\n"); 373 374 bus_space_unmap(sc->sc_apmemt, sc->sc_apmemh, sc->sc_fbsize); 375 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mmiosize); 376 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0x20); 377 378 return 0; 379 } 380 381 static int 382 unichromefb_drm_map(struct unichromefb_softc *sc) 383 { 384 int rv; 385 386 rv = bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, 387 &sc->sc_ioh); 388 if (rv) { 389 aprint_error_dev(sc->sc_dev, "failed to map I/O registers\n"); 390 return rv; 391 } 392 rv = bus_space_map(sc->sc_apmemt, sc->sc_fbaddr, sc->sc_fbsize, 393 BUS_SPACE_MAP_LINEAR, &sc->sc_apmemh); 394 if (rv) { 395 aprint_error_dev(sc->sc_dev, 396 "failed to map aperture at 0x%08x/0x%x\n", 397 sc->sc_fbaddr, sc->sc_fbsize); 398 return rv; 399 } 400 sc->sc_fbbase = (void *)bus_space_vaddr(sc->sc_apmemt, sc->sc_apmemh); 401 rv = pci_mapreg_map(&sc->sc_pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, 402 &sc->sc_memt, &sc->sc_memh, &sc->sc_mmiobase, 403 &sc->sc_mmiosize); 404 if (rv) { 405 aprint_error_dev(sc->sc_dev, "failed to map MMIO registers\n"); 406 sc->sc_accel = 0; 407 } 408 409 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth); 410 uni_init_dac(sc, IGA1); 411 if (sc->sc_accel) 412 uni_init_accel(sc); 413 414 aprint_debug_dev(sc->sc_dev, "re-acquired bus resources\n"); 415 416 return 0; 417 } 418 419 static int 420 unichromefb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 421 struct lwp *l) 422 { 423 struct vcons_data *vd; 424 struct unichromefb_softc *sc; 425 struct wsdisplay_fbinfo *fb; 426 427 vd = (struct vcons_data *)v; 428 sc = (struct unichromefb_softc *)vd->cookie; 429 430 switch (cmd) { 431 case WSDISPLAYIO_GTYPE: 432 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 433 return 0; 434 case WSDISPLAYIO_GINFO: 435 if (vd->active != NULL) { 436 fb = (struct wsdisplay_fbinfo *)data; 437 fb->width = sc->sc_width; 438 fb->height = sc->sc_height; 439 fb->depth = sc->sc_depth; 440 fb->cmsize = 256; 441 return 0; 442 } else 443 return ENODEV; 444 case WSDISPLAYIO_GVIDEO: 445 return ENODEV; 446 case WSDISPLAYIO_SVIDEO: 447 return ENODEV; 448 case WSDISPLAYIO_GETCMAP: 449 return EINVAL; 450 case WSDISPLAYIO_PUTCMAP: 451 return EINVAL; 452 case WSDISPLAYIO_LINEBYTES: 453 *(u_int *)data = sc->sc_stride; 454 return 0; 455 case WSDISPLAYIO_SMODE: 456 { 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 484 return EPASSTHROUGH; 485 } 486 487 static paddr_t 488 unichromefb_mmap(void *v, void *vs, off_t offset, int prot) 489 { 490 return -1; 491 } 492 493 static void 494 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing, 495 long *defattr) 496 { 497 struct unichromefb_softc *sc; 498 struct rasops_info *ri; 499 500 sc = (struct unichromefb_softc *)c; 501 ri = &scr->scr_ri; 502 ri->ri_flg = RI_CENTER; 503 ri->ri_depth = sc->sc_depth; 504 ri->ri_width = sc->sc_width; 505 ri->ri_height = sc->sc_height; 506 ri->ri_stride = sc->sc_stride; 507 ri->ri_bits = sc->sc_fbbase; 508 if (existing) 509 ri->ri_flg |= RI_CLEAR; 510 511 switch (ri->ri_depth) { 512 case 32: 513 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8; 514 ri->ri_rpos = 16; 515 ri->ri_gpos = 8; 516 ri->ri_bpos = 0; 517 break; 518 case 16: 519 ri->ri_rnum = 5; 520 ri->ri_gnum = 6; 521 ri->ri_bnum = 5; 522 ri->ri_rpos = 11; 523 ri->ri_gpos = 5; 524 ri->ri_bpos = 0; 525 break; 526 } 527 528 rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8); 529 ri->ri_caps = WSSCREEN_WSCOLORS; 530 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 531 sc->sc_width / ri->ri_font->fontwidth); 532 533 ri->ri_hw = scr; 534 if (sc->sc_accel) { 535 ri->ri_ops.copyrows = uni_copyrows; 536 ri->ri_ops.copycols = uni_copycols; 537 ri->ri_ops.eraserows = uni_eraserows; 538 ri->ri_ops.erasecols = uni_erasecols; 539 ri->ri_ops.cursor = uni_cursor; 540 ri->ri_ops.putchar = uni_putchar; 541 } 542 543 return; 544 } 545 546 /* 547 * hardware access 548 */ 549 static uint8_t 550 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx) 551 { 552 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx); 553 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1); 554 } 555 556 static void 557 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val) 558 { 559 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx); 560 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val); 561 } 562 563 static void 564 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx, 565 uint8_t val, uint8_t mask) 566 { 567 uint8_t tmp; 568 569 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx); 570 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1); 571 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, 572 ((val & mask) | (tmp & ~mask))); 573 } 574 575 static void 576 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx, 577 uint8_t r, uint8_t g, uint8_t b) 578 { 579 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx); 580 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r); 581 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g); 582 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b); 583 } 584 585 static void 586 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num) 587 { 588 int i; 589 uint8_t tmp; 590 591 for (i = 0; i < num; i++) { 592 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port, 593 tbl[i].index); 594 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 595 tbl[i].port + 1); 596 tmp = (tmp & (~tbl[i].mask)) | tbl[i].value; 597 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1, 598 tmp); 599 } 600 } 601 602 /* 603 * helpers 604 */ 605 static struct VideoModeTable * 606 uni_getmode(int mode) 607 { 608 int i; 609 610 for (i = 0; i < NUM_TOTAL_MODETABLE; i++) 611 if (CLE266Modes[i].ModeIndex == mode) 612 return &CLE266Modes[i]; 613 614 return NULL; 615 } 616 617 static void 618 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp) 619 { 620 struct VideoModeTable *vtbl; 621 struct crt_mode_table *crt; 622 int i; 623 624 /* XXX */ 625 vtbl = uni_getmode(idx); 626 if (vtbl == NULL) 627 panic("%s: unsupported mode: %d\n", 628 device_xname(sc->sc_dev), idx); 629 630 crt = vtbl->crtc; 631 632 uni_screen_disable(sc); 633 634 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus); 635 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0); 636 637 /* XXX assume CN900 for now */ 638 uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs); 639 640 uni_crt_disable(sc); 641 642 /* Fill VPIT params */ 643 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc); 644 645 /* Write sequencer */ 646 for (i = 1; i <= StdSR; i++) { 647 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i); 648 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1, 649 VPIT.SR[i - 1]); 650 } 651 652 uni_set_start(sc); 653 654 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1); 655 656 for (i = 0; i < StdGR; i++) { 657 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i); 658 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1, 659 VPIT.GR[i]); 660 } 661 662 for (i = 0; i < StdAR; i++) { 663 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus); 664 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i); 665 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 666 VPIT.AR[i]); 667 } 668 669 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus); 670 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20); 671 672 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1); 673 /* set crt output path */ 674 uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6); 675 676 uni_crt_enable(sc); 677 uni_screen_enable(sc); 678 679 return; 680 } 681 682 static void 683 uni_crt_lock(struct unichromefb_softc *sc) 684 { 685 uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7); 686 } 687 688 static void 689 uni_crt_unlock(struct unichromefb_softc *sc) 690 { 691 uni_wr_mask(sc, VIACR, CR11, 0, BIT7); 692 uni_wr_mask(sc, VIACR, CR47, 0, BIT0); 693 } 694 695 static void 696 uni_crt_enable(struct unichromefb_softc *sc) 697 { 698 uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4); 699 } 700 701 static void 702 uni_crt_disable(struct unichromefb_softc *sc) 703 { 704 uni_wr_mask(sc, VIACR, CR36, BIT5+BIT4, BIT5+BIT4); 705 } 706 707 static void 708 uni_screen_enable(struct unichromefb_softc *sc) 709 { 710 uni_wr_mask(sc, VIASR, SR01, 0, BIT5); 711 } 712 713 static void 714 uni_screen_disable(struct unichromefb_softc *sc) 715 { 716 uni_wr_mask(sc, VIASR, SR01, 0x20, BIT5); 717 } 718 719 static void 720 uni_set_start(struct unichromefb_softc *sc) 721 { 722 uni_crt_unlock(sc); 723 724 uni_wr(sc, VIACR, CR0C, 0x00); 725 uni_wr(sc, VIACR, CR0D, 0x00); 726 uni_wr(sc, VIACR, CR34, 0x00); 727 uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1); 728 729 uni_wr(sc, VIACR, CR62, 0x00); 730 uni_wr(sc, VIACR, CR63, 0x00); 731 uni_wr(sc, VIACR, CR64, 0x00); 732 uni_wr(sc, VIACR, CRA3, 0x00); 733 734 uni_crt_lock(sc); 735 } 736 737 static void 738 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl, 739 int mode, int bpp_byte, int iga) 740 { 741 struct VideoModeTable *vtbl; 742 struct display_timing crtreg; 743 int i; 744 int index; 745 int haddr, vaddr; 746 uint8_t val; 747 uint32_t pll_d_n; 748 749 index = 0; 750 751 vtbl = uni_getmode(mode); 752 for (i = 0; i < vtbl->mode_array; i++) { 753 index = i; 754 if (ctbl[i].refresh_rate == 60) 755 break; 756 } 757 758 crtreg = ctbl[index].crtc; 759 760 haddr = crtreg.hor_addr; 761 vaddr = crtreg.ver_addr; 762 763 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc); 764 if (ctbl[index].h_sync_polarity == NEGATIVE) { 765 if (ctbl[index].v_sync_polarity == NEGATIVE) 766 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 767 (val & (~(BIT6+BIT7))) | (BIT6+BIT7)); 768 else 769 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 770 (val & (~(BIT6+BIT7))) | (BIT6)); 771 } else { 772 if (ctbl[index].v_sync_polarity == NEGATIVE) 773 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 774 (val & (~(BIT6+BIT7))) | (BIT7)); 775 else 776 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, 777 (val & (~(BIT6+BIT7)))); 778 } 779 780 if (iga == IGA1) { 781 uni_crt_unlock(sc); 782 uni_wr(sc, VIACR, CR09, 0x00); 783 uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6); 784 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7); 785 } 786 787 uni_load_crtc(sc, crtreg, iga); 788 uni_fix_crtc(sc); 789 uni_crt_lock(sc); 790 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7); 791 792 uni_load_offset(sc, haddr, bpp_byte, iga); 793 uni_load_fetchcnt(sc, haddr, bpp_byte, iga); 794 uni_load_fifo(sc, iga, haddr, vaddr); 795 796 uni_set_depth(sc, bpp_byte, iga); 797 pll_d_n = uni_get_clkval(sc, ctbl[index].clk); 798 uni_set_vclk(sc, pll_d_n, iga); 799 } 800 801 static void 802 uni_load_crtc(struct unichromefb_softc *sc, 803 struct display_timing device_timing, int iga) 804 { 805 int regnum, val; 806 struct io_register *reg; 807 int i; 808 809 regnum = val = 0; 810 reg = NULL; 811 812 uni_crt_unlock(sc); 813 814 for (i = 0; i < 12; i++) { 815 switch (iga) { 816 case IGA1: 817 switch (i) { 818 case H_TOTAL_INDEX: 819 val = IGA1_HOR_TOTAL_FORMULA( 820 device_timing.hor_total); 821 regnum = iga1_crtc_reg.hor_total.reg_num; 822 reg = iga1_crtc_reg.hor_total.reg; 823 break; 824 case H_ADDR_INDEX: 825 val = IGA1_HOR_ADDR_FORMULA( 826 device_timing.hor_addr); 827 regnum = iga1_crtc_reg.hor_addr.reg_num; 828 reg = iga1_crtc_reg.hor_addr.reg; 829 break; 830 case H_BLANK_START_INDEX: 831 val = IGA1_HOR_BLANK_START_FORMULA( 832 device_timing.hor_blank_start); 833 regnum = iga1_crtc_reg.hor_blank_start.reg_num; 834 reg = iga1_crtc_reg.hor_blank_start.reg; 835 break; 836 case H_BLANK_END_INDEX: 837 val = IGA1_HOR_BLANK_END_FORMULA( 838 device_timing.hor_blank_start, 839 device_timing.hor_blank_end); 840 regnum = iga1_crtc_reg.hor_blank_end.reg_num; 841 reg = iga1_crtc_reg.hor_blank_end.reg; 842 break; 843 case H_SYNC_START_INDEX: 844 val = IGA1_HOR_SYNC_START_FORMULA( 845 device_timing.hor_sync_start); 846 regnum = iga1_crtc_reg.hor_sync_start.reg_num; 847 reg = iga1_crtc_reg.hor_sync_start.reg; 848 break; 849 case H_SYNC_END_INDEX: 850 val = IGA1_HOR_SYNC_END_FORMULA( 851 device_timing.hor_sync_start, 852 device_timing.hor_sync_end); 853 regnum = iga1_crtc_reg.hor_sync_end.reg_num; 854 reg = iga1_crtc_reg.hor_sync_end.reg; 855 break; 856 case V_TOTAL_INDEX: 857 val = IGA1_VER_TOTAL_FORMULA( 858 device_timing.ver_total); 859 regnum = iga1_crtc_reg.ver_total.reg_num; 860 reg = iga1_crtc_reg.ver_total.reg; 861 break; 862 case V_ADDR_INDEX: 863 val = IGA1_VER_ADDR_FORMULA( 864 device_timing.ver_addr); 865 regnum = iga1_crtc_reg.ver_addr.reg_num; 866 reg = iga1_crtc_reg.ver_addr.reg; 867 break; 868 case V_BLANK_START_INDEX: 869 val = IGA1_VER_BLANK_START_FORMULA( 870 device_timing.ver_blank_start); 871 regnum = iga1_crtc_reg.ver_blank_start.reg_num; 872 reg = iga1_crtc_reg.ver_blank_start.reg; 873 break; 874 case V_BLANK_END_INDEX: 875 val = IGA1_VER_BLANK_END_FORMULA( 876 device_timing.ver_blank_start, 877 device_timing.ver_blank_end); 878 regnum = iga1_crtc_reg.ver_blank_end.reg_num; 879 reg = iga1_crtc_reg.ver_blank_end.reg; 880 break; 881 case V_SYNC_START_INDEX: 882 val = IGA1_VER_SYNC_START_FORMULA( 883 device_timing.ver_sync_start); 884 regnum = iga1_crtc_reg.ver_sync_start.reg_num; 885 reg = iga1_crtc_reg.ver_sync_start.reg; 886 break; 887 case V_SYNC_END_INDEX: 888 val = IGA1_VER_SYNC_END_FORMULA( 889 device_timing.ver_sync_start, 890 device_timing.ver_sync_end); 891 regnum = iga1_crtc_reg.ver_sync_end.reg_num; 892 reg = iga1_crtc_reg.ver_sync_end.reg; 893 break; 894 default: 895 aprint_error_dev(sc->sc_dev, 896 "unknown index %d while setting up CRTC\n", 897 i); 898 break; 899 } 900 break; 901 case IGA2: 902 aprint_error_dev(sc->sc_dev, "%s: IGA2 not supported\n", 903 __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 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 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 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 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 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 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 aprint_error_dev(sc->sc_dev, 1084 "%s: mode (%d) unsupported\n", __func__, bpp); 1085 } 1086 break; 1087 default: 1088 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 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_dev(sc->sc_dev, "can't find matching PLL value\n"); 1107 1108 return 0; 1109 } 1110 1111 static void 1112 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga) 1113 { 1114 uint8_t val; 1115 1116 /* hardware reset on */ 1117 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7); 1118 1119 switch (iga) { 1120 case IGA1: 1121 /* XXX only CN900 is supported */ 1122 uni_wr(sc, VIASR, SR44, clk / 0x10000); 1123 uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100); 1124 uni_wr(sc, VIASR, SR46, clk % 0x100); 1125 break; 1126 default: 1127 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n", 1128 __func__); 1129 break; 1130 } 1131 1132 /* hardware reset off */ 1133 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7); 1134 1135 /* reset pll */ 1136 switch (iga) { 1137 case IGA1: 1138 uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1); 1139 uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1); 1140 break; 1141 } 1142 1143 /* good to go */ 1144 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc); 1145 val |= (BIT2+BIT3); 1146 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val); 1147 1148 return; 1149 } 1150 1151 static void 1152 uni_init_dac(struct unichromefb_softc *sc, int iga) 1153 { 1154 int i; 1155 1156 /* XXX only IGA1 for now */ 1157 uni_wr_mask(sc, VIASR, SR1A, 0x00, BIT0); 1158 uni_wr_mask(sc, VIASR, SR18, 0x00, BIT7+BIT6); 1159 for (i = 0; i < 256; i++) 1160 uni_wr_dac(sc, i, 1161 palLUT_table[i].red, palLUT_table[i].green, palLUT_table[i].blue); 1162 1163 uni_wr_mask(sc, VIASR, SR18, 0xc0, BIT7+BIT6); 1164 1165 return; 1166 } 1167 1168 static void 1169 uni_init_accel(struct unichromefb_softc *sc) 1170 { 1171 1172 /* init 2D engine regs to reset 2D engine */ 1173 MMIO_OUT32(VIA_REG_GEMODE, 0); 1174 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1175 MMIO_OUT32(VIA_REG_DSTPOS, 0); 1176 MMIO_OUT32(VIA_REG_DIMENSION, 0); 1177 MMIO_OUT32(VIA_REG_PATADDR, 0); 1178 MMIO_OUT32(VIA_REG_FGCOLOR, 0); 1179 MMIO_OUT32(VIA_REG_BGCOLOR, 0); 1180 MMIO_OUT32(VIA_REG_CLIPTL, 0); 1181 MMIO_OUT32(VIA_REG_CLIPBR, 0); 1182 MMIO_OUT32(VIA_REG_OFFSET, 0); 1183 MMIO_OUT32(VIA_REG_KEYCONTROL, 0); 1184 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1185 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1186 MMIO_OUT32(VIA_REG_PITCH, 0); 1187 MMIO_OUT32(VIA_REG_MONOPAT1, 0); 1188 1189 /* init AGP and VQ registers */ 1190 MMIO_OUT32(VIA_REG_TRANSET, 0x00100000); 1191 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000); 1192 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00333004); 1193 MMIO_OUT32(VIA_REG_TRANSPACE, 0x60000000); 1194 MMIO_OUT32(VIA_REG_TRANSPACE, 0x61000000); 1195 MMIO_OUT32(VIA_REG_TRANSPACE, 0x62000000); 1196 MMIO_OUT32(VIA_REG_TRANSPACE, 0x63000000); 1197 MMIO_OUT32(VIA_REG_TRANSPACE, 0x64000000); 1198 MMIO_OUT32(VIA_REG_TRANSPACE, 0x7d000000); 1199 1200 MMIO_OUT32(VIA_REG_TRANSET, 0xfe020000); 1201 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000); 1202 1203 /* disable VQ */ 1204 MMIO_OUT32(VIA_REG_TRANSET, 0x00fe0000); 1205 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000004); 1206 MMIO_OUT32(VIA_REG_TRANSPACE, 0x40008c0f); 1207 MMIO_OUT32(VIA_REG_TRANSPACE, 0x44000000); 1208 MMIO_OUT32(VIA_REG_TRANSPACE, 0x45080c04); 1209 MMIO_OUT32(VIA_REG_TRANSPACE, 0x46800408); 1210 1211 uni_set_accel_depth(sc); 1212 1213 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1214 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1215 1216 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1217 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1218 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1219 1220 return; 1221 } 1222 1223 static void 1224 uni_set_accel_depth(struct unichromefb_softc *sc) 1225 { 1226 uint32_t gemode; 1227 1228 gemode = MMIO_IN32(0x04) & 0xfffffcff; 1229 1230 switch (sc->sc_depth) { 1231 case 32: 1232 gemode |= VIA_GEM_32bpp; 1233 break; 1234 case 16: 1235 gemode |= VIA_GEM_16bpp; 1236 break; 1237 default: 1238 gemode |= VIA_GEM_8bpp; 1239 break; 1240 } 1241 1242 /* set colour depth and pitch */ 1243 MMIO_OUT32(VIA_REG_GEMODE, gemode); 1244 1245 return; 1246 } 1247 1248 static void 1249 uni_wait_idle(struct unichromefb_softc *sc) 1250 { 1251 int loop = 0; 1252 1253 while (!(MMIO_IN32(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && 1254 (loop++ < MAXLOOP)) 1255 ; 1256 1257 while ((MMIO_IN32(VIA_REG_STATUS) & 1258 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && 1259 (loop++ < MAXLOOP)) 1260 ; 1261 1262 if (loop >= MAXLOOP) 1263 aprint_error_dev(sc->sc_dev, "engine stall\n"); 1264 1265 return; 1266 } 1267 1268 static void 1269 uni_fillrect(struct unichromefb_softc *sc, int x, int y, int width, 1270 int height, int colour) 1271 { 1272 1273 uni_wait_idle(sc); 1274 1275 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1276 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1277 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1278 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1279 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1280 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1281 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x)); 1282 MMIO_OUT32(VIA_REG_DIMENSION, 1283 (((height - 1) << 16) | (width - 1))); 1284 MMIO_OUT32(VIA_REG_FGCOLOR, colour); 1285 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0xf0 << 24)); 1286 1287 return; 1288 } 1289 1290 static void 1291 uni_rectinvert(struct unichromefb_softc *sc, int x, int y, int width, 1292 int height) 1293 { 1294 1295 uni_wait_idle(sc); 1296 1297 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1298 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1299 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1300 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1301 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1302 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1303 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x)); 1304 MMIO_OUT32(VIA_REG_DIMENSION, 1305 (((height - 1) << 16) | (width - 1))); 1306 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0x55 << 24)); 1307 1308 return; 1309 } 1310 1311 static void 1312 uni_bitblit(struct unichromefb_softc *sc, int xs, int ys, int xd, int yd, int width, int height) 1313 { 1314 uint32_t dir; 1315 1316 dir = 0; 1317 1318 if (ys < yd) { 1319 yd += height - 1; 1320 ys += height - 1; 1321 dir |= 0x4000; 1322 } 1323 1324 if (xs < xd) { 1325 xd += width - 1; 1326 xs += width - 1; 1327 dir |= 0x8000; 1328 } 1329 1330 uni_wait_idle(sc); 1331 1332 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1333 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1334 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1335 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1336 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1337 MMIO_OUT32(VIA_REG_SRCPOS, ys << 16 | xs); 1338 MMIO_OUT32(VIA_REG_DSTPOS, yd << 16 | xd); 1339 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1)); 1340 MMIO_OUT32(VIA_REG_GECMD, (0x01 | dir | (0xcc << 24))); 1341 1342 return; 1343 } 1344 1345 static void 1346 uni_setup_mono(struct unichromefb_softc *sc, int xd, int yd, int width, int height, 1347 uint32_t fg, uint32_t bg) 1348 { 1349 1350 uni_wait_idle(sc); 1351 1352 MMIO_OUT32(VIA_REG_SRCBASE, 0); 1353 MMIO_OUT32(VIA_REG_DSTBASE, 0); 1354 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE | 1355 (((sc->sc_width * sc->sc_depth >> 3) >> 3) | 1356 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16))); 1357 MMIO_OUT32(VIA_REG_SRCPOS, 0); 1358 MMIO_OUT32(VIA_REG_DSTPOS, (yd << 16) | xd); 1359 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1)); 1360 MMIO_OUT32(VIA_REG_FGCOLOR, fg); 1361 MMIO_OUT32(VIA_REG_BGCOLOR, bg); 1362 MMIO_OUT32(VIA_REG_GECMD, 0xcc020142); 1363 1364 return; 1365 } 1366 1367 #if notyet 1368 static void 1369 uni_cursor_show(struct unichromefb_softc *sc) 1370 { 1371 uint32_t val; 1372 1373 val = MMIO_IN32(VIA_REG_CURSOR_MODE); 1374 val |= 1; 1375 MMIO_OUT32(VIA_REG_CURSOR_MODE, val); 1376 1377 return; 1378 } 1379 1380 static void 1381 uni_cursor_hide(struct unichromefb_softc *sc) 1382 { 1383 uint32_t val; 1384 1385 val = MMIO_IN32(VIA_REG_CURSOR_MODE); 1386 val &= 0xfffffffe; 1387 MMIO_OUT32(VIA_REG_CURSOR_MODE, val); 1388 1389 return; 1390 } 1391 #endif 1392 1393 /* 1394 * rasops glue 1395 */ 1396 static void 1397 uni_copycols(void *opaque, int row, int srccol, int dstcol, int ncols) 1398 { 1399 struct rasops_info *ri; 1400 struct vcons_screen *scr; 1401 struct unichromefb_softc *sc; 1402 int xs, xd, y, width, height; 1403 1404 ri = (struct rasops_info *)opaque; 1405 scr = (struct vcons_screen *)ri->ri_hw; 1406 sc = (struct unichromefb_softc *)scr->scr_cookie; 1407 1408 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1409 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1410 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1411 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1412 width = ri->ri_font->fontwidth * ncols; 1413 height = ri->ri_font->fontheight; 1414 uni_bitblit(sc, xs, y, xd, y, width, height); 1415 } 1416 1417 return; 1418 } 1419 1420 static void 1421 uni_copyrows(void *opaque, int srcrow, int dstrow, int nrows) 1422 { 1423 struct rasops_info *ri; 1424 struct vcons_screen *scr; 1425 struct unichromefb_softc *sc; 1426 int x, ys, yd, width, height; 1427 1428 ri = (struct rasops_info *)opaque; 1429 scr = (struct vcons_screen *)ri->ri_hw; 1430 sc = (struct unichromefb_softc *)scr->scr_cookie; 1431 1432 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1433 x = ri->ri_xorigin; 1434 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1435 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1436 width = ri->ri_emuwidth; 1437 height = ri->ri_font->fontheight * nrows; 1438 uni_bitblit(sc, x, ys, x, yd, width, height); 1439 } 1440 1441 return; 1442 } 1443 1444 static void 1445 uni_erasecols(void *opaque, int row, int startcol, int ncols, long fillattr) 1446 { 1447 struct rasops_info *ri; 1448 struct vcons_screen *scr; 1449 struct unichromefb_softc *sc; 1450 int x, y, width, height, fg, bg, ul; 1451 1452 ri = (struct rasops_info *)opaque; 1453 scr = (struct vcons_screen *)ri->ri_hw; 1454 sc = (struct unichromefb_softc *)scr->scr_cookie; 1455 1456 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1457 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1458 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1459 width = ri->ri_font->fontwidth * ncols; 1460 height = ri->ri_font->fontheight; 1461 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1462 uni_fillrect(sc, x, y, width, height, ri->ri_devcmap[bg]); 1463 } 1464 1465 return; 1466 } 1467 1468 static void 1469 uni_eraserows(void *opaque, int row, int nrows, long fillattr) 1470 { 1471 struct rasops_info *ri; 1472 struct vcons_screen *scr; 1473 struct unichromefb_softc *sc; 1474 int x, y, width, height, fg, bg, ul; 1475 1476 ri = (struct rasops_info *)opaque; 1477 scr = (struct vcons_screen *)ri->ri_hw; 1478 sc = (struct unichromefb_softc *)scr->scr_cookie; 1479 1480 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1481 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1482 if ((row == 0) && (nrows == ri->ri_rows)) { 1483 /* clear the whole screen */ 1484 uni_fillrect(sc, 0, 0, ri->ri_width, 1485 ri->ri_height, ri->ri_devcmap[bg]); 1486 } else { 1487 x = ri->ri_xorigin; 1488 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1489 width = ri->ri_emuwidth; 1490 height = ri->ri_font->fontheight * nrows; 1491 uni_fillrect(sc, x, y, width, height, 1492 ri->ri_devcmap[bg]); 1493 } 1494 } 1495 1496 return; 1497 } 1498 1499 static void 1500 uni_cursor(void *opaque, int on, int row, int col) 1501 { 1502 struct rasops_info *ri; 1503 struct vcons_screen *scr; 1504 struct unichromefb_softc *sc; 1505 int x, y, wi, he; 1506 1507 ri = (struct rasops_info *)opaque; 1508 scr = (struct vcons_screen *)ri->ri_hw; 1509 sc = (struct unichromefb_softc *)scr->scr_cookie; 1510 1511 uni_wait_idle(sc); 1512 1513 wi = ri->ri_font->fontwidth; 1514 he = ri->ri_font->fontheight; 1515 1516 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1517 x = ri->ri_ccol * wi + ri->ri_xorigin; 1518 y = ri->ri_crow * he + ri->ri_yorigin; 1519 if (ri->ri_flg & RI_CURSOR) { 1520 uni_rectinvert(sc, x, y, wi, he); 1521 ri->ri_flg &= ~RI_CURSOR; 1522 } 1523 ri->ri_crow = row; 1524 ri->ri_ccol = col; 1525 if (on) { 1526 x = ri->ri_ccol * wi + ri->ri_xorigin; 1527 y = ri->ri_crow * he + ri->ri_yorigin; 1528 uni_rectinvert(sc, x, y, wi, he); 1529 ri->ri_flg |= RI_CURSOR; 1530 } 1531 } else { 1532 ri->ri_flg &= ~RI_CURSOR; 1533 ri->ri_crow = row; 1534 ri->ri_ccol = col; 1535 } 1536 1537 return; 1538 } 1539 1540 static void 1541 uni_putchar(void *opaque, int row, int col, u_int c, long attr) 1542 { 1543 struct rasops_info *ri; 1544 struct vcons_screen *scr; 1545 struct unichromefb_softc *sc; 1546 1547 ri = (struct rasops_info *)opaque; 1548 scr = (struct vcons_screen *)ri->ri_hw; 1549 sc = (struct unichromefb_softc *)scr->scr_cookie; 1550 1551 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) { 1552 uint32_t *data; 1553 int fg, bg, ul, uc, i; 1554 int x, y, wi, he; 1555 1556 wi = ri->ri_font->fontwidth; 1557 he = ri->ri_font->fontheight; 1558 1559 if (!CHAR_IN_FONT(c, ri->ri_font)) 1560 return; 1561 1562 rasops_unpack_attr(attr, &fg, &bg, &ul); 1563 x = ri->ri_xorigin + col * wi; 1564 y = ri->ri_yorigin + row * he; 1565 if (c == 0x20) 1566 uni_fillrect(sc, x, y, wi, he, ri->ri_devcmap[bg]); 1567 else { 1568 uc = c - ri->ri_font->firstchar; 1569 data = (uint32_t *)((uint8_t *)ri->ri_font->data + 1570 uc * ri->ri_fontscale); 1571 uni_setup_mono(sc, x, y, wi, he, 1572 ri->ri_devcmap[fg], ri->ri_devcmap[bg]); 1573 for (i = 0; i < (wi * he) / 4; i++) { 1574 MMIO_OUT32(VIA_MMIO_BLTBASE, *data); 1575 data++; 1576 } 1577 } 1578 } 1579 1580 return; 1581 } 1582