1 /* 2 * Copyright (c) 2015 Naruaki Etomi 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 /* 27 * A console driver for Permedia 3 graphics controllers 28 * most of the following was adapted from the xf86-video-glint driver's 29 * pm3_accel.c, pm3_dac.c and pm2fb framebuffer console driver 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/device.h> 36 #include <sys/malloc.h> 37 #include <sys/lwp.h> 38 #include <sys/kauth.h> 39 #include <sys/atomic.h> 40 41 #include <dev/videomode/videomode.h> 42 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcireg.h> 45 #include <dev/pci/pcidevs.h> 46 #include <dev/pci/pciio.h> 47 #include <dev/pci/pm3reg.h> 48 49 #include <dev/wscons/wsdisplayvar.h> 50 #include <dev/wscons/wsconsio.h> 51 #include <dev/wsfont/wsfont.h> 52 #include <dev/rasops/rasops.h> 53 #include <dev/wscons/wsdisplay_vconsvar.h> 54 #include <dev/pci/wsdisplay_pci.h> 55 56 #include <dev/i2c/i2cvar.h> 57 #include <dev/i2c/i2c_bitbang.h> 58 #include <dev/i2c/ddcvar.h> 59 #include <dev/videomode/videomode.h> 60 #include <dev/videomode/edidvar.h> 61 #include <dev/videomode/edidreg.h> 62 63 struct pm3fb_softc { 64 device_t sc_dev; 65 66 pci_chipset_tag_t sc_pc; 67 pcitag_t sc_pcitag; 68 69 bus_space_tag_t sc_memt; 70 bus_space_tag_t sc_iot; 71 72 bus_space_handle_t sc_regh; 73 bus_addr_t sc_fb, sc_reg; 74 bus_size_t sc_fbsize, sc_regsize; 75 76 int sc_width, sc_height, sc_depth, sc_stride; 77 int sc_locked; 78 struct vcons_screen sc_console_screen; 79 struct wsscreen_descr sc_defaultscreen_descr; 80 const struct wsscreen_descr *sc_screens[1]; 81 struct wsscreen_list sc_screenlist; 82 struct vcons_data vd; 83 int sc_mode; 84 u_char sc_cmap_red[256]; 85 u_char sc_cmap_green[256]; 86 u_char sc_cmap_blue[256]; 87 /* i2c stuff */ 88 struct i2c_controller sc_i2c; 89 uint8_t sc_edid_data[128]; 90 struct edid_info sc_ei; 91 const struct videomode *sc_videomode; 92 }; 93 94 static int pm3fb_match(device_t, cfdata_t, void *); 95 static void pm3fb_attach(device_t, device_t, void *); 96 97 CFATTACH_DECL_NEW(pm3fb, sizeof(struct pm3fb_softc), 98 pm3fb_match, pm3fb_attach, NULL, NULL); 99 100 extern const u_char rasops_cmap[768]; 101 102 static int pm3fb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 103 static paddr_t pm3fb_mmap(void *, void *, off_t, int); 104 static void pm3fb_init_screen(void *, struct vcons_screen *, int, long *); 105 106 static int pm3fb_putcmap(struct pm3fb_softc *, struct wsdisplay_cmap *); 107 static int pm3fb_getcmap(struct pm3fb_softc *, struct wsdisplay_cmap *); 108 static void pm3fb_init_palette(struct pm3fb_softc *); 109 static int pm3fb_putpalreg(struct pm3fb_softc *, uint8_t, uint8_t, uint8_t, uint8_t); 110 111 static void pm3fb_init(struct pm3fb_softc *); 112 static inline void pm3fb_wait(struct pm3fb_softc *, int); 113 static void pm3fb_flush_engine(struct pm3fb_softc *); 114 static void pm3fb_rectfill(struct pm3fb_softc *, int, int, int, int, uint32_t); 115 static void pm3fb_bitblt(void *, int, int, int, int, int, int, int); 116 117 static void pm3fb_cursor(void *, int, int, int); 118 static void pm3fb_putchar(void *, int, int, u_int, long); 119 static void pm3fb_copycols(void *, int, int, int, int); 120 static void pm3fb_erasecols(void *, int, int, int, long); 121 static void pm3fb_copyrows(void *, int, int, int); 122 static void pm3fb_eraserows(void *, int, int, long); 123 124 struct wsdisplay_accessops pm3fb_accessops = { 125 pm3fb_ioctl, 126 pm3fb_mmap, 127 NULL, /* alloc_screen */ 128 NULL, /* free_screen */ 129 NULL, /* show_screen */ 130 NULL, /* load_font */ 131 NULL, /* pollc */ 132 NULL /* scroll */ 133 }; 134 135 /* I2C glue */ 136 static int pm3fb_i2c_send_start(void *, int); 137 static int pm3fb_i2c_send_stop(void *, int); 138 static int pm3fb_i2c_initiate_xfer(void *, i2c_addr_t, int); 139 static int pm3fb_i2c_read_byte(void *, uint8_t *, int); 140 static int pm3fb_i2c_write_byte(void *, uint8_t, int); 141 142 /* I2C bitbang glue */ 143 static void pm3fb_i2cbb_set_bits(void *, uint32_t); 144 static void pm3fb_i2cbb_set_dir(void *, uint32_t); 145 static uint32_t pm3fb_i2cbb_read(void *); 146 147 static void pm3_setup_i2c(struct pm3fb_softc *); 148 149 static const struct i2c_bitbang_ops pm3fb_i2cbb_ops = { 150 pm3fb_i2cbb_set_bits, 151 pm3fb_i2cbb_set_dir, 152 pm3fb_i2cbb_read, 153 { 154 PM3_DD_SDA_IN, 155 PM3_DD_SCL_IN, 156 0, 157 0 158 } 159 }; 160 161 /* mode setting stuff */ 162 static int pm3fb_set_pll(struct pm3fb_softc *, int); 163 static void pm3fb_write_dac(struct pm3fb_softc *, int, uint8_t); 164 static void pm3fb_set_mode(struct pm3fb_softc *, const struct videomode *); 165 166 static inline void 167 pm3fb_wait(struct pm3fb_softc *sc, int slots) 168 { 169 uint32_t reg; 170 171 do { 172 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, 173 PM3_INPUT_FIFO_SPACE); 174 } while (reg <= slots); 175 } 176 177 static void 178 pm3fb_flush_engine(struct pm3fb_softc *sc) 179 { 180 181 pm3fb_wait(sc, 2); 182 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FILTER_MODE, PM3_FM_PASS_SYNC); 183 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SYNC, 0); 184 185 do { 186 while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_OUTPUT_FIFO_WORDS) == 0); 187 } while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_OUTPUT_FIFO) != 188 PM3_SYNC_TAG); 189 } 190 191 static int 192 pm3fb_match(device_t parent, cfdata_t match, void *aux) 193 { 194 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 195 196 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) 197 return 0; 198 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3DLABS) 199 return 0; 200 201 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_PERMEDIA3) 202 return 100; 203 return (0); 204 } 205 206 static void 207 pm3fb_attach(device_t parent, device_t self, void *aux) 208 { 209 struct pm3fb_softc *sc = device_private(self); 210 struct pci_attach_args *pa = aux; 211 struct rasops_info *ri; 212 struct wsemuldisplaydev_attach_args aa; 213 prop_dictionary_t dict; 214 unsigned long defattr; 215 bool is_console; 216 uint32_t flags; 217 218 sc->sc_pc = pa->pa_pc; 219 sc->sc_pcitag = pa->pa_tag; 220 sc->sc_memt = pa->pa_memt; 221 sc->sc_iot = pa->pa_iot; 222 sc->sc_dev = self; 223 224 pci_aprint_devinfo(pa, NULL); 225 226 /* 227 * fill in parameters from properties 228 * if we can't get a usable mode via DDC2 we'll use this to pick one, 229 * which is why we fill them in with some conservative values that 230 * hopefully work as a last resort 231 */ 232 dict = device_properties(self); 233 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) { 234 aprint_error("%s: no width property\n", device_xname(self)); 235 sc->sc_width = 1280; 236 } 237 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) { 238 aprint_error("%s: no height property\n", device_xname(self)); 239 sc->sc_height = 1024; 240 } 241 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) { 242 aprint_error("%s: no depth property\n", device_xname(self)); 243 sc->sc_depth = 8; 244 } 245 246 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3); 247 248 prop_dictionary_get_bool(dict, "is_console", &is_console); 249 250 pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x14, PCI_MAPREG_TYPE_MEM, 251 &sc->sc_fb, &sc->sc_fbsize, &flags); 252 253 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0, 254 &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 255 aprint_error("%s: failed to map registers.\n", 256 device_xname(sc->sc_dev)); 257 } 258 259 /* 260 * Permedia 3 always return 64MB fbsize 261 * 16 MB should be enough -- more just wastes map entries 262 */ 263 if (sc->sc_fbsize != 0) 264 sc->sc_fbsize = (16 << 20); 265 266 /* 267 * Some Power Mac G4 model could not initialize these registers, 268 * Power Mac G4 (Mirrored Drive Doors), for example 269 */ 270 #if defined(__powerpc__) 271 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOCALMEMCAPS, 0x02e311B8); 272 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOCALMEMTIMINGS, 0x07424905); 273 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOCALMEMCONTROL, 0x0c000003); 274 #endif 275 276 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self), 277 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb); 278 279 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 280 "default", 281 0, 0, 282 NULL, 283 8, 16, 284 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 285 NULL 286 }; 287 288 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 289 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 290 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 291 sc->sc_locked = 0; 292 293 pm3_setup_i2c(sc); 294 295 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 296 &pm3fb_accessops); 297 298 sc->vd.init_screen = pm3fb_init_screen; 299 300 /* init engine here */ 301 pm3fb_init(sc); 302 303 ri = &sc->sc_console_screen.scr_ri; 304 305 if (is_console) { 306 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 307 &defattr); 308 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 309 310 pm3fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 311 ri->ri_devcmap[(defattr >> 16) & 0xff]); 312 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 313 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 314 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 315 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 316 317 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 318 defattr); 319 vcons_replay_msgbuf(&sc->sc_console_screen); 320 } else { 321 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 322 /* do some minimal setup to avoid weirdnesses later */ 323 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 324 &defattr); 325 } 326 } 327 328 pm3fb_init_palette(sc); 329 330 aa.console = is_console; 331 aa.scrdata = &sc->sc_screenlist; 332 aa.accessops = &pm3fb_accessops; 333 aa.accesscookie = &sc->vd; 334 335 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 336 } 337 338 static int 339 pm3fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 340 struct lwp *l) 341 { 342 struct vcons_data *vd = v; 343 struct pm3fb_softc *sc = vd->cookie; 344 struct wsdisplay_fbinfo *wdf; 345 struct vcons_screen *ms = vd->active; 346 347 switch (cmd) { 348 case WSDISPLAYIO_GTYPE: 349 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 350 return 0; 351 352 /* PCI config read/write passthrough. */ 353 case PCI_IOC_CFGREAD: 354 case PCI_IOC_CFGWRITE: 355 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 356 cmd, data, flag, l); 357 358 case WSDISPLAYIO_GET_BUSID: 359 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 360 sc->sc_pcitag, data); 361 362 case WSDISPLAYIO_GINFO: 363 if (ms == NULL) 364 return ENODEV; 365 wdf = (void *)data; 366 wdf->height = ms->scr_ri.ri_height; 367 wdf->width = ms->scr_ri.ri_width; 368 wdf->depth = ms->scr_ri.ri_depth; 369 wdf->cmsize = 256; 370 return 0; 371 372 case WSDISPLAYIO_GETCMAP: 373 return pm3fb_getcmap(sc, 374 (struct wsdisplay_cmap *)data); 375 376 case WSDISPLAYIO_PUTCMAP: 377 return pm3fb_putcmap(sc, 378 (struct wsdisplay_cmap *)data); 379 380 case WSDISPLAYIO_LINEBYTES: 381 *(u_int *)data = sc->sc_stride; 382 return 0; 383 384 case WSDISPLAYIO_SMODE: { 385 int new_mode = *(int*)data; 386 if (new_mode != sc->sc_mode) { 387 sc->sc_mode = new_mode; 388 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 389 /* first set the video mode */ 390 if (sc->sc_videomode != NULL) { 391 pm3fb_set_mode(sc, sc->sc_videomode); 392 } 393 /* then initialize the drawing engine */ 394 pm3fb_init(sc); 395 pm3fb_init_palette(sc); 396 vcons_redraw_screen(ms); 397 } else 398 pm3fb_flush_engine(sc); 399 } 400 } 401 return 0; 402 case WSDISPLAYIO_GET_EDID: { 403 struct wsdisplayio_edid_info *d = data; 404 d->data_size = 128; 405 if (d->buffer_size < 128) 406 return EAGAIN; 407 return copyout(sc->sc_edid_data, d->edid_data, 128); 408 } 409 410 case WSDISPLAYIO_GET_FBINFO: { 411 struct wsdisplayio_fbinfo *fbi = data; 412 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 413 } 414 } 415 return EPASSTHROUGH; 416 } 417 418 static paddr_t 419 pm3fb_mmap(void *v, void *vs, off_t offset, int prot) 420 { 421 struct vcons_data *vd = v; 422 struct pm3fb_softc *sc = vd->cookie; 423 paddr_t pa; 424 425 /* 'regular' framebuffer mmap()ing */ 426 if (offset < sc->sc_fbsize) { 427 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot, 428 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 429 return pa; 430 } 431 432 /* 433 * restrict all other mappings to processes with superuser privileges 434 * or the kernel itself 435 */ 436 if (kauth_authorize_machdep(kauth_cred_get(), 437 KAUTH_MACHDEP_UNMANAGEDMEM, 438 NULL, NULL, NULL, NULL) != 0) { 439 aprint_normal("%s: mmap() rejected.\n", 440 device_xname(sc->sc_dev)); 441 return -1; 442 } 443 444 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 445 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 446 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 447 return pa; 448 } 449 450 if ((offset >= sc->sc_reg) && 451 (offset < (sc->sc_reg + sc->sc_regsize))) { 452 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 453 BUS_SPACE_MAP_LINEAR); 454 return pa; 455 } 456 457 #ifdef PCI_MAGIC_IO_RANGE 458 /* allow mapping of IO space */ 459 if ((offset >= PCI_MAGIC_IO_RANGE) && 460 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) { 461 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE, 462 0, prot, BUS_SPACE_MAP_LINEAR); 463 return pa; 464 } 465 #endif 466 return -1; 467 } 468 469 static void 470 pm3fb_init_screen(void *cookie, struct vcons_screen *scr, 471 int existing, long *defattr) 472 { 473 struct pm3fb_softc *sc = cookie; 474 struct rasops_info *ri = &scr->scr_ri; 475 476 ri->ri_depth = sc->sc_depth; 477 ri->ri_width = sc->sc_width; 478 ri->ri_height = sc->sc_height; 479 ri->ri_stride = sc->sc_stride; 480 ri->ri_flg = RI_CENTER; 481 if (sc->sc_depth == 8) 482 ri->ri_flg |= RI_8BIT_IS_RGB; 483 484 rasops_init(ri, 0, 0); 485 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE; 486 487 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 488 sc->sc_width / ri->ri_font->fontwidth); 489 490 ri->ri_hw = scr; 491 ri->ri_ops.copyrows = pm3fb_copyrows; 492 ri->ri_ops.copycols = pm3fb_copycols; 493 ri->ri_ops.cursor = pm3fb_cursor; 494 ri->ri_ops.eraserows = pm3fb_eraserows; 495 ri->ri_ops.erasecols = pm3fb_erasecols; 496 ri->ri_ops.putchar = pm3fb_putchar; 497 } 498 499 static int 500 pm3fb_putcmap(struct pm3fb_softc *sc, struct wsdisplay_cmap *cm) 501 { 502 u_char *r, *g, *b; 503 u_int index = cm->index; 504 u_int count = cm->count; 505 int i, error; 506 u_char rbuf[256], gbuf[256], bbuf[256]; 507 508 if (cm->index >= 256 || cm->count > 256 || 509 (cm->index + cm->count) > 256) 510 return EINVAL; 511 error = copyin(cm->red, &rbuf[index], count); 512 if (error) 513 return error; 514 error = copyin(cm->green, &gbuf[index], count); 515 if (error) 516 return error; 517 error = copyin(cm->blue, &bbuf[index], count); 518 if (error) 519 return error; 520 521 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 522 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 523 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 524 525 r = &sc->sc_cmap_red[index]; 526 g = &sc->sc_cmap_green[index]; 527 b = &sc->sc_cmap_blue[index]; 528 529 for (i = 0; i < count; i++) { 530 pm3fb_putpalreg(sc, index, *r, *g, *b); 531 index++; 532 r++, g++, b++; 533 } 534 return 0; 535 } 536 537 static int 538 pm3fb_getcmap(struct pm3fb_softc *sc, struct wsdisplay_cmap *cm) 539 { 540 u_int index = cm->index; 541 u_int count = cm->count; 542 int error; 543 544 if (index >= 255 || count > 256 || index + count > 256) 545 return EINVAL; 546 547 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 548 if (error) 549 return error; 550 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 551 if (error) 552 return error; 553 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 554 if (error) 555 return error; 556 557 return 0; 558 } 559 560 static void 561 pm3fb_init_palette(struct pm3fb_softc *sc) 562 { 563 struct rasops_info *ri = &sc->sc_console_screen.scr_ri; 564 int i, j = 0; 565 uint8_t cmap[768]; 566 567 rasops_get_cmap(ri, cmap, sizeof(cmap)); 568 569 for (i = 0; i < 256; i++) { 570 sc->sc_cmap_red[i] = cmap[j]; 571 sc->sc_cmap_green[i] = cmap[j + 1]; 572 sc->sc_cmap_blue[i] = cmap[j + 2]; 573 pm3fb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 574 j += 3; 575 } 576 } 577 578 static int 579 pm3fb_putpalreg(struct pm3fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, uint8_t b) 580 { 581 582 pm3fb_wait(sc, 4); 583 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_WRITE_IDX, idx); 584 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_DATA, r); 585 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_DATA, g); 586 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_DATA, b); 587 return 0; 588 } 589 590 static void 591 pm3fb_write_dac(struct pm3fb_softc *sc, int reg, uint8_t data) 592 { 593 594 pm3fb_wait(sc, 3); 595 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_INDEX_LOW, reg & 0xff); 596 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_INDEX_HIGH, (reg >> 8) & 0xff); 597 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_INDEX_DATA, data); 598 } 599 600 static void 601 pm3fb_init(struct pm3fb_softc *sc) 602 { 603 604 pm3fb_wait(sc, 16); 605 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_DESTREAD_MODE, 0); 606 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_DESTREAD_ENABLES, 0); 607 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_SOURCEREAD_MODE, 0); 608 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_WRITE_MODE, 0); 609 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FILTER_MODE, PM3_FM_PASS_SYNC); 610 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STATISTIC_MODE, 0); 611 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DELTA_MODE, 0); 612 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RASTERIZER_MODE, 0); 613 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCISSOR_MODE, 0); 614 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LINESTIPPLE_MODE, 0); 615 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_AREASTIPPLE_MODE, 0); 616 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_GID_MODE, 0); 617 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DEPTH_MODE, 0); 618 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STENCIL_MODE, 0); 619 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STENCIL_DATA, 0); 620 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_COLORDDA_MODE, 0); 621 622 pm3fb_wait(sc, 16); 623 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREADDRESS_MODE, 0); 624 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREINDEX_MODE0, 0); 625 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREINDEX_MODE1, 0); 626 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREREAD_MODE, 0); 627 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXELLUT_MODE, 0); 628 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREFILTER_MODE, 0); 629 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITE_MODE, 0); 630 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOLOR_MODE, 0); 631 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITECOLOR_MODE1, 0); 632 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITEALPHA_MODE1, 0); 633 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITECOLOR_MODE0, 0); 634 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITEALPHA_MODE0, 0); 635 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FOG_MODE, 0); 636 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CHROMATEST_MODE, 0); 637 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ALPHATEST_MODE, 0); 638 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ANTIALIAS_MODE, 0); 639 640 pm3fb_wait(sc, 16); 641 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_YUV_MODE, 0); 642 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ALPHABLENDCOLOR_MODE, 0); 643 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ALPHABLENDALPHA_MODE, 0); 644 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DITHER_MODE, 0); 645 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOGICALOP_MODE, 0); 646 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ROUTER_MODE, 0); 647 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_WINDOW, 0); 648 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D, 0); 649 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SPANCOLORMASK, 0xffffffff); 650 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_XBIAS, 0); 651 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_YBIAS, 0); 652 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DELTACONTROL, 0); 653 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_BITMASKPATTERN, 0xffffffff); 654 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_ENABLE, 655 PM3_FBDESTREAD_SET(0xff, 0xff, 0xff)); 656 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_BUFFERADDRESS0, 0); 657 658 pm3fb_wait(sc, 16); 659 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_BUFFEROFFSET0, 0); 660 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_BUFFERWIDTH0, 661 PM3_FBDESTREAD_BUFFERWIDTH_WIDTH(sc->sc_stride)); 662 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FB_DESTREAD_MODE, 663 PM3_FBDRM_ENABLE | PM3_FBDRM_ENABLE0); 664 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFERADDRESS, 0); 665 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFEROFFSET, 0); 666 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFERWIDTH, 667 PM3_FBSOURCEREAD_BUFFERWIDTH_WIDTH(sc->sc_stride)); 668 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_MODE, 669 PM3_FBSOURCEREAD_MODE_BLOCKING | PM3_FBSOURCEREAD_MODE_ENABLE); 670 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_PIXEL_SIZE, PM3_PS_8BIT); 671 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOFTWAREWRITEMASK, 0xffffffff); 672 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBHARDWAREWRITEMASK, 0xffffffff); 673 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITE_MODE, 674 PM3_FBWRITEMODE_WRITEENABLE | PM3_FBWRITEMODE_OPAQUESPAN | PM3_FBWRITEMODE_ENABLE0); 675 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITEBUFFERADDRESS0, 0); 676 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITEBUFFEROFFSET0, 0); 677 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITEBUFFERWIDTH0, 678 PM3_FBWRITEBUFFERWIDTH_WIDTH(sc->sc_stride)); 679 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SIZEOF_FRAMEBUFFER, 4095); 680 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DITHER_MODE, PM3_CF_TO_DIM_CF(4)); 681 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DXDOM, 0); 682 683 pm3fb_wait(sc, 6); 684 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DXSUB, 0); 685 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DY, 1 << 16); 686 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STARTXDOM, 0); 687 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STARTXSUB, 0); 688 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STARTY, 0); 689 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_COUNT, 0); 690 } 691 692 static void 693 pm3fb_rectfill(struct pm3fb_softc *sc, int x, int y, int wi, int he, 694 uint32_t colour) 695 { 696 pm3fb_wait(sc, 4); 697 698 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D, 699 PM3_CONFIG2D_USECONSTANTSOURCE | PM3_CONFIG2D_FOREGROUNDROP_ENABLE | 700 (PM3_CONFIG2D_FOREGROUNDROP(0x3)) | PM3_CONFIG2D_FBWRITE_ENABLE); 701 702 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FOREGROUNDCOLOR, colour); 703 704 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RECTANGLEPOSITION, 705 (((y) & 0xffff) << 16) | ((x) & 0xffff) ); 706 707 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RENDER2D, 708 PM3_RENDER2D_XPOSITIVE | PM3_RENDER2D_YPOSITIVE | 709 PM3_RENDER2D_OPERATION_NORMAL | PM3_RENDER2D_SPANOPERATION | 710 (((he) & 0x0fff) << 16) | ((wi) & 0x0fff)); 711 712 #ifdef PM3FB_DEBUG 713 pm3fb_flush_engine(sc); 714 #endif 715 } 716 717 static void 718 pm3fb_bitblt(void *cookie, int srcx, int srcy, int dstx, int dsty, 719 int width, int height, int rop) 720 { 721 struct pm3fb_softc *sc = cookie; 722 int x_align, offset_x, offset_y; 723 uint32_t dir = 0; 724 725 offset_x = srcx - dstx; 726 offset_y = srcy - dsty; 727 728 if (dsty <= srcy) { 729 dir |= PM3_RENDER2D_YPOSITIVE; 730 } 731 732 if (dstx <= srcx) { 733 dir |= PM3_RENDER2D_XPOSITIVE; 734 } 735 736 x_align = (srcx & 0x1f); 737 738 pm3fb_wait(sc, 6); 739 740 if (rop == 3){ 741 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D, 742 PM3_CONFIG2D_USERSCISSOR_ENABLE | PM3_CONFIG2D_FOREGROUNDROP_ENABLE | PM3_CONFIG2D_BLOCKING | 743 PM3_CONFIG2D_FOREGROUNDROP(rop) | PM3_CONFIG2D_FBWRITE_ENABLE); 744 } else { 745 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D, 746 PM3_CONFIG2D_USERSCISSOR_ENABLE | PM3_CONFIG2D_FOREGROUNDROP_ENABLE | PM3_CONFIG2D_BLOCKING | 747 PM3_CONFIG2D_FOREGROUNDROP(rop) | PM3_CONFIG2D_FBWRITE_ENABLE | PM3_CONFIG2D_FBDESTREAD_ENABLE); 748 } 749 750 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCISSORMINXY, 751 ((dsty & 0x0fff) << 16) | (dstx & 0x0fff)); 752 753 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCISSORMAXXY, 754 (((dsty + height) & 0x0fff) << 16) | ((dstx + width) & 0x0fff)); 755 756 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFEROFFSET, 757 (((offset_y) & 0xffff) << 16) | ((offset_x) & 0xffff)); 758 759 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RECTANGLEPOSITION, 760 (((dsty) & 0xffff) << 16) | ((dstx - x_align) & 0xffff)); 761 762 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RENDER2D, 763 dir | 764 PM3_RENDER2D_OPERATION_NORMAL | PM3_RENDER2D_SPANOPERATION | PM3_RENDER2D_FBSOURCEREADENABLE | 765 (((height) & 0x0fff) << 16) | ((width + x_align) & 0x0fff)); 766 767 #ifdef PM3FB_DEBUG 768 pm3fb_flush_engine(sc); 769 #endif 770 } 771 772 static void 773 pm3fb_cursor(void *cookie, int on, int row, int col) 774 { 775 struct rasops_info *ri = cookie; 776 struct vcons_screen *scr = ri->ri_hw; 777 struct pm3fb_softc *sc = scr->scr_cookie; 778 int x, y, wi, he; 779 780 wi = ri->ri_font->fontwidth; 781 he = ri->ri_font->fontheight; 782 783 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 784 x = ri->ri_ccol * wi + ri->ri_xorigin; 785 y = ri->ri_crow * he + ri->ri_yorigin; 786 if (ri->ri_flg & RI_CURSOR) { 787 pm3fb_bitblt(sc, x, y, x, y, wi, he, 12); 788 ri->ri_flg &= ~RI_CURSOR; 789 } 790 ri->ri_crow = row; 791 ri->ri_ccol = col; 792 if (on) { 793 x = ri->ri_ccol * wi + ri->ri_xorigin; 794 y = ri->ri_crow * he + ri->ri_yorigin; 795 pm3fb_bitblt(sc, x, y, x, y, wi, he, 12); 796 ri->ri_flg |= RI_CURSOR; 797 } 798 } else { 799 scr->scr_ri.ri_crow = row; 800 scr->scr_ri.ri_ccol = col; 801 scr->scr_ri.ri_flg &= ~RI_CURSOR; 802 } 803 } 804 805 static void 806 pm3fb_putchar(void *cookie, int row, int col, u_int c, long attr) 807 { 808 struct rasops_info *ri = cookie; 809 struct wsdisplay_font *font = PICK_FONT(ri, c); 810 struct vcons_screen *scr = ri->ri_hw; 811 struct pm3fb_softc *sc = scr->scr_cookie; 812 uint32_t mode; 813 814 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 815 void *data; 816 uint32_t fg, bg; 817 int uc, i; 818 int x, y, wi, he; 819 820 wi = font->fontwidth; 821 he = font->fontheight; 822 823 if (!CHAR_IN_FONT(c, font)) 824 return; 825 826 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 827 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 828 x = ri->ri_xorigin + col * wi; 829 y = ri->ri_yorigin + row * he; 830 if (c == 0x20) { 831 pm3fb_rectfill(sc, x, y, wi, he, bg); 832 } else { 833 uc = c - font->firstchar; 834 data = (uint8_t *)font->data + uc * ri->ri_fontscale; 835 mode = PM3_RM_MASK_MIRROR; 836 837 #if BYTE_ORDER == LITTLE_ENDIAN 838 switch (ri->ri_font->stride) { 839 case 1: 840 mode |= 4 << 7; 841 break; 842 case 2: 843 mode |= 3 << 7; 844 break; 845 } 846 #else 847 switch (ri->ri_font->stride) { 848 case 1: 849 mode |= 3 << 7; 850 break; 851 case 2: 852 mode |= 2 << 7; 853 break; 854 } 855 #endif 856 pm3fb_wait(sc, 8); 857 bus_space_write_4(sc->sc_memt, sc->sc_regh, 858 PM3_FOREGROUNDCOLOR, fg); 859 bus_space_write_4(sc->sc_memt, sc->sc_regh, 860 PM3_BACKGROUNDCOLOR, bg); 861 862 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RASTERIZER_MODE, mode); 863 864 bus_space_write_4(sc->sc_memt, sc->sc_regh, 865 PM3_CONFIG2D, 866 PM3_CONFIG2D_USERSCISSOR_ENABLE | 867 PM3_CONFIG2D_USECONSTANTSOURCE | 868 PM3_CONFIG2D_FOREGROUNDROP_ENABLE | 869 PM3_CONFIG2D_FOREGROUNDROP(0x03) | 870 PM3_CONFIG2D_OPAQUESPAN | 871 PM3_CONFIG2D_FBWRITE_ENABLE); 872 873 bus_space_write_4(sc->sc_memt, sc->sc_regh, 874 PM3_SCISSORMINXY, ((y & 0x0fff) << 16) | (x & 0x0fff)); 875 876 bus_space_write_4(sc->sc_memt, sc->sc_regh, 877 PM3_SCISSORMAXXY, (((y + he) & 0x0fff) << 16) | ((x + wi) & 0x0fff)); 878 879 bus_space_write_4(sc->sc_memt, sc->sc_regh, 880 PM3_RECTANGLEPOSITION, (((y) & 0xffff)<<16) | ((x) & 0xffff)); 881 882 bus_space_write_4(sc->sc_memt, sc->sc_regh, 883 PM3_RENDER2D, 884 PM3_RENDER2D_XPOSITIVE | 885 PM3_RENDER2D_YPOSITIVE | 886 PM3_RENDER2D_OPERATION_SYNCONBITMASK | 887 PM3_RENDER2D_SPANOPERATION | 888 ((wi) & 0x0fff) | (((he) & 0x0fff) << 16)); 889 890 pm3fb_wait(sc, he); 891 892 switch (ri->ri_font->stride) { 893 case 1: { 894 uint8_t *data8 = data; 895 uint32_t reg; 896 for (i = 0; i < he; i++) { 897 reg = *data8; 898 bus_space_write_4(sc->sc_memt, 899 sc->sc_regh, 900 PM3_BITMASKPATTERN, reg); 901 data8++; 902 } 903 break; 904 } 905 case 2: { 906 uint16_t *data16 = data; 907 uint32_t reg; 908 for (i = 0; i < he; i++) { 909 reg = *data16; 910 bus_space_write_4(sc->sc_memt, 911 sc->sc_regh, 912 PM3_BITMASKPATTERN, reg); 913 data16++; 914 } 915 break; 916 } 917 } 918 } 919 } 920 } 921 922 static void 923 pm3fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 924 { 925 struct rasops_info *ri = cookie; 926 struct vcons_screen *scr = ri->ri_hw; 927 struct pm3fb_softc *sc = scr->scr_cookie; 928 int32_t xs, xd, y, width, height; 929 930 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 931 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 932 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 933 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 934 width = ri->ri_font->fontwidth * ncols; 935 height = ri->ri_font->fontheight; 936 pm3fb_bitblt(sc, xs, y, xd, y, width, height, 3); 937 } 938 } 939 940 static void 941 pm3fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 942 { 943 struct rasops_info *ri = cookie; 944 struct vcons_screen *scr = ri->ri_hw; 945 struct pm3fb_softc *sc = scr->scr_cookie; 946 int32_t x, y, width, height, fg, bg, ul; 947 948 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 949 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 950 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 951 width = ri->ri_font->fontwidth * ncols; 952 height = ri->ri_font->fontheight; 953 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 954 955 pm3fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 956 } 957 } 958 959 static void 960 pm3fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 961 { 962 struct rasops_info *ri = cookie; 963 struct vcons_screen *scr = ri->ri_hw; 964 struct pm3fb_softc *sc = scr->scr_cookie; 965 int32_t x, ys, yd, width, height; 966 967 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 968 x = ri->ri_xorigin; 969 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 970 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 971 width = ri->ri_emuwidth; 972 height = ri->ri_font->fontheight*nrows; 973 pm3fb_bitblt(sc, x, ys, x, yd, width, height, 3); 974 } 975 } 976 977 static void 978 pm3fb_eraserows(void *cookie, int row, int nrows, long fillattr) 979 { 980 struct rasops_info *ri = cookie; 981 struct vcons_screen *scr = ri->ri_hw; 982 struct pm3fb_softc *sc = scr->scr_cookie; 983 int32_t x, y, width, height, fg, bg, ul; 984 985 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 986 x = ri->ri_xorigin; 987 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 988 width = ri->ri_emuwidth; 989 height = ri->ri_font->fontheight * nrows; 990 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 991 992 pm3fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 993 } 994 } 995 996 /* should be enough */ 997 #define MODE_IS_VALID(m) (((m)->hdisplay < 2048)) 998 999 static void 1000 pm3_setup_i2c(struct pm3fb_softc *sc) 1001 { 1002 int i; 1003 1004 /* Fill in the i2c tag */ 1005 iic_tag_init(&sc->sc_i2c); 1006 sc->sc_i2c.ic_cookie = sc; 1007 sc->sc_i2c.ic_send_start = pm3fb_i2c_send_start; 1008 sc->sc_i2c.ic_send_stop = pm3fb_i2c_send_stop; 1009 sc->sc_i2c.ic_initiate_xfer = pm3fb_i2c_initiate_xfer; 1010 sc->sc_i2c.ic_read_byte = pm3fb_i2c_read_byte; 1011 sc->sc_i2c.ic_write_byte = pm3fb_i2c_write_byte; 1012 sc->sc_i2c.ic_exec = NULL; 1013 1014 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DISPLAY_DATA, 0); 1015 1016 /* zero out the EDID buffer */ 1017 memset(sc->sc_edid_data, 0, 128); 1018 1019 /* Some monitors don't respond first time */ 1020 i = 0; 1021 while (sc->sc_edid_data[1] == 0 && i < 10) { 1022 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128); 1023 i++; 1024 } 1025 1026 if (edid_parse(&sc->sc_edid_data[0], &sc->sc_ei) != -1) { 1027 /* 1028 * Now pick a mode. 1029 */ 1030 if ((sc->sc_ei.edid_preferred_mode != NULL)) { 1031 struct videomode *m = sc->sc_ei.edid_preferred_mode; 1032 if (MODE_IS_VALID(m)) { 1033 sc->sc_videomode = m; 1034 } else { 1035 aprint_error_dev(sc->sc_dev, 1036 "unable to use preferred mode\n"); 1037 } 1038 } 1039 /* 1040 * if we can't use the preferred mode go look for the 1041 * best one we can support 1042 */ 1043 if (sc->sc_videomode == NULL) { 1044 struct videomode *m = sc->sc_ei.edid_modes; 1045 1046 sort_modes(sc->sc_ei.edid_modes, 1047 &sc->sc_ei.edid_preferred_mode, 1048 sc->sc_ei.edid_nmodes); 1049 if (sc->sc_videomode == NULL) 1050 for (int n = 0; n < sc->sc_ei.edid_nmodes; n++) 1051 if (MODE_IS_VALID(&m[n])) { 1052 sc->sc_videomode = &m[n]; 1053 break; 1054 } 1055 } 1056 } 1057 if (sc->sc_videomode == NULL) { 1058 /* no EDID data? */ 1059 sc->sc_videomode = pick_mode_by_ref(sc->sc_width, 1060 sc->sc_height, 60); 1061 } 1062 if (sc->sc_videomode != NULL) { 1063 pm3fb_set_mode(sc, sc->sc_videomode); 1064 } 1065 } 1066 1067 /* I2C bitbanging */ 1068 static void pm3fb_i2cbb_set_bits(void *cookie, uint32_t bits) 1069 { 1070 struct pm3fb_softc *sc = cookie; 1071 uint32_t out; 1072 1073 out = bits << 2; /* bitmasks match the IN bits */ 1074 1075 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DISPLAY_DATA, out); 1076 delay(100); 1077 } 1078 1079 static void pm3fb_i2cbb_set_dir(void *cookie, uint32_t dir) 1080 { 1081 /* Nothing to do */ 1082 } 1083 1084 static uint32_t pm3fb_i2cbb_read(void *cookie) 1085 { 1086 struct pm3fb_softc *sc = cookie; 1087 uint32_t bits; 1088 1089 bits = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_DISPLAY_DATA); 1090 return bits; 1091 } 1092 1093 /* higher level I2C stuff */ 1094 static int 1095 pm3fb_i2c_send_start(void *cookie, int flags) 1096 { 1097 1098 return (i2c_bitbang_send_start(cookie, flags, &pm3fb_i2cbb_ops)); 1099 } 1100 1101 static int 1102 pm3fb_i2c_send_stop(void *cookie, int flags) 1103 { 1104 1105 return (i2c_bitbang_send_stop(cookie, flags, &pm3fb_i2cbb_ops)); 1106 } 1107 1108 static int 1109 pm3fb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 1110 { 1111 1112 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, 1113 &pm3fb_i2cbb_ops)); 1114 } 1115 1116 static int 1117 pm3fb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 1118 { 1119 1120 return (i2c_bitbang_read_byte(cookie, valp, flags, &pm3fb_i2cbb_ops)); 1121 } 1122 1123 static int 1124 pm3fb_i2c_write_byte(void *cookie, uint8_t val, int flags) 1125 { 1126 return (i2c_bitbang_write_byte(cookie, val, flags, &pm3fb_i2cbb_ops)); 1127 } 1128 1129 static int 1130 pm3fb_set_pll(struct pm3fb_softc *sc, int freq) 1131 { 1132 uint8_t bf = 0, bpre = 0, bpost = 0; 1133 int count; 1134 unsigned long feedback, prescale, postscale, IntRef, VCO, out_freq, diff, VCOlow, VCOhigh, bdiff = 1000000; 1135 1136 freq *= 10; /* convert into 100Hz units */ 1137 1138 for (postscale = 0; postscale <= 5; postscale++) { 1139 /* 1140 * It is pointless going through the main loop if all values of 1141 * prescale produce an VCO outside the acceptable range 1142 */ 1143 prescale = 1; 1144 feedback = (prescale * (1UL << postscale) * freq) / (2 * PM3_EXT_CLOCK_FREQ); 1145 VCOlow = (2 * PM3_EXT_CLOCK_FREQ * feedback) / prescale; 1146 if (VCOlow > PM3_VCO_FREQ_MAX) 1147 continue; 1148 1149 prescale = 255; 1150 feedback = (prescale * (1UL << postscale) * freq) / (2 * PM3_EXT_CLOCK_FREQ); 1151 VCOhigh = (2 * PM3_EXT_CLOCK_FREQ * feedback) / prescale; 1152 if (VCOhigh < PM3_VCO_FREQ_MIN) 1153 continue; 1154 1155 for (prescale = 1; prescale <= 255; prescale++) { 1156 IntRef = PM3_EXT_CLOCK_FREQ / prescale; 1157 if (IntRef < PM3_INTREF_MIN || IntRef > PM3_INTREF_MAX) { 1158 if (IntRef > PM3_INTREF_MAX) { 1159 /* 1160 * Hopefully we will get into range as the prescale 1161 * value increases 1162 */ 1163 continue; 1164 } else { 1165 /* 1166 * already below minimum and it will only get worse 1167 * move to the next postscale value 1168 */ 1169 break; 1170 } 1171 } 1172 1173 feedback = (prescale * (1UL << postscale) * freq) / (2 * PM3_EXT_CLOCK_FREQ); 1174 1175 if (feedback > 255) { 1176 /* 1177 * prescale, feedbackscale & postscale registers 1178 * are only 8 bits wide 1179 */ 1180 break; 1181 } else if (feedback == 255) { 1182 count = 1; 1183 } else { 1184 count = 2; 1185 } 1186 1187 do { 1188 VCO = (2 * PM3_EXT_CLOCK_FREQ * feedback) / prescale; 1189 if (VCO >= PM3_VCO_FREQ_MIN && VCO <= PM3_VCO_FREQ_MAX) { 1190 out_freq = VCO / (1UL << postscale); 1191 diff = abs(out_freq - freq); 1192 if (diff < bdiff) { 1193 bdiff = diff; 1194 bf = feedback; 1195 bpre = prescale; 1196 bpost = postscale; 1197 if (diff == 0) 1198 goto out; 1199 } 1200 } 1201 feedback++; 1202 } while (--count >= 0); 1203 } 1204 } 1205 out: 1206 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_CLOCK0_PRE_SCALE, bpre); 1207 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_CLOCK0_FEEDBACK_SCALE, bf); 1208 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_CLOCK0_POST_SCALE, bpost); 1209 return 0; 1210 } 1211 1212 static void 1213 pm3fb_set_mode(struct pm3fb_softc *sc, const struct videomode *mode) 1214 { 1215 int t1, t2, t3, t4, stride; 1216 uint32_t vclk, tmp1; 1217 uint8_t sync = 0; 1218 1219 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_BYPASS_MASK, 0xffffffff); 1220 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_APERTURE1_CONTROL, 0x00000000); 1221 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_APERTURE2_CONTROL, 0x00000000); 1222 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FIFODISCONNECT, 0x00000007); 1223 1224 t1 = mode->hsync_start - mode->hdisplay; 1225 t2 = mode->vsync_start - mode->vdisplay; 1226 t3 = mode->hsync_end - mode->hsync_start; 1227 t4 = mode->vsync_end - mode->vsync_start; 1228 stride = (mode->hdisplay + 31) & ~31; 1229 1230 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_TOTAL, 1231 ((mode->htotal - 1) >> 4)); 1232 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_SYNC_END, 1233 (t1 + t3) >> 4); 1234 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_SYNC_START, 1235 (t1 >> 4)); 1236 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_BLANK_END, 1237 (mode->htotal - mode->hdisplay) >> 4); 1238 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_GATE_END, 1239 (mode->htotal - mode->hdisplay) >> 4); 1240 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCREEN_STRIDE, 1241 (stride >> 4)); 1242 1243 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1244 PM3_VERT_TOTAL, mode->vtotal - 1); 1245 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1246 PM3_VERT_SYNC_END, t2 + t4 - 1); 1247 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1248 PM3_VERT_SYNC_START, t2 - 1); 1249 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1250 PM3_VERT_BLANK_END, mode->vtotal - mode->vdisplay); 1251 1252 /*8bpp*/ 1253 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1254 PM3_BYAPERTURE1MODE, PM3_BYAPERTUREMODE_PIXELSIZE_8BIT); 1255 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1256 PM3_BYAPERTURE2MODE, PM3_BYAPERTUREMODE_PIXELSIZE_8BIT); 1257 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_VIDEO_CONTROL, 1258 (PM3_VC_ENABLE | PM3_VC_HSC_ACTIVE_HIGH | PM3_VC_VSC_ACTIVE_HIGH | PM3_VC_PIXELSIZE_8BIT)); 1259 1260 vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_V_CLOCK_CTL); 1261 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_V_CLOCK_CTL, (vclk & 0xFFFFFFFC)); 1262 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCREEN_BASE, 0x0); 1263 1264 tmp1 = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_CHIP_CONFIG); 1265 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CHIP_CONFIG, tmp1 & 0xFFFFFFFD); 1266 1267 pm3fb_set_pll(sc, mode->dot_clock); 1268 1269 if (mode->flags & VID_PHSYNC) 1270 sync |= PM3_SC_HSYNC_ACTIVE_HIGH; 1271 if (mode->flags & VID_PVSYNC) 1272 sync |= PM3_SC_VSYNC_ACTIVE_HIGH; 1273 1274 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1275 PM3_RD_PM3_INDEX_CONTROL, PM3_INCREMENT_DISABLE); 1276 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_SYNC_CONTROL, sync); 1277 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_DAC_CONTROL, 0x00); 1278 1279 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_PIXEL_SIZE, PM3_DACPS_8BIT); 1280 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_COLOR_FORMAT, 1281 (PM3_CF_ORDER_BGR | PM3_CF_VISUAL_256_COLOR)); 1282 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_MISC_CONTROL, PM3_MC_DAC_SIZE_8BIT); 1283 1284 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FIFOCONTROL, 0x00000905); 1285 1286 sc->sc_width = mode->hdisplay; 1287 sc->sc_height = mode->vdisplay; 1288 sc->sc_depth = 8; 1289 sc->sc_stride = stride; 1290 aprint_normal_dev(sc->sc_dev, "pm3 using %d x %d in 8 bit, stride %d\n", 1291 sc->sc_width, sc->sc_height, stride); 1292 } 1293