1 /* $NetBSD: pm2fb.c,v 1.31 2019/12/22 23:23:32 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2012 Michael Lorenz 5 * 2014 Naruaki Etomi 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * A console driver for Permedia 2 graphics controllers 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1.31 2019/12/22 23:23:32 thorpej Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/lwp.h> 42 #include <sys/kauth.h> 43 #include <sys/atomic.h> 44 45 #include <dev/videomode/videomode.h> 46 47 #include <dev/pci/pcivar.h> 48 #include <dev/pci/pcireg.h> 49 #include <dev/pci/pcidevs.h> 50 #include <dev/pci/pciio.h> 51 #include <dev/pci/pm2reg.h> 52 53 #include <dev/wscons/wsdisplayvar.h> 54 #include <dev/wscons/wsconsio.h> 55 #include <dev/wsfont/wsfont.h> 56 #include <dev/rasops/rasops.h> 57 #include <dev/wscons/wsdisplay_vconsvar.h> 58 #include <dev/wscons/wsdisplay_glyphcachevar.h> 59 #include <dev/pci/wsdisplay_pci.h> 60 61 #include <dev/i2c/i2cvar.h> 62 #include <dev/i2c/i2c_bitbang.h> 63 #include <dev/i2c/ddcvar.h> 64 #include <dev/videomode/videomode.h> 65 #include <dev/videomode/edidvar.h> 66 #include <dev/videomode/edidreg.h> 67 68 #include "opt_pm2fb.h" 69 70 #ifdef PM2FB_DEBUG 71 #define DPRINTF aprint_error 72 #else 73 #define DPRINTF while (0) printf 74 #endif 75 76 #if BYTE_ORDER == LITTLE_ENDIAN 77 /* 78 * XXX 79 * A temporary workaround for unaligned blits on little endian hardware. 80 * This makes pm2fb_bitblt() work well on little endian hardware to get 81 * scrolling right, but not much more. Unaligned blits ( as in, where the lower 82 * 2 bits of the source and destination X coordinates don't match ) are still 83 * wrong so the glyph cache is also disabled. 84 */ 85 #define BITBLT_LE_WORKAROUND 86 #endif 87 88 struct pm2fb_softc { 89 device_t sc_dev; 90 91 pci_chipset_tag_t sc_pc; 92 pcitag_t sc_pcitag; 93 94 bus_space_tag_t sc_memt; 95 bus_space_tag_t sc_iot; 96 97 bus_space_handle_t sc_regh; 98 bus_addr_t sc_fb, sc_reg; 99 bus_size_t sc_fbsize, sc_regsize; 100 101 int sc_width, sc_height, sc_depth, sc_stride; 102 int sc_locked; 103 struct vcons_screen sc_console_screen; 104 struct wsscreen_descr sc_defaultscreen_descr; 105 const struct wsscreen_descr *sc_screens[1]; 106 struct wsscreen_list sc_screenlist; 107 struct vcons_data vd; 108 int sc_mode; 109 u_char sc_cmap_red[256]; 110 u_char sc_cmap_green[256]; 111 u_char sc_cmap_blue[256]; 112 /* engine stuff */ 113 uint32_t sc_pprod; 114 int sc_is_pm2; 115 /* i2c stuff */ 116 struct i2c_controller sc_i2c; 117 uint8_t sc_edid_data[128]; 118 struct edid_info sc_ei; 119 const struct videomode *sc_videomode; 120 glyphcache sc_gc; 121 }; 122 123 static int pm2fb_match(device_t, cfdata_t, void *); 124 static void pm2fb_attach(device_t, device_t, void *); 125 126 CFATTACH_DECL_NEW(pm2fb, sizeof(struct pm2fb_softc), 127 pm2fb_match, pm2fb_attach, NULL, NULL); 128 129 extern const u_char rasops_cmap[768]; 130 131 static int pm2fb_ioctl(void *, void *, u_long, void *, int, 132 struct lwp *); 133 static paddr_t pm2fb_mmap(void *, void *, off_t, int); 134 static void pm2fb_init_screen(void *, struct vcons_screen *, int, long *); 135 136 static int pm2fb_putcmap(struct pm2fb_softc *, struct wsdisplay_cmap *); 137 static int pm2fb_getcmap(struct pm2fb_softc *, struct wsdisplay_cmap *); 138 static void pm2fb_init_palette(struct pm2fb_softc *); 139 static int pm2fb_putpalreg(struct pm2fb_softc *, uint8_t, uint8_t, 140 uint8_t, uint8_t); 141 142 static void pm2fb_init(struct pm2fb_softc *); 143 static inline void pm2fb_wait(struct pm2fb_softc *, int); 144 static void pm2fb_flush_engine(struct pm2fb_softc *); 145 static void pm2fb_rectfill(struct pm2fb_softc *, int, int, int, int, 146 uint32_t); 147 static void pm2fb_rectfill_a(void *, int, int, int, int, long); 148 static void pm2fb_bitblt(void *, int, int, int, int, int, int, int); 149 150 static void pm2fb_cursor(void *, int, int, int); 151 static void pm2fb_putchar(void *, int, int, u_int, long); 152 static void pm2fb_putchar_aa(void *, int, int, u_int, long); 153 static void pm2fb_copycols(void *, int, int, int, int); 154 static void pm2fb_erasecols(void *, int, int, int, long); 155 static void pm2fb_copyrows(void *, int, int, int); 156 static void pm2fb_eraserows(void *, int, int, long); 157 158 struct wsdisplay_accessops pm2fb_accessops = { 159 pm2fb_ioctl, 160 pm2fb_mmap, 161 NULL, /* alloc_screen */ 162 NULL, /* free_screen */ 163 NULL, /* show_screen */ 164 NULL, /* load_font */ 165 NULL, /* pollc */ 166 NULL /* scroll */ 167 }; 168 169 /* I2C glue */ 170 static int pm2fb_i2c_send_start(void *, int); 171 static int pm2fb_i2c_send_stop(void *, int); 172 static int pm2fb_i2c_initiate_xfer(void *, i2c_addr_t, int); 173 static int pm2fb_i2c_read_byte(void *, uint8_t *, int); 174 static int pm2fb_i2c_write_byte(void *, uint8_t, int); 175 176 /* I2C bitbang glue */ 177 static void pm2fb_i2cbb_set_bits(void *, uint32_t); 178 static void pm2fb_i2cbb_set_dir(void *, uint32_t); 179 static uint32_t pm2fb_i2cbb_read(void *); 180 181 static void pm2_setup_i2c(struct pm2fb_softc *); 182 183 static const struct i2c_bitbang_ops pm2fb_i2cbb_ops = { 184 pm2fb_i2cbb_set_bits, 185 pm2fb_i2cbb_set_dir, 186 pm2fb_i2cbb_read, 187 { 188 PM2_DD_SDA_IN, 189 PM2_DD_SCL_IN, 190 0, 191 0 192 } 193 }; 194 195 /* mode setting stuff */ 196 static int pm2fb_set_pll(struct pm2fb_softc *, int); 197 static int pm2vfb_set_pll(struct pm2fb_softc *, int); 198 static uint8_t pm2fb_read_dac(struct pm2fb_softc *, int); 199 static void pm2fb_write_dac(struct pm2fb_softc *, int, uint8_t); 200 static void pm2fb_set_mode(struct pm2fb_softc *, const struct videomode *); 201 202 const struct { 203 int vendor; 204 int product; 205 int flags; 206 } pm2fb_pci_devices[] = { 207 { 208 PCI_VENDOR_3DLABS, 209 PCI_PRODUCT_3DLABS_PERMEDIA2V, 210 0 211 }, 212 { 213 PCI_VENDOR_TI, 214 PCI_PRODUCT_TI_TVP4020, 215 1 216 }, 217 { 218 0, 219 0, 220 0 221 } 222 }; 223 224 /* this table is from xf86-video-glint */ 225 #define PARTPROD(a,b,c) (((a)<<6) | ((b)<<3) | (c)) 226 int partprodPermedia[] = { 227 -1, 228 PARTPROD(0,0,1), PARTPROD(0,1,1), PARTPROD(1,1,1), PARTPROD(1,1,2), 229 PARTPROD(1,2,2), PARTPROD(2,2,2), PARTPROD(1,2,3), PARTPROD(2,2,3), 230 PARTPROD(1,3,3), PARTPROD(2,3,3), PARTPROD(1,2,4), PARTPROD(3,3,3), 231 PARTPROD(1,3,4), PARTPROD(2,3,4), -1, PARTPROD(3,3,4), 232 PARTPROD(1,4,4), PARTPROD(2,4,4), -1, PARTPROD(3,4,4), 233 -1, PARTPROD(2,3,5), -1, PARTPROD(4,4,4), 234 PARTPROD(1,4,5), PARTPROD(2,4,5), PARTPROD(3,4,5), -1, 235 -1, -1, -1, PARTPROD(4,4,5), 236 PARTPROD(1,5,5), PARTPROD(2,5,5), -1, PARTPROD(3,5,5), 237 -1, -1, -1, PARTPROD(4,5,5), 238 -1, -1, -1, PARTPROD(3,4,6), 239 -1, -1, -1, PARTPROD(5,5,5), 240 PARTPROD(1,5,6), PARTPROD(2,5,6), -1, PARTPROD(3,5,6), 241 -1, -1, -1, PARTPROD(4,5,6), 242 -1, -1, -1, -1, 243 -1, -1, -1, PARTPROD(5,5,6), 244 -1, -1, -1, -1, 245 -1, -1, -1, -1, 246 -1, -1, -1, -1, 247 -1, -1, -1, -1, 248 -1, -1, -1, -1, 249 -1, -1, -1, -1, 250 -1, -1, -1, -1, 251 -1, -1, -1, -1, 252 -1, -1, -1, -1, 253 -1, -1, -1, -1, 254 -1, -1, -1, -1, 255 -1, -1, -1, -1, 256 -1, -1, -1, -1, 257 -1, -1, -1, -1, 258 -1, -1, -1, -1, 259 -1, -1, -1, -1, 260 0}; 261 262 static inline void 263 pm2fb_wait(struct pm2fb_softc *sc, int slots) 264 { 265 uint32_t reg; 266 267 do { 268 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, 269 PM2_INPUT_FIFO_SPACE); 270 } while (reg <= slots); 271 } 272 273 static void 274 pm2fb_flush_engine(struct pm2fb_softc *sc) 275 { 276 277 pm2fb_wait(sc, 2); 278 279 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_FILTER_MODE, 280 PM2FLT_PASS_SYNC); 281 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SYNC, 0); 282 do { 283 while (bus_space_read_4(sc->sc_memt, sc->sc_regh, 284 PM2_OUTPUT_FIFO_WORDS) == 0); 285 } while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_OUTPUT_FIFO) != 286 PM2_SYNC_TAG); 287 } 288 289 static int 290 pm2fb_match(device_t parent, cfdata_t match, void *aux) 291 { 292 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 293 int i; 294 295 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) 296 return 0; 297 298 for (i = 0; pm2fb_pci_devices[i].vendor; i++) { 299 if ((PCI_VENDOR(pa->pa_id) == pm2fb_pci_devices[i].vendor && 300 PCI_PRODUCT(pa->pa_id) == pm2fb_pci_devices[i].product)) 301 return 100; 302 } 303 304 return (0); 305 } 306 307 static void 308 pm2fb_attach(device_t parent, device_t self, void *aux) 309 { 310 struct pm2fb_softc *sc = device_private(self); 311 struct pci_attach_args *pa = aux; 312 struct rasops_info *ri; 313 struct wsemuldisplaydev_attach_args aa; 314 prop_dictionary_t dict; 315 unsigned long defattr; 316 bool is_console = FALSE; 317 uint32_t flags; 318 int i; 319 320 sc->sc_pc = pa->pa_pc; 321 sc->sc_pcitag = pa->pa_tag; 322 sc->sc_memt = pa->pa_memt; 323 sc->sc_iot = pa->pa_iot; 324 sc->sc_dev = self; 325 326 for (i = 0; pm2fb_pci_devices[i].vendor; i++) { 327 if (PCI_PRODUCT(pa->pa_id) == pm2fb_pci_devices[i].product) { 328 sc->sc_is_pm2 = pm2fb_pci_devices[i].flags ; 329 break; 330 } 331 } 332 333 pci_aprint_devinfo(pa, NULL); 334 335 /* 336 * fill in parameters from properties 337 * if we can't get a usable mode via DDC2 we'll use this to pick one, 338 * which is why we fill them in with some conservative values that 339 * hopefully work as a last resort 340 */ 341 dict = device_properties(self); 342 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) { 343 aprint_error("%s: no width property\n", device_xname(self)); 344 sc->sc_width = 1024; 345 } 346 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) { 347 aprint_error("%s: no height property\n", device_xname(self)); 348 sc->sc_height = 768; 349 } 350 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) { 351 aprint_error("%s: no depth property\n", device_xname(self)); 352 sc->sc_depth = 8; 353 } 354 355 /* 356 * don't look at the linebytes property - The Raptor firmware lies 357 * about it. Get it from width * depth >> 3 instead. 358 */ 359 360 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); 361 362 prop_dictionary_get_bool(dict, "is_console", &is_console); 363 364 pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x14, PCI_MAPREG_TYPE_MEM, 365 &sc->sc_fb, &sc->sc_fbsize, &flags); 366 367 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0, 368 &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 369 aprint_error("%s: failed to map registers.\n", 370 device_xname(sc->sc_dev)); 371 } 372 373 /* 374 * XXX yeah, casting the fb address to uint32_t is formally wrong 375 * but as far as I know there are no PM2 with 64bit BARs 376 */ 377 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self), 378 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb); 379 380 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 381 "default", 382 0, 0, 383 NULL, 384 8, 16, 385 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 386 NULL 387 }; 388 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 389 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 390 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 391 sc->sc_locked = 0; 392 393 pm2_setup_i2c(sc); 394 395 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 396 &pm2fb_accessops); 397 sc->vd.init_screen = pm2fb_init_screen; 398 399 /* init engine here */ 400 pm2fb_init(sc); 401 402 ri = &sc->sc_console_screen.scr_ri; 403 404 sc->sc_gc.gc_bitblt = pm2fb_bitblt; 405 sc->sc_gc.gc_rectfill = pm2fb_rectfill_a; 406 sc->sc_gc.gc_blitcookie = sc; 407 sc->sc_gc.gc_rop = 3; 408 409 #ifdef PM2FB_DEBUG 410 /* 411 * leave some room at the bottom of the screen for various blitter 412 * tests and in order to make the glyph cache visible 413 */ 414 sc->sc_height -= 200; 415 #endif 416 417 if (is_console) { 418 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 419 &defattr); 420 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 421 422 pm2fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 423 ri->ri_devcmap[(defattr >> 16) & 0xff]); 424 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 425 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 426 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 427 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 428 429 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 430 uimin(2047, (sc->sc_fbsize / sc->sc_stride)) 431 - sc->sc_height - 5, 432 sc->sc_width, 433 ri->ri_font->fontwidth, 434 ri->ri_font->fontheight, 435 defattr); 436 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 437 defattr); 438 vcons_replay_msgbuf(&sc->sc_console_screen); 439 } else { 440 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 441 /* do some minimal setup to avoid weirdnesses later */ 442 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 443 &defattr); 444 } else 445 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 446 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 447 uimin(2047, (sc->sc_fbsize / sc->sc_stride)) 448 - sc->sc_height - 5, 449 sc->sc_width, 450 ri->ri_font->fontwidth, 451 ri->ri_font->fontheight, 452 defattr); 453 } 454 455 pm2fb_init_palette(sc); 456 457 aa.console = is_console; 458 aa.scrdata = &sc->sc_screenlist; 459 aa.accessops = &pm2fb_accessops; 460 aa.accesscookie = &sc->vd; 461 462 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 463 464 #ifdef PM2FB_DEBUG 465 /* 466 * draw a pattern to check if pm2fb_bitblt() gets the alignment stuff 467 * right 468 */ 469 pm2fb_rectfill(sc, 0, sc->sc_height, sc->sc_width, 200, 0xffffffff); 470 pm2fb_rectfill(sc, 0, sc->sc_height, 300, 10, 0); 471 pm2fb_rectfill(sc, 10, sc->sc_height, 200, 10, 0xe0e0e0e0); 472 for (i = 1; i < 20; i++) { 473 pm2fb_bitblt(sc, 0, sc->sc_height, 474 i, sc->sc_height + 10 * i, 475 300, 10, 3); 476 pm2fb_bitblt(sc, i, sc->sc_height, 477 400, sc->sc_height + 10 * i, 478 300, 10, 3); 479 } 480 #endif 481 } 482 483 static int 484 pm2fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 485 struct lwp *l) 486 { 487 struct vcons_data *vd = v; 488 struct pm2fb_softc *sc = vd->cookie; 489 struct wsdisplay_fbinfo *wdf; 490 struct vcons_screen *ms = vd->active; 491 492 switch (cmd) { 493 case WSDISPLAYIO_GTYPE: 494 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 495 return 0; 496 497 /* PCI config read/write passthrough. */ 498 case PCI_IOC_CFGREAD: 499 case PCI_IOC_CFGWRITE: 500 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 501 cmd, data, flag, l); 502 503 case WSDISPLAYIO_GET_BUSID: 504 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 505 sc->sc_pcitag, data); 506 507 case WSDISPLAYIO_GINFO: 508 if (ms == NULL) 509 return ENODEV; 510 wdf = (void *)data; 511 wdf->height = ms->scr_ri.ri_height; 512 wdf->width = ms->scr_ri.ri_width; 513 wdf->depth = ms->scr_ri.ri_depth; 514 wdf->cmsize = 256; 515 return 0; 516 517 case WSDISPLAYIO_GETCMAP: 518 return pm2fb_getcmap(sc, 519 (struct wsdisplay_cmap *)data); 520 521 case WSDISPLAYIO_PUTCMAP: 522 return pm2fb_putcmap(sc, 523 (struct wsdisplay_cmap *)data); 524 525 case WSDISPLAYIO_LINEBYTES: 526 *(u_int *)data = sc->sc_stride; 527 return 0; 528 529 case WSDISPLAYIO_SMODE: { 530 int new_mode = *(int*)data; 531 if (new_mode != sc->sc_mode) { 532 sc->sc_mode = new_mode; 533 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 534 /* first set the video mode */ 535 if (sc->sc_videomode != NULL) { 536 pm2fb_set_mode(sc, sc->sc_videomode); 537 } 538 /* then initialize the drawing engine */ 539 pm2fb_init(sc); 540 pm2fb_init_palette(sc); 541 /* clean out the glyph cache */ 542 glyphcache_wipe(&sc->sc_gc); 543 /* and redraw everything */ 544 vcons_redraw_screen(ms); 545 } else 546 pm2fb_flush_engine(sc); 547 } 548 } 549 return 0; 550 case WSDISPLAYIO_GET_EDID: { 551 struct wsdisplayio_edid_info *d = data; 552 d->data_size = 128; 553 if (d->buffer_size < 128) 554 return EAGAIN; 555 return copyout(sc->sc_edid_data, d->edid_data, 128); 556 } 557 558 case WSDISPLAYIO_GET_FBINFO: { 559 struct wsdisplayio_fbinfo *fbi = data; 560 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 561 } 562 } 563 return EPASSTHROUGH; 564 } 565 566 static paddr_t 567 pm2fb_mmap(void *v, void *vs, off_t offset, int prot) 568 { 569 struct vcons_data *vd = v; 570 struct pm2fb_softc *sc = vd->cookie; 571 paddr_t pa; 572 573 /* 'regular' framebuffer mmap()ing */ 574 if (offset < sc->sc_fbsize) { 575 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot, 576 BUS_SPACE_MAP_LINEAR); 577 return pa; 578 } 579 580 /* 581 * restrict all other mappings to processes with superuser privileges 582 * or the kernel itself 583 */ 584 if (kauth_authorize_machdep(kauth_cred_get(), 585 KAUTH_MACHDEP_UNMANAGEDMEM, 586 NULL, NULL, NULL, NULL) != 0) { 587 aprint_normal("%s: mmap() rejected.\n", 588 device_xname(sc->sc_dev)); 589 return -1; 590 } 591 592 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 593 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 594 BUS_SPACE_MAP_LINEAR); 595 return pa; 596 } 597 598 if ((offset >= sc->sc_reg) && 599 (offset < (sc->sc_reg + sc->sc_regsize))) { 600 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 601 BUS_SPACE_MAP_LINEAR); 602 return pa; 603 } 604 /* XXX 2nd fb BAR? */ 605 606 #ifdef PCI_MAGIC_IO_RANGE 607 /* allow mapping of IO space */ 608 if ((offset >= PCI_MAGIC_IO_RANGE) && 609 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) { 610 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE, 611 0, prot, BUS_SPACE_MAP_LINEAR); 612 return pa; 613 } 614 #endif 615 616 return -1; 617 } 618 619 static void 620 pm2fb_init_screen(void *cookie, struct vcons_screen *scr, 621 int existing, long *defattr) 622 { 623 struct pm2fb_softc *sc = cookie; 624 struct rasops_info *ri = &scr->scr_ri; 625 626 ri->ri_depth = sc->sc_depth; 627 ri->ri_width = sc->sc_width; 628 ri->ri_height = sc->sc_height; 629 ri->ri_stride = sc->sc_stride; 630 ri->ri_flg = RI_CENTER; 631 if (sc->sc_depth == 8) 632 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA; 633 634 rasops_init(ri, 0, 0); 635 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE; 636 637 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 638 sc->sc_width / ri->ri_font->fontwidth); 639 640 ri->ri_hw = scr; 641 ri->ri_ops.copyrows = pm2fb_copyrows; 642 ri->ri_ops.copycols = pm2fb_copycols; 643 ri->ri_ops.cursor = pm2fb_cursor; 644 ri->ri_ops.eraserows = pm2fb_eraserows; 645 ri->ri_ops.erasecols = pm2fb_erasecols; 646 if (FONT_IS_ALPHA(ri->ri_font)) { 647 ri->ri_ops.putchar = pm2fb_putchar_aa; 648 } else 649 ri->ri_ops.putchar = pm2fb_putchar; 650 } 651 652 static int 653 pm2fb_putcmap(struct pm2fb_softc *sc, struct wsdisplay_cmap *cm) 654 { 655 u_char *r, *g, *b; 656 u_int index = cm->index; 657 u_int count = cm->count; 658 int i, error; 659 u_char rbuf[256], gbuf[256], bbuf[256]; 660 661 #ifdef PM2FB_DEBUG 662 aprint_debug("putcmap: %d %d\n",index, count); 663 #endif 664 if (cm->index >= 256 || cm->count > 256 || 665 (cm->index + cm->count) > 256) 666 return EINVAL; 667 error = copyin(cm->red, &rbuf[index], count); 668 if (error) 669 return error; 670 error = copyin(cm->green, &gbuf[index], count); 671 if (error) 672 return error; 673 error = copyin(cm->blue, &bbuf[index], count); 674 if (error) 675 return error; 676 677 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 678 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 679 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 680 681 r = &sc->sc_cmap_red[index]; 682 g = &sc->sc_cmap_green[index]; 683 b = &sc->sc_cmap_blue[index]; 684 685 for (i = 0; i < count; i++) { 686 pm2fb_putpalreg(sc, index, *r, *g, *b); 687 index++; 688 r++, g++, b++; 689 } 690 return 0; 691 } 692 693 static int 694 pm2fb_getcmap(struct pm2fb_softc *sc, struct wsdisplay_cmap *cm) 695 { 696 u_int index = cm->index; 697 u_int count = cm->count; 698 int error; 699 700 if (index >= 255 || count > 256 || index + count > 256) 701 return EINVAL; 702 703 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 704 if (error) 705 return error; 706 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 707 if (error) 708 return error; 709 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 710 if (error) 711 return error; 712 713 return 0; 714 } 715 716 static void 717 pm2fb_init_palette(struct pm2fb_softc *sc) 718 { 719 struct rasops_info *ri = &sc->sc_console_screen.scr_ri; 720 int i, j = 0; 721 uint8_t cmap[768]; 722 723 rasops_get_cmap(ri, cmap, sizeof(cmap)); 724 for (i = 0; i < 256; i++) { 725 sc->sc_cmap_red[i] = cmap[j]; 726 sc->sc_cmap_green[i] = cmap[j + 1]; 727 sc->sc_cmap_blue[i] = cmap[j + 2]; 728 pm2fb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 729 j += 3; 730 } 731 } 732 733 static int 734 pm2fb_putpalreg(struct pm2fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 735 uint8_t b) 736 { 737 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_PAL_WRITE_IDX, idx); 738 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, r); 739 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, g); 740 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, b); 741 return 0; 742 } 743 744 static uint8_t 745 pm2fb_read_dac(struct pm2fb_softc *sc, int reg) 746 { 747 if (sc->sc_is_pm2) { 748 bus_space_write_1(sc->sc_memt, sc->sc_regh, 749 PM2_DAC_PAL_WRITE_IDX, reg); 750 return bus_space_read_1(sc->sc_memt, sc->sc_regh, 751 PM2_DAC_INDEX_DATA); 752 } else { 753 bus_space_write_1(sc->sc_memt, sc->sc_regh, 754 PM2V_DAC_INDEX_LOW, reg & 0xff); 755 bus_space_write_1(sc->sc_memt, sc->sc_regh, 756 PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff); 757 return bus_space_read_1(sc->sc_memt, sc->sc_regh, 758 PM2V_DAC_INDEX_DATA); 759 } 760 } 761 762 static void 763 pm2fb_write_dac(struct pm2fb_softc *sc, int reg, uint8_t data) 764 { 765 pm2fb_wait(sc, 3); 766 if (sc->sc_is_pm2) { 767 pm2fb_wait(sc, 2); 768 bus_space_write_1(sc->sc_memt, sc->sc_regh, 769 PM2_DAC_PAL_WRITE_IDX, reg); 770 bus_space_write_1(sc->sc_memt, sc->sc_regh, 771 PM2_DAC_INDEX_DATA, data); 772 } else { 773 pm2fb_wait(sc, 3); 774 bus_space_write_1(sc->sc_memt, sc->sc_regh, 775 PM2V_DAC_INDEX_LOW, reg & 0xff); 776 bus_space_write_1(sc->sc_memt, sc->sc_regh, 777 PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff); 778 bus_space_write_1(sc->sc_memt, sc->sc_regh, 779 PM2V_DAC_INDEX_DATA, data); 780 } 781 } 782 783 static void 784 pm2fb_init(struct pm2fb_softc *sc) 785 { 786 pm2fb_flush_engine(sc); 787 788 pm2fb_wait(sc, 9); 789 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_BASE, 0); 790 /* set aperture endianness */ 791 #if BYTE_ORDER == BIG_ENDIAN 792 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_APERTURE1_CONTROL, 793 PM2_AP_BYTESWAP | PM2_AP_HALFWORDSWAP); 794 #else 795 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_APERTURE1_CONTROL, 0); 796 #endif 797 #if 0 798 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_BYPASS_MASK, 799 0xffffffff); 800 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_WRITE_MASK, 801 0xffffffff); 802 #endif 803 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HW_WRITEMASK, 804 0xffffffff); 805 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SW_WRITEMASK, 806 0xffffffff); 807 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WRITE_MODE, 808 PM2WM_WRITE_EN); 809 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCREENSIZE, 810 (sc->sc_height << 16) | sc->sc_width); 811 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MODE, 812 PM2SC_SCREEN_EN); 813 pm2fb_wait(sc, 8); 814 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0); 815 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0); 816 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); 817 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_COLOUR_MODE, 0); 818 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_ADDRESS_MODE, 0); 819 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_READ_MODE, 0); 820 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_LUT_MODE, 0); 821 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_YUV_MODE, 0); 822 pm2fb_wait(sc, 8); 823 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DEPTH_MODE, 0); 824 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DEPTH, 0); 825 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STENCIL_MODE, 0); 826 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STIPPLE_MODE, 0); 827 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ROP_MODE, 0); 828 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WINDOW_ORIGIN, 0); 829 #if 0 830 sc->sc_pprod = bus_space_read_4(sc->sc_memt, sc->sc_regh, 831 PM2_FB_READMODE) & 832 (PM2FB_PP0_MASK | PM2FB_PP1_MASK | PM2FB_PP2_MASK); 833 #endif 834 sc->sc_pprod = partprodPermedia[sc->sc_stride >> 5]; 835 836 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_READMODE, 837 sc->sc_pprod); 838 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEXMAP_FORMAT, 839 sc->sc_pprod); 840 pm2fb_wait(sc, 9); 841 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DY, 1 << 16); 842 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DXDOM, 0); 843 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXDOM, 0); 844 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXSUB, 0); 845 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTY, 0); 846 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_COUNT, 0); 847 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MINYX, 0); 848 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MAXYX, 849 0x0fff0fff); 850 /* 851 * another scissor we need to disable in order to blit into off-screen 852 * memory 853 */ 854 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCREENSIZE, 855 0x0fff0fff); 856 857 switch(sc->sc_depth) { 858 case 8: 859 bus_space_write_4(sc->sc_memt, sc->sc_regh, 860 PM2_RE_PIXEL_SIZE, PM2PS_8BIT); 861 break; 862 case 16: 863 bus_space_write_4(sc->sc_memt, sc->sc_regh, 864 PM2_RE_PIXEL_SIZE, PM2PS_16BIT); 865 break; 866 case 32: 867 bus_space_write_4(sc->sc_memt, sc->sc_regh, 868 PM2_RE_PIXEL_SIZE, PM2PS_32BIT); 869 break; 870 } 871 pm2fb_flush_engine(sc); 872 DPRINTF("pixel size: %08x\n", 873 bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_RE_PIXEL_SIZE)); 874 } 875 876 static void 877 pm2fb_rectfill(struct pm2fb_softc *sc, int x, int y, int wi, int he, 878 uint32_t colour) 879 { 880 881 pm2fb_wait(sc, 9); 882 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); 883 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); 884 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0); 885 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0); 886 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG, 887 PM2RECFG_WRITE_EN); 888 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_BLOCK_COLOUR, 889 colour); 890 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START, 891 (y << 16) | x); 892 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE, 893 (he << 16) | wi); 894 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER, 895 PM2RE_RECTANGLE | PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL); 896 } 897 898 static void 899 pm2fb_rectfill_a(void *cookie, int x, int y, int wi, int he, long attr) 900 { 901 struct pm2fb_softc *sc = cookie; 902 903 pm2fb_rectfill(sc, x, y, wi, he, 904 sc->vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]); 905 } 906 907 static void 908 pm2fb_bitblt(void *cookie, int xs, int ys, int xd, int yd, 909 int wi, int he, int rop) 910 { 911 struct pm2fb_softc *sc = cookie; 912 uint32_t dir = 0; 913 int rxd, rwi, rxdelta; 914 915 if (yd <= ys) { 916 dir |= PM2RE_INC_Y; 917 } 918 if (xd <= xs) { 919 dir |= PM2RE_INC_X; 920 } 921 pm2fb_wait(sc, 10); 922 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); 923 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); 924 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0); 925 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0); 926 if (sc->sc_depth == 8) { 927 int adjust; 928 /* 929 * use packed mode for some extra speed 930 * this copies 32bit quantities even in 8 bit mode, so we need 931 * to adjust for cases where the lower two bits in source and 932 * destination X don't align, and/or where the width isn't a 933 * multiple of 4 934 */ 935 if (rop == 3) { 936 bus_space_write_4(sc->sc_memt, sc->sc_regh, 937 PM2_RE_CONFIG, 938 PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | 939 PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6)); 940 } else { 941 bus_space_write_4(sc->sc_memt, sc->sc_regh, 942 PM2_RE_CONFIG, 943 PM2RECFG_READ_SRC | PM2RECFG_READ_DST | 944 PM2RECFG_WRITE_EN | PM2RECFG_PACKED | 945 PM2RECFG_ROP_EN | (rop << 6)); 946 } 947 rxd = xd >> 2; 948 rwi = (wi + 7) >> 2; 949 rxdelta = (xs & 0xffc) - (xd & 0xffc); 950 /* adjust for non-aligned x */ 951 #ifdef BITBLT_LE_WORKAROUND 952 /* I have no idea why this seems to work */ 953 adjust = 1; 954 #else 955 adjust = ((xd & 3) - (xs & 3)); 956 #endif 957 bus_space_write_4(sc->sc_memt, sc->sc_regh, 958 PM2_RE_PACKEDDATA_LIMIT, 959 (xd << 16) | (xd + wi) | (adjust << 29)); 960 961 } else { 962 /* we're in 16 or 32bit mode */ 963 if (rop == 3) { 964 bus_space_write_4(sc->sc_memt, sc->sc_regh, 965 PM2_RE_CONFIG, 966 PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | 967 PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6)); 968 } else { 969 bus_space_write_4(sc->sc_memt, sc->sc_regh, 970 PM2_RE_CONFIG, 971 PM2RECFG_READ_SRC | PM2RECFG_READ_DST | 972 PM2RECFG_WRITE_EN | PM2RECFG_PACKED | 973 PM2RECFG_ROP_EN | (rop << 6)); 974 } 975 rxd = xd; 976 rwi = wi; 977 rxdelta = xs - xd; 978 } 979 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START, 980 (yd << 16) | rxd); 981 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE, 982 (he << 16) | rwi); 983 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SOURCE_DELTA, 984 (((ys - yd) & 0xfff) << 16) | (rxdelta & 0xfff)); 985 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER, 986 PM2RE_RECTANGLE | dir); 987 } 988 989 static void 990 pm2fb_cursor(void *cookie, int on, int row, int col) 991 { 992 struct rasops_info *ri = cookie; 993 struct vcons_screen *scr = ri->ri_hw; 994 struct pm2fb_softc *sc = scr->scr_cookie; 995 int x, y, wi, he; 996 997 wi = ri->ri_font->fontwidth; 998 he = ri->ri_font->fontheight; 999 1000 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1001 x = ri->ri_ccol * wi + ri->ri_xorigin; 1002 y = ri->ri_crow * he + ri->ri_yorigin; 1003 if (ri->ri_flg & RI_CURSOR) { 1004 pm2fb_bitblt(sc, x, y, x, y, wi, he, 12); 1005 ri->ri_flg &= ~RI_CURSOR; 1006 } 1007 ri->ri_crow = row; 1008 ri->ri_ccol = col; 1009 if (on) { 1010 x = ri->ri_ccol * wi + ri->ri_xorigin; 1011 y = ri->ri_crow * he + ri->ri_yorigin; 1012 pm2fb_bitblt(sc, x, y, x, y, wi, he, 12); 1013 ri->ri_flg |= RI_CURSOR; 1014 } 1015 } else { 1016 scr->scr_ri.ri_crow = row; 1017 scr->scr_ri.ri_ccol = col; 1018 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1019 } 1020 1021 } 1022 1023 static void 1024 pm2fb_putchar(void *cookie, int row, int col, u_int c, long attr) 1025 { 1026 struct rasops_info *ri = cookie; 1027 struct wsdisplay_font *font = PICK_FONT(ri, c); 1028 struct vcons_screen *scr = ri->ri_hw; 1029 struct pm2fb_softc *sc = scr->scr_cookie; 1030 uint32_t mode; 1031 1032 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1033 void *data; 1034 uint32_t fg, bg; 1035 int uc, i; 1036 int x, y, wi, he; 1037 1038 wi = font->fontwidth; 1039 he = font->fontheight; 1040 1041 if (!CHAR_IN_FONT(c, font)) 1042 return; 1043 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1044 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1045 x = ri->ri_xorigin + col * wi; 1046 y = ri->ri_yorigin + row * he; 1047 if (c == 0x20) { 1048 pm2fb_rectfill(sc, x, y, wi, he, bg); 1049 } else { 1050 uc = c - font->firstchar; 1051 data = (uint8_t *)font->data + uc * ri->ri_fontscale; 1052 1053 mode = PM2RM_MASK_MIRROR; 1054 #if BYTE_ORDER == LITTLE_ENDIAN 1055 switch (ri->ri_font->stride) { 1056 case 1: 1057 mode |= 4 << 7; 1058 break; 1059 case 2: 1060 mode |= 3 << 7; 1061 break; 1062 } 1063 #else 1064 switch (ri->ri_font->stride) { 1065 case 1: 1066 mode |= 3 << 7; 1067 break; 1068 case 2: 1069 mode |= 2 << 7; 1070 break; 1071 } 1072 #endif 1073 pm2fb_wait(sc, 8); 1074 1075 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1076 PM2_RE_MODE, mode); 1077 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1078 PM2_RE_CONFIG, PM2RECFG_WRITE_EN); 1079 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1080 PM2_RE_BLOCK_COLOUR, bg); 1081 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1082 PM2_RE_RECT_START, (y << 16) | x); 1083 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1084 PM2_RE_RECT_SIZE, (he << 16) | wi); 1085 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1086 PM2_RE_RENDER, 1087 PM2RE_RECTANGLE | 1088 PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL); 1089 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1090 PM2_RE_BLOCK_COLOUR, fg); 1091 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1092 PM2_RE_RENDER, 1093 PM2RE_RECTANGLE | PM2RE_SYNC_ON_MASK | 1094 PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL); 1095 1096 pm2fb_wait(sc, he); 1097 switch (ri->ri_font->stride) { 1098 case 1: { 1099 uint8_t *data8 = data; 1100 uint32_t reg; 1101 for (i = 0; i < he; i++) { 1102 reg = *data8; 1103 bus_space_write_4(sc->sc_memt, 1104 sc->sc_regh, 1105 PM2_RE_BITMASK, reg); 1106 data8++; 1107 } 1108 break; 1109 } 1110 case 2: { 1111 uint16_t *data16 = data; 1112 uint32_t reg; 1113 for (i = 0; i < he; i++) { 1114 reg = *data16; 1115 bus_space_write_4(sc->sc_memt, 1116 sc->sc_regh, 1117 PM2_RE_BITMASK, reg); 1118 data16++; 1119 } 1120 break; 1121 } 1122 } 1123 } 1124 if (attr & 1) 1125 pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1126 } 1127 } 1128 1129 static void 1130 pm2fb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1131 { 1132 struct rasops_info *ri = cookie; 1133 struct wsdisplay_font *font = PICK_FONT(ri, c); 1134 struct vcons_screen *scr = ri->ri_hw; 1135 struct pm2fb_softc *sc = scr->scr_cookie; 1136 uint32_t bg, fg, pixel, /*bg32,*/ fg32, aval; 1137 int i, x, y, wi, he; 1138 int r1, g1, b1, /*r0, g0, b0,*/ fgo/*, bgo*/; 1139 uint8_t *data8; 1140 int rv = GC_NOPE, cnt = 0; 1141 1142 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1143 return; 1144 1145 if (!CHAR_IN_FONT(c, font)) 1146 return; 1147 1148 wi = font->fontwidth; 1149 he = font->fontheight; 1150 1151 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1152 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1153 x = ri->ri_xorigin + col * wi; 1154 y = ri->ri_yorigin + row * he; 1155 1156 /* always blit the cell with the background colour */ 1157 pm2fb_rectfill(sc, x, y, wi, he, bg); 1158 1159 /* if we draw a whitespace we're done here */ 1160 if (c == 0x20) { 1161 if (attr & 1) 1162 pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1163 return; 1164 } 1165 1166 #ifdef BITBLT_LE_WORKAROUND 1167 rv = GC_NOPE; 1168 #else 1169 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1170 if (rv == GC_OK) 1171 return; 1172 #endif 1173 1174 data8 = WSFONT_GLYPH(c, font); 1175 1176 pm2fb_wait(sc, 7); 1177 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); 1178 /* 1179 * XXX 1180 * we *chould* be able to get away without reading the framebuffer 1181 * since our background colour is always constant, but for some reason 1182 * that produces random, mostly black background 1183 */ 1184 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG, 1185 PM2RECFG_WRITE_EN | PM2RECFG_READ_DST); 1186 1187 /* enable alpha blending and R3G3B2 output */ 1188 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 1189 PM2AL_ENABLE | 1190 PM2AL_OP_SRC_IS_SRC_ALPHA | 1191 PM2AL_OP_DST_IS_ONE_MINUS_SRC_ALPHA | 1192 PM2AL_332F | PM2AL_RGB); 1193 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 1194 PM2DM_ENABLE | 1195 PM2DM_332F | PM2DM_RGB); 1196 1197 /* 1198 * we need the RGB colours here, so get offsets into rasops_cmap 1199 */ 1200 fgo = ((attr >> 24) & 0xf) * 3; 1201 1202 r1 = rasops_cmap[fgo]; 1203 g1 = rasops_cmap[fgo + 1]; 1204 b1 = rasops_cmap[fgo + 2]; 1205 1206 fg32 = ( r1 << 16) | (g1 << 8) | b1; 1207 1208 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1209 PM2_RE_RECT_START, (y << 16) | x); 1210 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1211 PM2_RE_RECT_SIZE, (he << 16) | wi); 1212 1213 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1214 PM2_RE_RENDER, 1215 PM2RE_RECTANGLE | PM2RE_SYNC_ON_HOST | 1216 PM2RE_INC_X | PM2RE_INC_Y); 1217 1218 pm2fb_wait(sc, uimin(200, ri->ri_fontscale)); 1219 1220 /* 1221 * and now we just hammer the forground colour and alpha values into 1222 * the upload port 1223 */ 1224 for (i = 0; i < ri->ri_fontscale; i++) { 1225 aval = *data8; 1226 pixel = fg32 | (aval << 24); 1227 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1228 PM2_RE_COLOUR, pixel); 1229 1230 if (cnt > 190) { 1231 pm2fb_wait(sc, 200); 1232 cnt = 0; 1233 } 1234 data8++; 1235 } 1236 /* 1237 * XXX 1238 * occasionally characters end up in the cache only partially drawn 1239 * apparently the blitter might end up grabbing them before they're 1240 * completely flushed out into video memory 1241 * so we let the pipeline drain a little bit before continuing 1242 */ 1243 pm2fb_wait(sc, 20); 1244 1245 if (rv == GC_ADD) { 1246 glyphcache_add(&sc->sc_gc, c, x, y); 1247 } else if (attr & 1) 1248 pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1249 } 1250 1251 static void 1252 pm2fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1253 { 1254 struct rasops_info *ri = cookie; 1255 struct vcons_screen *scr = ri->ri_hw; 1256 struct pm2fb_softc *sc = scr->scr_cookie; 1257 int32_t xs, xd, y, width, height; 1258 1259 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1260 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1261 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1262 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1263 width = ri->ri_font->fontwidth * ncols; 1264 height = ri->ri_font->fontheight; 1265 pm2fb_bitblt(sc, xs, y, xd, y, width, height, 3); 1266 } 1267 } 1268 1269 static void 1270 pm2fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1271 { 1272 struct rasops_info *ri = cookie; 1273 struct vcons_screen *scr = ri->ri_hw; 1274 struct pm2fb_softc *sc = scr->scr_cookie; 1275 int32_t x, y, width, height, fg, bg, ul; 1276 1277 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1278 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1279 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1280 width = ri->ri_font->fontwidth * ncols; 1281 height = ri->ri_font->fontheight; 1282 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1283 1284 pm2fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1285 } 1286 } 1287 1288 static void 1289 pm2fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1290 { 1291 struct rasops_info *ri = cookie; 1292 struct vcons_screen *scr = ri->ri_hw; 1293 struct pm2fb_softc *sc = scr->scr_cookie; 1294 int32_t x, ys, yd, width, height; 1295 1296 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1297 x = ri->ri_xorigin; 1298 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1299 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1300 width = ri->ri_emuwidth; 1301 height = ri->ri_font->fontheight*nrows; 1302 pm2fb_bitblt(sc, x, ys, x, yd, width, height, 3); 1303 } 1304 } 1305 1306 static void 1307 pm2fb_eraserows(void *cookie, int row, int nrows, long fillattr) 1308 { 1309 struct rasops_info *ri = cookie; 1310 struct vcons_screen *scr = ri->ri_hw; 1311 struct pm2fb_softc *sc = scr->scr_cookie; 1312 int32_t x, y, width, height, fg, bg, ul; 1313 1314 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1315 x = ri->ri_xorigin; 1316 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1317 width = ri->ri_emuwidth; 1318 height = ri->ri_font->fontheight * nrows; 1319 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1320 1321 pm2fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1322 } 1323 } 1324 1325 /* 1326 * Permedia2 can't blit outside of 2048x2048, so reject anything higher 1327 * max. dot clock is probably too high 1328 */ 1329 1330 #define MODE_IS_VALID(m) (((m)->hdisplay < 2048) && \ 1331 ((m)->dot_clock < 230000)) 1332 1333 static void 1334 pm2_setup_i2c(struct pm2fb_softc *sc) 1335 { 1336 int i; 1337 #ifdef PM2FB_DEBUG 1338 int j; 1339 #endif 1340 1341 /* Fill in the i2c tag */ 1342 iic_tag_init(&sc->sc_i2c); 1343 sc->sc_i2c.ic_cookie = sc; 1344 sc->sc_i2c.ic_send_start = pm2fb_i2c_send_start; 1345 sc->sc_i2c.ic_send_stop = pm2fb_i2c_send_stop; 1346 sc->sc_i2c.ic_initiate_xfer = pm2fb_i2c_initiate_xfer; 1347 sc->sc_i2c.ic_read_byte = pm2fb_i2c_read_byte; 1348 sc->sc_i2c.ic_write_byte = pm2fb_i2c_write_byte; 1349 1350 DPRINTF("data: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, 1351 PM2_DISPLAY_DATA)); 1352 1353 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, 0); 1354 1355 /* zero out the EDID buffer */ 1356 memset(sc->sc_edid_data, 0, 128); 1357 1358 /* Some monitors don't respond first time */ 1359 i = 0; 1360 while (sc->sc_edid_data[1] == 0 && i < 10) { 1361 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128); 1362 i++; 1363 } 1364 #ifdef PM2FB_DEBUG 1365 printf("i = %d\n", i); 1366 for (i = 0; i < 128; i += 16) { 1367 printf("%02x:", i); 1368 for (j = 0; j < 16; j++) 1369 printf(" %02x", sc->sc_edid_data[i + j]); 1370 printf("\n"); 1371 } 1372 #endif 1373 1374 if (edid_parse(&sc->sc_edid_data[0], &sc->sc_ei) != -1) { 1375 #ifdef PM2FB_DEBUG 1376 edid_print(&sc->sc_ei); 1377 #endif 1378 1379 /* 1380 * Now pick a mode. 1381 */ 1382 if ((sc->sc_ei.edid_preferred_mode != NULL)) { 1383 struct videomode *m = sc->sc_ei.edid_preferred_mode; 1384 if (MODE_IS_VALID(m)) { 1385 sc->sc_videomode = m; 1386 } else { 1387 aprint_error_dev(sc->sc_dev, 1388 "unable to use preferred mode\n"); 1389 } 1390 } 1391 /* 1392 * if we can't use the preferred mode go look for the 1393 * best one we can support 1394 */ 1395 if (sc->sc_videomode == NULL) { 1396 struct videomode *m = sc->sc_ei.edid_modes; 1397 1398 sort_modes(sc->sc_ei.edid_modes, 1399 &sc->sc_ei.edid_preferred_mode, 1400 sc->sc_ei.edid_nmodes); 1401 if (sc->sc_videomode == NULL) 1402 for (int n = 0; n < sc->sc_ei.edid_nmodes; n++) 1403 if (MODE_IS_VALID(&m[n])) { 1404 sc->sc_videomode = &m[n]; 1405 break; 1406 } 1407 } 1408 } 1409 if (sc->sc_videomode == NULL) { 1410 /* no EDID data? */ 1411 sc->sc_videomode = pick_mode_by_ref(sc->sc_width, 1412 sc->sc_height, 60); 1413 } 1414 if (sc->sc_videomode != NULL) { 1415 pm2fb_set_mode(sc, sc->sc_videomode); 1416 } 1417 } 1418 1419 /* I2C bitbanging */ 1420 static void pm2fb_i2cbb_set_bits(void *cookie, uint32_t bits) 1421 { 1422 struct pm2fb_softc *sc = cookie; 1423 uint32_t out; 1424 1425 out = bits << 2; /* bitmasks match the IN bits */ 1426 1427 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, out); 1428 delay(100); 1429 } 1430 1431 static void pm2fb_i2cbb_set_dir(void *cookie, uint32_t dir) 1432 { 1433 /* Nothing to do */ 1434 } 1435 1436 static uint32_t pm2fb_i2cbb_read(void *cookie) 1437 { 1438 struct pm2fb_softc *sc = cookie; 1439 uint32_t bits; 1440 1441 bits = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA); 1442 return bits; 1443 } 1444 1445 /* higher level I2C stuff */ 1446 static int 1447 pm2fb_i2c_send_start(void *cookie, int flags) 1448 { 1449 return (i2c_bitbang_send_start(cookie, flags, &pm2fb_i2cbb_ops)); 1450 } 1451 1452 static int 1453 pm2fb_i2c_send_stop(void *cookie, int flags) 1454 { 1455 1456 return (i2c_bitbang_send_stop(cookie, flags, &pm2fb_i2cbb_ops)); 1457 } 1458 1459 static int 1460 pm2fb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 1461 { 1462 1463 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, 1464 &pm2fb_i2cbb_ops)); 1465 } 1466 1467 static int 1468 pm2fb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 1469 { 1470 return (i2c_bitbang_read_byte(cookie, valp, flags, &pm2fb_i2cbb_ops)); 1471 } 1472 1473 static int 1474 pm2fb_i2c_write_byte(void *cookie, uint8_t val, int flags) 1475 { 1476 return (i2c_bitbang_write_byte(cookie, val, flags, &pm2fb_i2cbb_ops)); 1477 } 1478 1479 static int 1480 pm2vfb_set_pll(struct pm2fb_softc *sc, int freq) 1481 { 1482 int m, n, p, diff, out_freq, bm = 1, bn = 3, bp = 0, 1483 bdiff = 1000000 /* , bfreq */; 1484 int fi; 1485 uint8_t temp; 1486 1487 for (m = 1; m < 128; m++) { 1488 for (n = 2 * m + 1; n < 256; n++) { 1489 fi = PM2_EXT_CLOCK_FREQ * n / m; 1490 for (p = 0; p < 2; p++) { 1491 out_freq = fi >> (p + 1); 1492 diff = abs(out_freq - freq); 1493 if (diff < bdiff) { 1494 bdiff = diff; 1495 /* bfreq = out_freq; */ 1496 bm = m; 1497 bn = n; 1498 bp = p; 1499 } 1500 } 1501 } 1502 } 1503 #if 0 1504 /* 1505 * XXX 1506 * output between switching modes and attaching a wsdisplay will 1507 * go through firmware calls on sparc64 and potentially mess up 1508 * our drawing engine state 1509 */ 1510 DPRINTF("best: %d kHz ( %d off ), %d %d %d\n", bfreq, bdiff, bm, bn, bp); 1511 #endif 1512 temp = pm2fb_read_dac(sc, PM2V_DAC_CLOCK_CONTROL) & 0xfc; 1513 pm2fb_write_dac(sc, PM2V_DAC_CONTROL, 0); 1514 pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_M, bm); 1515 pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_N, bn); 1516 pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_P, bp); 1517 pm2fb_write_dac(sc, PM2V_DAC_CLOCK_CONTROL, temp | 3); 1518 return 0; 1519 } 1520 1521 static int 1522 pm2fb_set_pll(struct pm2fb_softc *sc, int freq) 1523 { 1524 uint8_t reg, bm = 0, bn = 0, bp = 0; 1525 unsigned int m, n, p, fi, diff, out_freq, bdiff = 1000000; 1526 1527 for (n = 2; n < 15; n++) { 1528 for (m = 2 ; m < 256; m++) { 1529 fi = PM2_EXT_CLOCK_FREQ * m / n; 1530 if (fi >= PM2_PLL_FREQ_MIN && fi <= PM2_PLL_FREQ_MAX) { 1531 for (p = 0; p < 5; p++) { 1532 out_freq = fi >> p; 1533 diff = abs(out_freq - freq); 1534 if (diff < bdiff) { 1535 bm = m; 1536 bn = n; 1537 bp = p; 1538 bdiff = diff; 1539 } 1540 } 1541 } 1542 } 1543 } 1544 1545 pm2fb_write_dac(sc, PM2_DAC_PIXELCLKA_M, bm); 1546 pm2fb_write_dac(sc, PM2_DAC_PIXELCLKA_N, bn); 1547 pm2fb_write_dac(sc, PM2_DAC_PIXELCLKA_P, (bp | 0x08)); 1548 1549 do { 1550 reg = bus_space_read_1(sc->sc_memt, sc->sc_regh, 1551 PM2_DAC_INDEX_DATA); 1552 } while (reg == PCLK_LOCKED); 1553 1554 return 0; 1555 } 1556 1557 /* 1558 * most of the following was adapted from the xf86-video-glint driver's 1559 * pm2_dac.c (8bpp only) 1560 */ 1561 static void 1562 pm2fb_set_dac(struct pm2fb_softc *sc, const struct videomode *mode) 1563 { 1564 int t1, t2, t3, t4, stride; 1565 uint32_t vclk, tmp; 1566 uint8_t sync = 0; 1567 1568 t1 = mode->hsync_start - mode->hdisplay; 1569 t2 = mode->vsync_start - mode->vdisplay; 1570 t3 = mode->hsync_end - mode->hsync_start; 1571 t4 = mode->vsync_end - mode->vsync_start; 1572 1573 /* first round up to the next multiple of 32 */ 1574 stride = (mode->hdisplay + 31) & ~31; 1575 /* then find the next bigger one that we have partial products for */ 1576 while ((partprodPermedia[stride >> 5] == -1) && (stride < 2048)) { 1577 stride += 32; 1578 } 1579 1580 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HTOTAL, 1581 ((mode->htotal) >> 2) - 1); 1582 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_END, 1583 (t1 + t3) >> 2); 1584 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_START, 1585 (t1 >> 2)); 1586 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HBLANK_END, 1587 (mode->htotal - mode->hdisplay) >> 2); 1588 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HGATE_END, 1589 (mode->htotal - mode->hdisplay) >> 2); 1590 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_STRIDE, 1591 stride >> 3); 1592 1593 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VTOTAL, 1594 mode->vtotal - 2); 1595 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_END, 1596 t2 + t4 - 1); 1597 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_START, 1598 t2 - 1); 1599 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VBLANK_END, 1600 mode->vtotal - mode->vdisplay); 1601 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VIDEO_CONTROL, 1602 PM2_VC_VIDEO_ENABLE | 1603 PM2_VC_HSYNC_ACT_HIGH | PM2_VC_VSYNC_ACT_HIGH); 1604 1605 vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL); 1606 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL, 1607 vclk & 0xfffffffc); 1608 1609 tmp = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_CHIP_CONFIG); 1610 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_CHIP_CONFIG, 1611 tmp & 0xffffffdd); 1612 1613 pm2fb_write_dac(sc, PM2_DAC_MODE_CONTROL, MOC_BUFFERFRONT); 1614 pm2fb_set_pll(sc, mode->dot_clock); 1615 1616 sync = MC_PALETTE_8BIT; 1617 1618 if (!(mode->flags & VID_PHSYNC)) 1619 sync |= MC_HSYNC_INV; 1620 if (!(mode->flags & VID_PVSYNC)) 1621 sync |= MC_VSYNC_INV; 1622 1623 pm2fb_write_dac(sc, PM2_DAC_MISC_CONTROL, sync); 1624 pm2fb_write_dac(sc, PM2_DAC_COLOR_MODE, 1625 CM_PALETTE | CM_GUI_ENABLE | CM_RGB); 1626 1627 sc->sc_width = mode->hdisplay; 1628 sc->sc_height = mode->vdisplay; 1629 sc->sc_depth = 8; 1630 sc->sc_stride = stride; 1631 aprint_normal_dev(sc->sc_dev, "pm2 using %d x %d in 8 bit, stride %d\n", 1632 sc->sc_width, sc->sc_height, stride); 1633 } 1634 1635 /* 1636 * most of the following was adapted from the xf86-video-glint driver's 1637 * pm2v_dac.c 1638 */ 1639 static void 1640 pm2vfb_set_dac(struct pm2fb_softc *sc, const struct videomode *mode) 1641 { 1642 int t1, t2, t3, t4, stride; 1643 uint32_t vclk; 1644 uint8_t sync = 0; 1645 1646 t1 = mode->hsync_start - mode->hdisplay; 1647 t2 = mode->vsync_start - mode->vdisplay; 1648 t3 = mode->hsync_end - mode->hsync_start; 1649 t4 = mode->vsync_end - mode->vsync_start; 1650 1651 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HTOTAL, 1652 ((mode->htotal) >> 3) - 1); 1653 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_END, 1654 (t1 + t3) >> 3); 1655 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_START, 1656 (t1 >> 3) - 1); 1657 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HBLANK_END, 1658 (mode->htotal - mode->hdisplay) >> 3); 1659 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HGATE_END, 1660 (mode->htotal - mode->hdisplay) >> 3); 1661 1662 /* first round up to the next multiple of 32 */ 1663 stride = (mode->hdisplay + 31) & ~31; 1664 /* then find the next bigger one that we have partial products for */ 1665 while ((partprodPermedia[stride >> 5] == -1) && (stride < 2048)) { 1666 stride += 32; 1667 } 1668 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_STRIDE, 1669 stride >> 3); 1670 1671 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VTOTAL, 1672 mode->vtotal - 1); 1673 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_END, 1674 t2 + t4); 1675 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_START, 1676 t2); 1677 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VBLANK_END, 1678 mode->vtotal - mode->vdisplay); 1679 1680 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VIDEO_CONTROL, 1681 PM2_VC_VIDEO_ENABLE | PM2_VC_RAMDAC_64BIT | 1682 PM2_VC_HSYNC_ACT_HIGH | PM2_VC_VSYNC_ACT_HIGH); 1683 1684 vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL); 1685 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL, 1686 vclk & 0xfffffffc); 1687 1688 pm2vfb_set_pll(sc, mode->dot_clock / 2); 1689 pm2fb_write_dac(sc, PM2V_DAC_MISC_CONTROL, PM2V_DAC_8BIT); 1690 1691 if (mode->flags & VID_PHSYNC) 1692 sync |= PM2V_DAC_HSYNC_INV; 1693 if (mode->flags & VID_PVSYNC) 1694 sync |= PM2V_DAC_VSYNC_INV; 1695 pm2fb_write_dac(sc, PM2V_DAC_SYNC_CONTROL, sync); 1696 1697 pm2fb_write_dac(sc, PM2V_DAC_COLOR_FORMAT, PM2V_DAC_PALETTE); 1698 pm2fb_write_dac(sc, PM2V_DAC_PIXEL_SIZE, PM2V_PS_8BIT); 1699 sc->sc_width = mode->hdisplay; 1700 sc->sc_height = mode->vdisplay; 1701 sc->sc_depth = 8; 1702 sc->sc_stride = stride; 1703 aprint_normal_dev(sc->sc_dev, "pm2v using %d x %d in 8 bit, stride %d\n", 1704 sc->sc_width, sc->sc_height, stride); 1705 } 1706 1707 static void 1708 pm2fb_set_mode(struct pm2fb_softc *sc, const struct videomode *mode) 1709 { 1710 if (sc->sc_is_pm2) { 1711 pm2fb_set_dac(sc, mode); 1712 } else { 1713 pm2vfb_set_dac(sc, mode); 1714 } 1715 } 1716