1 /* $NetBSD: pm2fb.c,v 1.37 2025/06/04 08:06: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.37 2025/06/04 08:06: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/lwp.h> 41 #include <sys/kauth.h> 42 #include <sys/atomic.h> 43 44 #include <dev/videomode/videomode.h> 45 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcidevs.h> 49 #include <dev/pci/pciio.h> 50 #include <dev/pci/pm2reg.h> 51 52 #include <dev/wscons/wsdisplayvar.h> 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wsfont/wsfont.h> 55 #include <dev/rasops/rasops.h> 56 #include <dev/wscons/wsdisplay_vconsvar.h> 57 #include <dev/wscons/wsdisplay_glyphcachevar.h> 58 #include <dev/pci/wsdisplay_pci.h> 59 60 #include <dev/i2c/i2cvar.h> 61 #include <dev/i2c/i2c_bitbang.h> 62 #include <dev/i2c/ddcvar.h> 63 #include <dev/videomode/videomode.h> 64 #include <dev/videomode/edidvar.h> 65 #include <dev/videomode/edidreg.h> 66 67 #include "opt_pm2fb.h" 68 69 #ifdef PM2FB_DEBUG 70 #define DPRINTF aprint_error 71 #else 72 #define DPRINTF while (0) printf 73 #endif 74 75 #if BYTE_ORDER == LITTLE_ENDIAN 76 /* 77 * XXX 78 * A temporary workaround for unaligned blits on little endian hardware. 79 * This makes pm2fb_bitblt() work well on little endian hardware to get 80 * scrolling right, but not much more. Unaligned blits ( as in, where the lower 81 * 2 bits of the source and destination X coordinates don't match ) are still 82 * wrong so the glyph cache is also disabled. 83 */ 84 #define BITBLT_LE_WORKAROUND 85 #endif 86 87 struct pm2fb_softc { 88 device_t sc_dev; 89 90 pci_chipset_tag_t sc_pc; 91 pcitag_t sc_pcitag; 92 93 bus_space_tag_t sc_memt; 94 bus_space_tag_t sc_iot; 95 96 bus_space_handle_t sc_regh; 97 bus_addr_t sc_fb, sc_reg; 98 bus_size_t sc_fbsize, sc_regsize; 99 100 int sc_width, sc_height, sc_depth, sc_stride; 101 int sc_locked; 102 struct vcons_screen sc_console_screen; 103 struct wsscreen_descr sc_defaultscreen_descr; 104 const struct wsscreen_descr *sc_screens[1]; 105 struct wsscreen_list sc_screenlist; 106 struct vcons_data vd; 107 int sc_mode; 108 u_char sc_cmap_red[256]; 109 u_char sc_cmap_green[256]; 110 u_char sc_cmap_blue[256]; 111 /* engine stuff */ 112 uint32_t sc_pprod; 113 int sc_is_pm2; 114 /* i2c stuff */ 115 struct i2c_controller sc_i2c; 116 uint8_t sc_edid_data[128]; 117 struct edid_info sc_ei; 118 const struct videomode *sc_videomode; 119 glyphcache sc_gc; 120 }; 121 122 static int pm2fb_match(device_t, cfdata_t, void *); 123 static void pm2fb_attach(device_t, device_t, void *); 124 125 CFATTACH_DECL_NEW(pm2fb, sizeof(struct pm2fb_softc), 126 pm2fb_match, pm2fb_attach, NULL, NULL); 127 128 extern const u_char rasops_cmap[768]; 129 130 static int pm2fb_ioctl(void *, void *, u_long, void *, int, 131 struct lwp *); 132 static paddr_t pm2fb_mmap(void *, void *, off_t, int); 133 static void pm2fb_init_screen(void *, struct vcons_screen *, int, long *); 134 135 static int pm2fb_putcmap(struct pm2fb_softc *, struct wsdisplay_cmap *); 136 static int pm2fb_getcmap(struct pm2fb_softc *, struct wsdisplay_cmap *); 137 static void pm2fb_init_palette(struct pm2fb_softc *); 138 static int pm2fb_putpalreg(struct pm2fb_softc *, uint8_t, uint8_t, 139 uint8_t, uint8_t); 140 141 static void pm2fb_init(struct pm2fb_softc *); 142 static inline void pm2fb_wait(struct pm2fb_softc *, int); 143 static void pm2fb_flush_engine(struct pm2fb_softc *); 144 static void pm2fb_rectfill(struct pm2fb_softc *, int, int, int, int, 145 uint32_t); 146 static void pm2fb_rectfill_a(void *, int, int, int, int, long); 147 static void pm2fb_bitblt(void *, int, int, int, int, int, int, int); 148 149 static void pm2fb_cursor(void *, int, int, int); 150 static void pm2fb_putchar(void *, int, int, u_int, long); 151 static void pm2fb_putchar_aa(void *, int, int, u_int, long); 152 static void pm2fb_copycols(void *, int, int, int, int); 153 static void pm2fb_erasecols(void *, int, int, int, long); 154 static void pm2fb_copyrows(void *, int, int, int); 155 static void pm2fb_eraserows(void *, int, int, long); 156 157 struct wsdisplay_accessops pm2fb_accessops = { 158 pm2fb_ioctl, 159 pm2fb_mmap, 160 NULL, /* alloc_screen */ 161 NULL, /* free_screen */ 162 NULL, /* show_screen */ 163 NULL, /* load_font */ 164 NULL, /* pollc */ 165 NULL /* scroll */ 166 }; 167 168 /* I2C glue */ 169 static int pm2fb_i2c_send_start(void *, int); 170 static int pm2fb_i2c_send_stop(void *, int); 171 static int pm2fb_i2c_initiate_xfer(void *, i2c_addr_t, int); 172 static int pm2fb_i2c_read_byte(void *, uint8_t *, int); 173 static int pm2fb_i2c_write_byte(void *, uint8_t, int); 174 175 /* I2C bitbang glue */ 176 static void pm2fb_i2cbb_set_bits(void *, uint32_t); 177 static void pm2fb_i2cbb_set_dir(void *, uint32_t); 178 static uint32_t pm2fb_i2cbb_read(void *); 179 180 static void pm2_setup_i2c(struct pm2fb_softc *); 181 182 static const struct i2c_bitbang_ops pm2fb_i2cbb_ops = { 183 pm2fb_i2cbb_set_bits, 184 pm2fb_i2cbb_set_dir, 185 pm2fb_i2cbb_read, 186 { 187 PM2_DD_SDA_IN, 188 PM2_DD_SCL_IN, 189 0, 190 0 191 } 192 }; 193 194 /* mode setting stuff */ 195 static int pm2fb_set_pll(struct pm2fb_softc *, int); 196 static int pm2vfb_set_pll(struct pm2fb_softc *, int); 197 static uint8_t pm2fb_read_dac(struct pm2fb_softc *, int); 198 static void pm2fb_write_dac(struct pm2fb_softc *, int, uint8_t); 199 static void pm2fb_set_mode(struct pm2fb_softc *, const struct videomode *); 200 201 const struct { 202 int vendor; 203 int product; 204 int flags; 205 } pm2fb_pci_devices[] = { 206 { 207 PCI_VENDOR_3DLABS, 208 PCI_PRODUCT_3DLABS_PERMEDIA2V, 209 0 210 }, 211 { 212 PCI_VENDOR_TI, 213 PCI_PRODUCT_TI_TVP4020, 214 1 215 }, 216 { 217 0, 218 0, 219 0 220 } 221 }; 222 223 /* this table is from xf86-video-glint */ 224 #define PARTPROD(a,b,c) (((a)<<6) | ((b)<<3) | (c)) 225 int partprodPermedia[] = { 226 -1, 227 PARTPROD(0,0,1), PARTPROD(0,1,1), PARTPROD(1,1,1), PARTPROD(1,1,2), 228 PARTPROD(1,2,2), PARTPROD(2,2,2), PARTPROD(1,2,3), PARTPROD(2,2,3), 229 PARTPROD(1,3,3), PARTPROD(2,3,3), PARTPROD(1,2,4), PARTPROD(3,3,3), 230 PARTPROD(1,3,4), PARTPROD(2,3,4), -1, PARTPROD(3,3,4), 231 PARTPROD(1,4,4), PARTPROD(2,4,4), -1, PARTPROD(3,4,4), 232 -1, PARTPROD(2,3,5), -1, PARTPROD(4,4,4), 233 PARTPROD(1,4,5), PARTPROD(2,4,5), PARTPROD(3,4,5), -1, 234 -1, -1, -1, PARTPROD(4,4,5), 235 PARTPROD(1,5,5), PARTPROD(2,5,5), -1, PARTPROD(3,5,5), 236 -1, -1, -1, PARTPROD(4,5,5), 237 -1, -1, -1, PARTPROD(3,4,6), 238 -1, -1, -1, PARTPROD(5,5,5), 239 PARTPROD(1,5,6), PARTPROD(2,5,6), -1, PARTPROD(3,5,6), 240 -1, -1, -1, PARTPROD(4,5,6), 241 -1, -1, -1, -1, 242 -1, -1, -1, PARTPROD(5,5,6), 243 -1, -1, -1, -1, 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 0}; 260 261 static inline void 262 pm2fb_wait(struct pm2fb_softc *sc, int slots) 263 { 264 uint32_t reg; 265 266 do { 267 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, 268 PM2_INPUT_FIFO_SPACE); 269 } while (reg <= slots); 270 } 271 272 static void 273 pm2fb_flush_engine(struct pm2fb_softc *sc) 274 { 275 276 pm2fb_wait(sc, 2); 277 278 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_FILTER_MODE, 279 PM2FLT_PASS_SYNC); 280 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SYNC, 0); 281 do { 282 while (bus_space_read_4(sc->sc_memt, sc->sc_regh, 283 PM2_OUTPUT_FIFO_WORDS) == 0); 284 } while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_OUTPUT_FIFO) != 285 PM2_SYNC_TAG); 286 } 287 288 static int 289 pm2fb_match(device_t parent, cfdata_t match, void *aux) 290 { 291 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 292 int i; 293 294 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) 295 return 0; 296 297 for (i = 0; pm2fb_pci_devices[i].vendor; i++) { 298 if ((PCI_VENDOR(pa->pa_id) == pm2fb_pci_devices[i].vendor && 299 PCI_PRODUCT(pa->pa_id) == pm2fb_pci_devices[i].product)) 300 return 100; 301 } 302 303 return (0); 304 } 305 306 static void 307 pm2fb_attach(device_t parent, device_t self, void *aux) 308 { 309 struct pm2fb_softc *sc = device_private(self); 310 struct pci_attach_args *pa = aux; 311 struct rasops_info *ri; 312 struct wsemuldisplaydev_attach_args aa; 313 prop_dictionary_t dict; 314 unsigned long defattr; 315 bool is_console = FALSE; 316 uint32_t flags; 317 int i; 318 319 sc->sc_pc = pa->pa_pc; 320 sc->sc_pcitag = pa->pa_tag; 321 sc->sc_memt = pa->pa_memt; 322 sc->sc_iot = pa->pa_iot; 323 sc->sc_dev = self; 324 325 for (i = 0; pm2fb_pci_devices[i].vendor; i++) { 326 if (PCI_PRODUCT(pa->pa_id) == pm2fb_pci_devices[i].product) { 327 sc->sc_is_pm2 = pm2fb_pci_devices[i].flags ; 328 break; 329 } 330 } 331 332 pci_aprint_devinfo(pa, NULL); 333 334 /* 335 * fill in parameters from properties 336 * if we can't get a usable mode via DDC2 we'll use this to pick one, 337 * which is why we fill them in with some conservative values that 338 * hopefully work as a last resort 339 */ 340 dict = device_properties(self); 341 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) { 342 aprint_error("%s: no width property\n", device_xname(self)); 343 sc->sc_width = 1024; 344 } 345 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) { 346 aprint_error("%s: no height property\n", device_xname(self)); 347 sc->sc_height = 768; 348 } 349 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) { 350 aprint_error("%s: no depth property\n", device_xname(self)); 351 sc->sc_depth = 8; 352 } 353 354 /* 355 * don't look at the linebytes property - The Raptor firmware lies 356 * about it. Get it from width * depth >> 3 instead. 357 */ 358 359 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); 360 361 prop_dictionary_get_bool(dict, "is_console", &is_console); 362 363 pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x14, PCI_MAPREG_TYPE_MEM, 364 &sc->sc_fb, &sc->sc_fbsize, &flags); 365 366 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0, 367 &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 368 aprint_error("%s: failed to map registers.\n", 369 device_xname(sc->sc_dev)); 370 } 371 372 /* 373 * XXX yeah, casting the fb address to uint32_t is formally wrong 374 * but as far as I know there are no PM2 with 64bit BARs 375 */ 376 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self), 377 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb); 378 379 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 380 "default", 381 0, 0, 382 NULL, 383 8, 16, 384 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 385 NULL 386 }; 387 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 388 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 389 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 390 sc->sc_locked = 0; 391 392 pm2_setup_i2c(sc); 393 394 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 395 &pm2fb_accessops); 396 sc->vd.init_screen = pm2fb_init_screen; 397 sc->vd.show_screen_cookie = &sc->sc_gc; 398 sc->vd.show_screen_cb = glyphcache_adapt; 399 400 /* init engine here */ 401 pm2fb_init(sc); 402 403 ri = &sc->sc_console_screen.scr_ri; 404 405 sc->sc_gc.gc_bitblt = pm2fb_bitblt; 406 sc->sc_gc.gc_rectfill = pm2fb_rectfill_a; 407 sc->sc_gc.gc_blitcookie = sc; 408 sc->sc_gc.gc_rop = 3; 409 410 #ifdef PM2FB_DEBUG 411 /* 412 * leave some room at the bottom of the screen for various blitter 413 * tests and in order to make the glyph cache visible 414 */ 415 sc->sc_height -= 200; 416 #endif 417 418 if (is_console) { 419 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 420 &defattr); 421 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 422 423 pm2fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 424 ri->ri_devcmap[(defattr >> 16) & 0xff]); 425 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 426 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 427 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 428 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 429 430 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 431 uimin(2047, (sc->sc_fbsize / sc->sc_stride)) 432 - sc->sc_height - 5, 433 sc->sc_width, 434 ri->ri_font->fontwidth, 435 ri->ri_font->fontheight, 436 defattr); 437 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 438 defattr); 439 vcons_replay_msgbuf(&sc->sc_console_screen); 440 } else { 441 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 442 /* do some minimal setup to avoid weirdnesses later */ 443 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 444 &defattr); 445 } else 446 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 447 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 448 uimin(2047, (sc->sc_fbsize / sc->sc_stride)) 449 - sc->sc_height - 5, 450 sc->sc_width, 451 ri->ri_font->fontwidth, 452 ri->ri_font->fontheight, 453 defattr); 454 } 455 456 pm2fb_init_palette(sc); 457 458 aa.console = is_console; 459 aa.scrdata = &sc->sc_screenlist; 460 aa.accessops = &pm2fb_accessops; 461 aa.accesscookie = &sc->vd; 462 463 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 464 465 #ifdef PM2FB_DEBUG 466 /* 467 * draw a pattern to check if pm2fb_bitblt() gets the alignment stuff 468 * right 469 */ 470 pm2fb_rectfill(sc, 0, sc->sc_height, sc->sc_width, 200, 0xffffffff); 471 pm2fb_rectfill(sc, 0, sc->sc_height, 300, 10, 0); 472 pm2fb_rectfill(sc, 10, sc->sc_height, 200, 10, 0xe0e0e0e0); 473 for (i = 1; i < 20; i++) { 474 pm2fb_bitblt(sc, 0, sc->sc_height, 475 i, sc->sc_height + 10 * i, 476 300, 10, 3); 477 pm2fb_bitblt(sc, i, sc->sc_height, 478 400, sc->sc_height + 10 * i, 479 300, 10, 3); 480 } 481 #endif 482 } 483 484 static int 485 pm2fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 486 struct lwp *l) 487 { 488 struct vcons_data *vd = v; 489 struct pm2fb_softc *sc = vd->cookie; 490 struct wsdisplay_fbinfo *wdf; 491 struct vcons_screen *ms = vd->active; 492 493 switch (cmd) { 494 case WSDISPLAYIO_GTYPE: 495 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 496 return 0; 497 498 /* PCI config read/write passthrough. */ 499 case PCI_IOC_CFGREAD: 500 case PCI_IOC_CFGWRITE: 501 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 502 cmd, data, flag, l); 503 504 case WSDISPLAYIO_GET_BUSID: 505 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 506 sc->sc_pcitag, data); 507 508 case WSDISPLAYIO_GINFO: 509 if (ms == NULL) 510 return ENODEV; 511 wdf = (void *)data; 512 wdf->height = ms->scr_ri.ri_height; 513 wdf->width = ms->scr_ri.ri_width; 514 wdf->depth = ms->scr_ri.ri_depth; 515 wdf->cmsize = 256; 516 return 0; 517 518 case WSDISPLAYIO_GETCMAP: 519 return pm2fb_getcmap(sc, 520 (struct wsdisplay_cmap *)data); 521 522 case WSDISPLAYIO_PUTCMAP: 523 return pm2fb_putcmap(sc, 524 (struct wsdisplay_cmap *)data); 525 526 case WSDISPLAYIO_LINEBYTES: 527 *(u_int *)data = sc->sc_stride; 528 return 0; 529 530 case WSDISPLAYIO_SMODE: { 531 int new_mode = *(int*)data; 532 if (new_mode != sc->sc_mode) { 533 sc->sc_mode = new_mode; 534 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 535 /* first set the video mode */ 536 if (sc->sc_videomode != NULL) { 537 pm2fb_set_mode(sc, sc->sc_videomode); 538 } 539 /* then initialize the drawing engine */ 540 pm2fb_init(sc); 541 pm2fb_init_palette(sc); 542 /* clean out the glyph cache */ 543 glyphcache_wipe(&sc->sc_gc); 544 /* and redraw everything */ 545 vcons_redraw_screen(ms); 546 } else 547 pm2fb_flush_engine(sc); 548 } 549 } 550 return 0; 551 case WSDISPLAYIO_GET_EDID: { 552 struct wsdisplayio_edid_info *d = data; 553 d->data_size = 128; 554 if (d->buffer_size < 128) 555 return EAGAIN; 556 return copyout(sc->sc_edid_data, d->edid_data, 128); 557 } 558 559 case WSDISPLAYIO_GET_FBINFO: { 560 struct wsdisplayio_fbinfo *fbi = data; 561 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 562 } 563 } 564 return EPASSTHROUGH; 565 } 566 567 static paddr_t 568 pm2fb_mmap(void *v, void *vs, off_t offset, int prot) 569 { 570 struct vcons_data *vd = v; 571 struct pm2fb_softc *sc = vd->cookie; 572 paddr_t pa; 573 574 /* 'regular' framebuffer mmap()ing */ 575 if (offset < sc->sc_fbsize) { 576 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot, 577 BUS_SPACE_MAP_LINEAR); 578 return pa; 579 } 580 581 /* 582 * restrict all other mappings to processes with superuser privileges 583 * or the kernel itself 584 */ 585 if (kauth_authorize_machdep(kauth_cred_get(), 586 KAUTH_MACHDEP_UNMANAGEDMEM, 587 NULL, NULL, NULL, NULL) != 0) { 588 aprint_normal("%s: mmap() rejected.\n", 589 device_xname(sc->sc_dev)); 590 return -1; 591 } 592 593 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 594 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 595 BUS_SPACE_MAP_LINEAR); 596 return pa; 597 } 598 599 if ((offset >= sc->sc_reg) && 600 (offset < (sc->sc_reg + sc->sc_regsize))) { 601 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 602 BUS_SPACE_MAP_LINEAR); 603 return pa; 604 } 605 /* XXX 2nd fb BAR? */ 606 607 #ifdef PCI_MAGIC_IO_RANGE 608 /* allow mapping of IO space */ 609 if ((offset >= PCI_MAGIC_IO_RANGE) && 610 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) { 611 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE, 612 0, prot, BUS_SPACE_MAP_LINEAR); 613 return pa; 614 } 615 #endif 616 617 return -1; 618 } 619 620 static void 621 pm2fb_init_screen(void *cookie, struct vcons_screen *scr, 622 int existing, long *defattr) 623 { 624 struct pm2fb_softc *sc = cookie; 625 struct rasops_info *ri = &scr->scr_ri; 626 627 ri->ri_depth = sc->sc_depth; 628 ri->ri_width = sc->sc_width; 629 ri->ri_height = sc->sc_height; 630 ri->ri_stride = sc->sc_stride; 631 ri->ri_flg = RI_CENTER; 632 if (sc->sc_depth == 8) 633 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA; 634 635 scr->scr_flags |= VCONS_LOADFONT; 636 637 rasops_init(ri, 0, 0); 638 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE | WSSCREEN_RESIZE; 639 640 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 641 sc->sc_width / ri->ri_font->fontwidth); 642 643 ri->ri_hw = scr; 644 ri->ri_ops.copyrows = pm2fb_copyrows; 645 ri->ri_ops.copycols = pm2fb_copycols; 646 ri->ri_ops.cursor = pm2fb_cursor; 647 ri->ri_ops.eraserows = pm2fb_eraserows; 648 ri->ri_ops.erasecols = pm2fb_erasecols; 649 if (FONT_IS_ALPHA(ri->ri_font)) { 650 ri->ri_ops.putchar = pm2fb_putchar_aa; 651 } else 652 ri->ri_ops.putchar = pm2fb_putchar; 653 } 654 655 static int 656 pm2fb_putcmap(struct pm2fb_softc *sc, struct wsdisplay_cmap *cm) 657 { 658 u_char *r, *g, *b; 659 u_int index = cm->index; 660 u_int count = cm->count; 661 int i, error; 662 u_char rbuf[256], gbuf[256], bbuf[256]; 663 664 #ifdef PM2FB_DEBUG 665 aprint_debug("putcmap: %d %d\n",index, count); 666 #endif 667 if (cm->index >= 256 || cm->count > 256 || 668 (cm->index + cm->count) > 256) 669 return EINVAL; 670 error = copyin(cm->red, &rbuf[index], count); 671 if (error) 672 return error; 673 error = copyin(cm->green, &gbuf[index], count); 674 if (error) 675 return error; 676 error = copyin(cm->blue, &bbuf[index], count); 677 if (error) 678 return error; 679 680 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 681 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 682 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 683 684 r = &sc->sc_cmap_red[index]; 685 g = &sc->sc_cmap_green[index]; 686 b = &sc->sc_cmap_blue[index]; 687 688 for (i = 0; i < count; i++) { 689 pm2fb_putpalreg(sc, index, *r, *g, *b); 690 index++; 691 r++, g++, b++; 692 } 693 return 0; 694 } 695 696 static int 697 pm2fb_getcmap(struct pm2fb_softc *sc, struct wsdisplay_cmap *cm) 698 { 699 u_int index = cm->index; 700 u_int count = cm->count; 701 int error; 702 703 if (index >= 255 || count > 256 || index + count > 256) 704 return EINVAL; 705 706 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 707 if (error) 708 return error; 709 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 710 if (error) 711 return error; 712 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 713 if (error) 714 return error; 715 716 return 0; 717 } 718 719 static void 720 pm2fb_init_palette(struct pm2fb_softc *sc) 721 { 722 struct rasops_info *ri = &sc->sc_console_screen.scr_ri; 723 int i, j = 0; 724 uint8_t cmap[768]; 725 726 rasops_get_cmap(ri, cmap, sizeof(cmap)); 727 for (i = 0; i < 256; i++) { 728 sc->sc_cmap_red[i] = cmap[j]; 729 sc->sc_cmap_green[i] = cmap[j + 1]; 730 sc->sc_cmap_blue[i] = cmap[j + 2]; 731 pm2fb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 732 j += 3; 733 } 734 } 735 736 static int 737 pm2fb_putpalreg(struct pm2fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 738 uint8_t b) 739 { 740 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_PAL_WRITE_IDX, idx); 741 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, r); 742 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, g); 743 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, b); 744 return 0; 745 } 746 747 static uint8_t 748 pm2fb_read_dac(struct pm2fb_softc *sc, int reg) 749 { 750 if (sc->sc_is_pm2) { 751 bus_space_write_1(sc->sc_memt, sc->sc_regh, 752 PM2_DAC_PAL_WRITE_IDX, reg); 753 return bus_space_read_1(sc->sc_memt, sc->sc_regh, 754 PM2_DAC_INDEX_DATA); 755 } else { 756 bus_space_write_1(sc->sc_memt, sc->sc_regh, 757 PM2V_DAC_INDEX_LOW, reg & 0xff); 758 bus_space_write_1(sc->sc_memt, sc->sc_regh, 759 PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff); 760 return bus_space_read_1(sc->sc_memt, sc->sc_regh, 761 PM2V_DAC_INDEX_DATA); 762 } 763 } 764 765 static void 766 pm2fb_write_dac(struct pm2fb_softc *sc, int reg, uint8_t data) 767 { 768 pm2fb_wait(sc, 3); 769 if (sc->sc_is_pm2) { 770 pm2fb_wait(sc, 2); 771 bus_space_write_1(sc->sc_memt, sc->sc_regh, 772 PM2_DAC_PAL_WRITE_IDX, reg); 773 bus_space_write_1(sc->sc_memt, sc->sc_regh, 774 PM2_DAC_INDEX_DATA, data); 775 } else { 776 pm2fb_wait(sc, 3); 777 bus_space_write_1(sc->sc_memt, sc->sc_regh, 778 PM2V_DAC_INDEX_LOW, reg & 0xff); 779 bus_space_write_1(sc->sc_memt, sc->sc_regh, 780 PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff); 781 bus_space_write_1(sc->sc_memt, sc->sc_regh, 782 PM2V_DAC_INDEX_DATA, data); 783 } 784 } 785 786 static void 787 pm2fb_init(struct pm2fb_softc *sc) 788 { 789 pm2fb_flush_engine(sc); 790 791 pm2fb_wait(sc, 9); 792 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_BASE, 0); 793 /* set aperture endianness */ 794 #if BYTE_ORDER == BIG_ENDIAN 795 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_APERTURE1_CONTROL, 796 PM2_AP_BYTESWAP | PM2_AP_HALFWORDSWAP); 797 #else 798 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_APERTURE1_CONTROL, 0); 799 #endif 800 #if 0 801 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_BYPASS_MASK, 802 0xffffffff); 803 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_WRITE_MASK, 804 0xffffffff); 805 #endif 806 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HW_WRITEMASK, 807 0xffffffff); 808 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SW_WRITEMASK, 809 0xffffffff); 810 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WRITE_MODE, 811 PM2WM_WRITE_EN); 812 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCREENSIZE, 813 (sc->sc_height << 16) | sc->sc_width); 814 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MODE, 815 PM2SC_SCREEN_EN); 816 pm2fb_wait(sc, 8); 817 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0); 818 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0); 819 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); 820 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_COLOUR_MODE, 0); 821 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_ADDRESS_MODE, 0); 822 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_READ_MODE, 0); 823 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_LUT_MODE, 0); 824 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_YUV_MODE, 0); 825 pm2fb_wait(sc, 8); 826 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DEPTH_MODE, 0); 827 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DEPTH, 0); 828 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STENCIL_MODE, 0); 829 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STIPPLE_MODE, 0); 830 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ROP_MODE, 0); 831 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WINDOW_ORIGIN, 0); 832 #if 0 833 sc->sc_pprod = bus_space_read_4(sc->sc_memt, sc->sc_regh, 834 PM2_FB_READMODE) & 835 (PM2FB_PP0_MASK | PM2FB_PP1_MASK | PM2FB_PP2_MASK); 836 #endif 837 sc->sc_pprod = partprodPermedia[sc->sc_stride >> 5]; 838 839 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_READMODE, 840 sc->sc_pprod); 841 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEXMAP_FORMAT, 842 sc->sc_pprod); 843 pm2fb_wait(sc, 9); 844 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DY, 1 << 16); 845 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DXDOM, 0); 846 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXDOM, 0); 847 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXSUB, 0); 848 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTY, 0); 849 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_COUNT, 0); 850 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MINYX, 0); 851 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MAXYX, 852 0x0fff0fff); 853 /* 854 * another scissor we need to disable in order to blit into off-screen 855 * memory 856 */ 857 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCREENSIZE, 858 0x0fff0fff); 859 860 switch(sc->sc_depth) { 861 case 8: 862 bus_space_write_4(sc->sc_memt, sc->sc_regh, 863 PM2_RE_PIXEL_SIZE, PM2PS_8BIT); 864 break; 865 case 16: 866 bus_space_write_4(sc->sc_memt, sc->sc_regh, 867 PM2_RE_PIXEL_SIZE, PM2PS_16BIT); 868 break; 869 case 32: 870 bus_space_write_4(sc->sc_memt, sc->sc_regh, 871 PM2_RE_PIXEL_SIZE, PM2PS_32BIT); 872 break; 873 } 874 pm2fb_flush_engine(sc); 875 DPRINTF("pixel size: %08x\n", 876 bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_RE_PIXEL_SIZE)); 877 } 878 879 static void 880 pm2fb_rectfill(struct pm2fb_softc *sc, int x, int y, int wi, int he, 881 uint32_t colour) 882 { 883 884 pm2fb_wait(sc, 9); 885 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); 886 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); 887 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0); 888 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0); 889 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG, 890 PM2RECFG_WRITE_EN); 891 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_BLOCK_COLOUR, 892 colour); 893 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START, 894 (y << 16) | x); 895 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE, 896 (he << 16) | wi); 897 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER, 898 PM2RE_RECTANGLE | PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL); 899 } 900 901 static void 902 pm2fb_rectfill_a(void *cookie, int x, int y, int wi, int he, long attr) 903 { 904 struct pm2fb_softc *sc = cookie; 905 906 pm2fb_rectfill(sc, x, y, wi, he, 907 sc->vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]); 908 } 909 910 static void 911 pm2fb_bitblt(void *cookie, int xs, int ys, int xd, int yd, 912 int wi, int he, int rop) 913 { 914 struct pm2fb_softc *sc = cookie; 915 uint32_t dir = 0; 916 int rxd, rwi, rxdelta; 917 918 if (yd <= ys) { 919 dir |= PM2RE_INC_Y; 920 } 921 if (xd <= xs) { 922 dir |= PM2RE_INC_X; 923 } 924 pm2fb_wait(sc, 10); 925 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0); 926 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); 927 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0); 928 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0); 929 if (sc->sc_depth == 8) { 930 int adjust; 931 /* 932 * use packed mode for some extra speed 933 * this copies 32bit quantities even in 8 bit mode, so we need 934 * to adjust for cases where the lower two bits in source and 935 * destination X don't align, and/or where the width isn't a 936 * multiple of 4 937 */ 938 if (rop == 3) { 939 bus_space_write_4(sc->sc_memt, sc->sc_regh, 940 PM2_RE_CONFIG, 941 PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | 942 PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6)); 943 } else { 944 bus_space_write_4(sc->sc_memt, sc->sc_regh, 945 PM2_RE_CONFIG, 946 PM2RECFG_READ_SRC | PM2RECFG_READ_DST | 947 PM2RECFG_WRITE_EN | PM2RECFG_PACKED | 948 PM2RECFG_ROP_EN | (rop << 6)); 949 } 950 rxd = xd >> 2; 951 rwi = (wi + 7) >> 2; 952 rxdelta = (xs & 0xffc) - (xd & 0xffc); 953 /* adjust for non-aligned x */ 954 #ifdef BITBLT_LE_WORKAROUND 955 /* I have no idea why this seems to work */ 956 adjust = 1; 957 #else 958 adjust = ((xd & 3) - (xs & 3)); 959 #endif 960 bus_space_write_4(sc->sc_memt, sc->sc_regh, 961 PM2_RE_PACKEDDATA_LIMIT, 962 (xd << 16) | (xd + wi) | (adjust << 29)); 963 964 } else { 965 /* we're in 16 or 32bit mode */ 966 if (rop == 3) { 967 bus_space_write_4(sc->sc_memt, sc->sc_regh, 968 PM2_RE_CONFIG, 969 PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN | 970 PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6)); 971 } else { 972 bus_space_write_4(sc->sc_memt, sc->sc_regh, 973 PM2_RE_CONFIG, 974 PM2RECFG_READ_SRC | PM2RECFG_READ_DST | 975 PM2RECFG_WRITE_EN | PM2RECFG_PACKED | 976 PM2RECFG_ROP_EN | (rop << 6)); 977 } 978 rxd = xd; 979 rwi = wi; 980 rxdelta = xs - xd; 981 } 982 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START, 983 (yd << 16) | rxd); 984 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE, 985 (he << 16) | rwi); 986 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SOURCE_DELTA, 987 (((ys - yd) & 0xfff) << 16) | (rxdelta & 0xfff)); 988 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER, 989 PM2RE_RECTANGLE | dir); 990 } 991 992 static void 993 pm2fb_cursor(void *cookie, int on, int row, int col) 994 { 995 struct rasops_info *ri = cookie; 996 struct vcons_screen *scr = ri->ri_hw; 997 struct pm2fb_softc *sc = scr->scr_cookie; 998 int x, y, wi, he; 999 1000 wi = ri->ri_font->fontwidth; 1001 he = ri->ri_font->fontheight; 1002 1003 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1004 x = ri->ri_ccol * wi + ri->ri_xorigin; 1005 y = ri->ri_crow * he + ri->ri_yorigin; 1006 if (ri->ri_flg & RI_CURSOR) { 1007 pm2fb_bitblt(sc, x, y, x, y, wi, he, 12); 1008 ri->ri_flg &= ~RI_CURSOR; 1009 } 1010 ri->ri_crow = row; 1011 ri->ri_ccol = col; 1012 if (on) { 1013 x = ri->ri_ccol * wi + ri->ri_xorigin; 1014 y = ri->ri_crow * he + ri->ri_yorigin; 1015 pm2fb_bitblt(sc, x, y, x, y, wi, he, 12); 1016 ri->ri_flg |= RI_CURSOR; 1017 } 1018 } else { 1019 scr->scr_ri.ri_crow = row; 1020 scr->scr_ri.ri_ccol = col; 1021 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1022 } 1023 1024 } 1025 1026 static void 1027 pm2fb_putchar(void *cookie, int row, int col, u_int c, long attr) 1028 { 1029 struct rasops_info *ri = cookie; 1030 struct wsdisplay_font *font = PICK_FONT(ri, c); 1031 struct vcons_screen *scr = ri->ri_hw; 1032 struct pm2fb_softc *sc = scr->scr_cookie; 1033 uint32_t mode; 1034 1035 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 1036 void *data; 1037 uint32_t fg, bg; 1038 int uc, i; 1039 int x, y, wi, he; 1040 1041 wi = font->fontwidth; 1042 he = font->fontheight; 1043 1044 if (!CHAR_IN_FONT(c, font)) 1045 return; 1046 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1047 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1048 x = ri->ri_xorigin + col * wi; 1049 y = ri->ri_yorigin + row * he; 1050 if (c == 0x20) { 1051 pm2fb_rectfill(sc, x, y, wi, he, bg); 1052 } else { 1053 uc = c - font->firstchar; 1054 data = (uint8_t *)font->data + uc * ri->ri_fontscale; 1055 1056 mode = PM2RM_MASK_MIRROR; 1057 #if BYTE_ORDER == LITTLE_ENDIAN 1058 switch (ri->ri_font->stride) { 1059 case 1: 1060 mode |= 4 << 7; 1061 break; 1062 case 2: 1063 mode |= 3 << 7; 1064 break; 1065 } 1066 #else 1067 switch (ri->ri_font->stride) { 1068 case 1: 1069 mode |= 3 << 7; 1070 break; 1071 case 2: 1072 mode |= 2 << 7; 1073 break; 1074 } 1075 #endif 1076 pm2fb_wait(sc, 8); 1077 1078 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1079 PM2_RE_MODE, mode); 1080 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1081 PM2_RE_CONFIG, PM2RECFG_WRITE_EN); 1082 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1083 PM2_RE_BLOCK_COLOUR, bg); 1084 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1085 PM2_RE_RECT_START, (y << 16) | x); 1086 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1087 PM2_RE_RECT_SIZE, (he << 16) | wi); 1088 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1089 PM2_RE_RENDER, 1090 PM2RE_RECTANGLE | 1091 PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL); 1092 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1093 PM2_RE_BLOCK_COLOUR, fg); 1094 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1095 PM2_RE_RENDER, 1096 PM2RE_RECTANGLE | PM2RE_SYNC_ON_MASK | 1097 PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL); 1098 1099 pm2fb_wait(sc, he); 1100 switch (ri->ri_font->stride) { 1101 case 1: { 1102 uint8_t *data8 = data; 1103 uint32_t reg; 1104 for (i = 0; i < he; i++) { 1105 reg = *data8; 1106 bus_space_write_4(sc->sc_memt, 1107 sc->sc_regh, 1108 PM2_RE_BITMASK, reg); 1109 data8++; 1110 } 1111 break; 1112 } 1113 case 2: { 1114 uint16_t *data16 = data; 1115 uint32_t reg; 1116 for (i = 0; i < he; i++) { 1117 reg = *data16; 1118 bus_space_write_4(sc->sc_memt, 1119 sc->sc_regh, 1120 PM2_RE_BITMASK, reg); 1121 data16++; 1122 } 1123 break; 1124 } 1125 } 1126 } 1127 if (attr & 1) 1128 pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1129 } 1130 } 1131 1132 static void 1133 pm2fb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1134 { 1135 struct rasops_info *ri = cookie; 1136 struct wsdisplay_font *font = PICK_FONT(ri, c); 1137 struct vcons_screen *scr = ri->ri_hw; 1138 struct pm2fb_softc *sc = scr->scr_cookie; 1139 uint32_t bg, fg, pixel, /*bg32,*/ fg32, aval; 1140 int i, x, y, wi, he; 1141 int r1, g1, b1, /*r0, g0, b0,*/ fgo/*, bgo*/; 1142 uint8_t *data8; 1143 int rv = GC_NOPE, cnt = 0; 1144 1145 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1146 return; 1147 1148 if (!CHAR_IN_FONT(c, font)) 1149 return; 1150 1151 wi = font->fontwidth; 1152 he = font->fontheight; 1153 1154 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1155 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1156 x = ri->ri_xorigin + col * wi; 1157 y = ri->ri_yorigin + row * he; 1158 1159 /* always blit the cell with the background colour */ 1160 pm2fb_rectfill(sc, x, y, wi, he, bg); 1161 1162 /* if we draw a whitespace we're done here */ 1163 if (c == 0x20) { 1164 if (attr & 1) 1165 pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1166 return; 1167 } 1168 1169 #ifdef BITBLT_LE_WORKAROUND 1170 rv = GC_NOPE; 1171 #else 1172 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1173 if (rv == GC_OK) 1174 return; 1175 #endif 1176 1177 data8 = WSFONT_GLYPH(c, font); 1178 1179 pm2fb_wait(sc, 7); 1180 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0); 1181 /* 1182 * XXX 1183 * we *should* be able to get away without reading the framebuffer 1184 * since our background colour is always constant, but for some reason 1185 * that produces random, mostly black background 1186 */ 1187 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG, 1188 PM2RECFG_WRITE_EN | PM2RECFG_READ_DST); 1189 1190 /* enable alpha blending and R3G3B2 output */ 1191 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 1192 PM2AL_ENABLE | 1193 PM2AL_OP_SRC_IS_SRC_ALPHA | 1194 PM2AL_OP_DST_IS_ONE_MINUS_SRC_ALPHA | 1195 PM2AL_332F | PM2AL_RGB); 1196 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 1197 PM2DM_ENABLE | 1198 PM2DM_332F | PM2DM_RGB); 1199 1200 /* 1201 * we need the RGB colours here, so get offsets into rasops_cmap 1202 */ 1203 fgo = ((attr >> 24) & 0xf) * 3; 1204 1205 r1 = rasops_cmap[fgo]; 1206 g1 = rasops_cmap[fgo + 1]; 1207 b1 = rasops_cmap[fgo + 2]; 1208 1209 fg32 = ( r1 << 16) | (g1 << 8) | b1; 1210 1211 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1212 PM2_RE_RECT_START, (y << 16) | x); 1213 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1214 PM2_RE_RECT_SIZE, (he << 16) | wi); 1215 1216 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1217 PM2_RE_RENDER, 1218 PM2RE_RECTANGLE | PM2RE_SYNC_ON_HOST | 1219 PM2RE_INC_X | PM2RE_INC_Y); 1220 1221 pm2fb_wait(sc, 50); 1222 1223 /* 1224 * and now we just hammer the foreground colour and alpha values into 1225 * the upload port 1226 */ 1227 for (i = 0; i < ri->ri_fontscale; i++) { 1228 aval = *data8; 1229 pixel = fg32 | (aval << 24); 1230 cnt++; 1231 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1232 PM2_RE_COLOUR, pixel); 1233 1234 if (cnt > 48) { 1235 pm2fb_wait(sc, 50); 1236 cnt = 0; 1237 } 1238 data8++; 1239 } 1240 1241 if (rv == GC_ADD) { 1242 glyphcache_add(&sc->sc_gc, c, x, y); 1243 } 1244 1245 if (attr & 1) 1246 pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg); 1247 } 1248 1249 static void 1250 pm2fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1251 { 1252 struct rasops_info *ri = cookie; 1253 struct vcons_screen *scr = ri->ri_hw; 1254 struct pm2fb_softc *sc = scr->scr_cookie; 1255 int32_t xs, xd, y, width, height; 1256 1257 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1258 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1259 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1260 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1261 width = ri->ri_font->fontwidth * ncols; 1262 height = ri->ri_font->fontheight; 1263 pm2fb_bitblt(sc, xs, y, xd, y, width, height, 3); 1264 } 1265 } 1266 1267 static void 1268 pm2fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1269 { 1270 struct rasops_info *ri = cookie; 1271 struct vcons_screen *scr = ri->ri_hw; 1272 struct pm2fb_softc *sc = scr->scr_cookie; 1273 int32_t x, y, width, height, fg, bg, ul; 1274 1275 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1276 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1277 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1278 width = ri->ri_font->fontwidth * ncols; 1279 height = ri->ri_font->fontheight; 1280 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1281 1282 pm2fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1283 } 1284 } 1285 1286 static void 1287 pm2fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1288 { 1289 struct rasops_info *ri = cookie; 1290 struct vcons_screen *scr = ri->ri_hw; 1291 struct pm2fb_softc *sc = scr->scr_cookie; 1292 int32_t x, ys, yd, width, height; 1293 1294 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1295 x = ri->ri_xorigin; 1296 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1297 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1298 width = ri->ri_emuwidth; 1299 height = ri->ri_font->fontheight*nrows; 1300 pm2fb_bitblt(sc, x, ys, x, yd, width, height, 3); 1301 } 1302 } 1303 1304 static void 1305 pm2fb_eraserows(void *cookie, int row, int nrows, long fillattr) 1306 { 1307 struct rasops_info *ri = cookie; 1308 struct vcons_screen *scr = ri->ri_hw; 1309 struct pm2fb_softc *sc = scr->scr_cookie; 1310 int32_t x, y, width, height, fg, bg, ul; 1311 1312 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1313 x = ri->ri_xorigin; 1314 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1315 width = ri->ri_emuwidth; 1316 height = ri->ri_font->fontheight * nrows; 1317 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1318 1319 pm2fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1320 } 1321 } 1322 1323 /* 1324 * Permedia2 can't blit outside of 2048x2048, so reject anything higher 1325 * max. dot clock is probably too high 1326 */ 1327 1328 #define MODE_IS_VALID(m) (((m)->hdisplay < 2048) && \ 1329 ((m)->dot_clock < 230000)) 1330 1331 static void 1332 pm2_setup_i2c(struct pm2fb_softc *sc) 1333 { 1334 int i, ok; 1335 #ifdef PM2FB_DEBUG 1336 int j; 1337 #endif 1338 1339 /* Fill in the i2c tag */ 1340 iic_tag_init(&sc->sc_i2c); 1341 sc->sc_i2c.ic_cookie = sc; 1342 sc->sc_i2c.ic_send_start = pm2fb_i2c_send_start; 1343 sc->sc_i2c.ic_send_stop = pm2fb_i2c_send_stop; 1344 sc->sc_i2c.ic_initiate_xfer = pm2fb_i2c_initiate_xfer; 1345 sc->sc_i2c.ic_read_byte = pm2fb_i2c_read_byte; 1346 sc->sc_i2c.ic_write_byte = pm2fb_i2c_write_byte; 1347 1348 DPRINTF("data: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, 1349 PM2_DISPLAY_DATA)); 1350 1351 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, 0); 1352 1353 /* zero out the EDID buffer */ 1354 memset(sc->sc_edid_data, 0, 128); 1355 1356 /* Some monitors don't respond first time */ 1357 i = 0; 1358 ok = 0; 1359 while (!ok && i < 10) { 1360 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128); 1361 ok = (edid_parse(&sc->sc_edid_data[0], &sc->sc_ei) != -1); 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 (ok) { 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