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