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