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