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