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