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