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