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