1 /* $NetBSD: crmfb.c,v 1.44 2017/05/19 19:25:53 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * 2008 Michael Lorenz <macallan@netbsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * SGI-CRM (O2) Framebuffer driver 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.44 2017/05/19 19:25:53 macallan Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 42 #include <machine/autoconf.h> 43 #include <sys/bus.h> 44 #include <machine/machtype.h> 45 #include <machine/vmparam.h> 46 47 #include <dev/arcbios/arcbios.h> 48 #include <dev/arcbios/arcbiosvar.h> 49 50 #include <dev/wscons/wsdisplayvar.h> 51 #include <dev/wscons/wsconsio.h> 52 #include <dev/wsfont/wsfont.h> 53 #include <dev/rasops/rasops.h> 54 #include <dev/wscons/wsdisplay_vconsvar.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 62 #include <arch/sgimips/dev/crmfbreg.h> 63 64 #include "opt_crmfb.h" 65 66 #ifdef CRMFB_DEBUG 67 #define DPRINTF printf 68 #else 69 #define DPRINTF while (0) printf 70 #endif 71 72 struct wsscreen_descr crmfb_defaultscreen = { 73 "default", 74 0, 0, 75 NULL, 76 8, 16, 77 WSSCREEN_WSCOLORS | WSSCREEN_RESIZE, 78 NULL, 79 }; 80 81 const struct wsscreen_descr *_crmfb_scrlist[] = { 82 &crmfb_defaultscreen, 83 }; 84 85 struct wsscreen_list crmfb_screenlist = { 86 sizeof(_crmfb_scrlist) / sizeof(struct wsscreen_descr *), 87 _crmfb_scrlist 88 }; 89 90 static struct vcons_screen crmfb_console_screen; 91 92 static int crmfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 93 static paddr_t crmfb_mmap(void *, void *, off_t, int); 94 static void crmfb_init_screen(void *, struct vcons_screen *, int, long *); 95 96 struct wsdisplay_accessops crmfb_accessops = { 97 crmfb_ioctl, 98 crmfb_mmap, 99 NULL, /* alloc_screen */ 100 NULL, /* free_screen */ 101 NULL, /* show_screen */ 102 NULL, /* load_font */ 103 NULL, /* pollc */ 104 NULL, /* scroll */ 105 }; 106 107 /* Memory to allocate to SGI-CRM -- remember, this is stolen from 108 * host memory! 109 */ 110 #define CRMFB_TILESIZE (512*128) 111 112 static int crmfb_match(device_t, struct cfdata *, void *); 113 static void crmfb_attach(device_t, device_t, void *); 114 int crmfb_probe(void); 115 116 #define KERNADDR(p) ((void *)((p).addr)) 117 #define DMAADDR(p) ((p).map->dm_segs[0].ds_addr) 118 119 #define CRMFB_REG_MASK(msb, lsb) \ 120 ( (((uint32_t) 1 << ((msb)-(lsb)+1)) - 1) << (lsb) ) 121 122 123 struct crmfb_dma { 124 bus_dmamap_t map; 125 void *addr; 126 bus_dma_segment_t segs[1]; 127 int nsegs; 128 size_t size; 129 }; 130 131 struct crmfb_softc { 132 device_t sc_dev; 133 struct vcons_data sc_vd; 134 struct i2c_controller sc_i2c; 135 int sc_dir; 136 137 bus_space_tag_t sc_iot; 138 bus_space_handle_t sc_ioh; 139 bus_space_handle_t sc_reh; 140 141 bus_dma_tag_t sc_dmat; 142 143 struct crmfb_dma sc_dma; 144 struct crmfb_dma sc_dmai; 145 146 int sc_width; 147 int sc_height; 148 int sc_depth; 149 int sc_console_depth; 150 int sc_tiles_x, sc_tiles_y; 151 uint32_t sc_fbsize; 152 int sc_mte_direction; 153 int sc_mte_x_shift; 154 uint32_t sc_mte_mode; 155 uint32_t sc_de_mode; 156 uint32_t sc_src_mode; 157 uint32_t sc_dst_mode; 158 int sc_needs_sync; 159 uint8_t *sc_lptr; 160 paddr_t sc_linear; 161 uint32_t sc_vtflags; 162 int sc_wsmode, sc_video_on; 163 uint8_t sc_edid_data[128]; 164 struct edid_info sc_edid_info; 165 166 /* cursor stuff */ 167 int sc_cur_x; 168 int sc_cur_y; 169 int sc_hot_x; 170 int sc_hot_y; 171 172 u_char sc_cmap_red[256]; 173 u_char sc_cmap_green[256]; 174 u_char sc_cmap_blue[256]; 175 }; 176 177 static int crmfb_putcmap(struct crmfb_softc *, struct wsdisplay_cmap *); 178 static int crmfb_getcmap(struct crmfb_softc *, struct wsdisplay_cmap *); 179 static void crmfb_set_palette(struct crmfb_softc *, 180 int, uint8_t, uint8_t, uint8_t); 181 static int crmfb_set_curpos(struct crmfb_softc *, int, int); 182 static int crmfb_gcursor(struct crmfb_softc *, struct wsdisplay_cursor *); 183 static int crmfb_scursor(struct crmfb_softc *, struct wsdisplay_cursor *); 184 static inline void crmfb_write_reg(struct crmfb_softc *, int, uint32_t); 185 static inline uint32_t crmfb_read_reg(struct crmfb_softc *, int); 186 static int crmfb_wait_dma_idle(struct crmfb_softc *); 187 188 /* setup video hw in given colour depth */ 189 static int crmfb_setup_video(struct crmfb_softc *, int); 190 static void crmfb_setup_palette(struct crmfb_softc *); 191 192 static void crmfb_fill_rect(struct crmfb_softc *, int, int, int, int, uint32_t); 193 static void crmfb_bitblt(struct crmfb_softc *, int, int, int, int, int, int, 194 uint32_t); 195 static void crmfb_scroll(struct crmfb_softc *, int, int, int, int, int, int); 196 197 static void crmfb_copycols(void *, int, int, int, int); 198 static void crmfb_erasecols(void *, int, int, int, long); 199 static void crmfb_copyrows(void *, int, int, int); 200 static void crmfb_eraserows(void *, int, int, long); 201 static void crmfb_cursor(void *, int, int, int); 202 static void crmfb_putchar(void *, int, int, u_int, long); 203 static void crmfb_putchar_aa(void *, int, int, u_int, long); 204 205 /* I2C glue */ 206 static int crmfb_i2c_acquire_bus(void *, int); 207 static void crmfb_i2c_release_bus(void *, int); 208 static int crmfb_i2c_send_start(void *, int); 209 static int crmfb_i2c_send_stop(void *, int); 210 static int crmfb_i2c_initiate_xfer(void *, i2c_addr_t, int); 211 static int crmfb_i2c_read_byte(void *, uint8_t *, int); 212 static int crmfb_i2c_write_byte(void *, uint8_t, int); 213 214 /* I2C bitbang glue */ 215 static void crmfb_i2cbb_set_bits(void *, uint32_t); 216 static void crmfb_i2cbb_set_dir(void *, uint32_t); 217 static uint32_t crmfb_i2cbb_read(void *); 218 219 static const struct i2c_bitbang_ops crmfb_i2cbb_ops = { 220 crmfb_i2cbb_set_bits, 221 crmfb_i2cbb_set_dir, 222 crmfb_i2cbb_read, 223 { 224 CRMFB_I2C_SDA, 225 CRMFB_I2C_SCL, 226 0, 227 1 228 } 229 }; 230 static void crmfb_setup_ddc(struct crmfb_softc *); 231 232 /* mode setting stuff */ 233 static uint32_t calc_pll(int); /* frequency in kHz */ 234 static int crmfb_set_mode(struct crmfb_softc *, const struct videomode *); 235 236 CFATTACH_DECL_NEW(crmfb, sizeof(struct crmfb_softc), 237 crmfb_match, crmfb_attach, NULL, NULL); 238 239 static int 240 crmfb_match(device_t parent, struct cfdata *cf, void *opaque) 241 { 242 return crmfb_probe(); 243 } 244 245 static void 246 crmfb_attach(device_t parent, device_t self, void *opaque) 247 { 248 struct mainbus_attach_args *ma; 249 struct crmfb_softc *sc; 250 struct rasops_info *ri; 251 struct wsemuldisplaydev_attach_args aa; 252 uint32_t d, h; 253 uint16_t *p; 254 unsigned long v; 255 long defattr; 256 const char *consdev; 257 int rv, i; 258 259 sc = device_private(self); 260 sc->sc_dev = self; 261 262 ma = (struct mainbus_attach_args *)opaque; 263 264 sc->sc_iot = normal_memt; 265 sc->sc_dmat = &sgimips_default_bus_dma_tag; 266 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL; 267 268 aprint_normal(": SGI CRIME Graphics Display Engine\n"); 269 rv = bus_space_map(sc->sc_iot, ma->ma_addr, 0 /* XXX */, 270 BUS_SPACE_MAP_LINEAR, &sc->sc_ioh); 271 if (rv) 272 panic("crmfb_attach: can't map I/O space"); 273 rv = bus_space_map(sc->sc_iot, 0x15000000, 0x6000, 0, &sc->sc_reh); 274 if (rv) 275 panic("crmfb_attach: can't map rendering engine"); 276 277 /* determine mode configured by firmware */ 278 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP); 279 sc->sc_width = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff; 280 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_VCMAP); 281 sc->sc_height = (d >> CRMFB_VT_VCMAP_ON_SHIFT) & 0xfff; 282 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 283 h = (d >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 0x3; 284 if (h == 0) 285 sc->sc_depth = 8; 286 else if (h == 1) 287 sc->sc_depth = 16; 288 else 289 sc->sc_depth = 32; 290 291 if (sc->sc_width == 0 || sc->sc_height == 0) { 292 /* 293 * XXX 294 * actually, these days we probably could 295 */ 296 aprint_error_dev(sc->sc_dev, 297 "device unusable if not setup by firmware\n"); 298 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0 /* XXX */); 299 return; 300 } 301 302 aprint_normal_dev(sc->sc_dev, "initial resolution %dx%d\n", 303 sc->sc_width, sc->sc_height); 304 305 sc->sc_console_depth = 8; 306 307 crmfb_setup_ddc(sc); 308 if ((sc->sc_edid_info.edid_preferred_mode != NULL)) { 309 if (crmfb_set_mode(sc, sc->sc_edid_info.edid_preferred_mode)) 310 aprint_normal_dev(sc->sc_dev, "using %dx%d\n", 311 sc->sc_width, sc->sc_height); 312 } 313 /* 314 * first determine how many tiles we need 315 * in 32bit each tile is 128x128 pixels 316 */ 317 sc->sc_tiles_x = (sc->sc_width + 127) >> 7; 318 sc->sc_tiles_y = (sc->sc_height + 127) >> 7; 319 sc->sc_fbsize = 0x10000 * sc->sc_tiles_x * sc->sc_tiles_y; 320 321 sc->sc_dmai.size = 256 * sizeof(uint16_t); 322 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmai.size, 65536, 0, 323 sc->sc_dmai.segs, 324 sizeof(sc->sc_dmai.segs) / sizeof(sc->sc_dmai.segs[0]), 325 &sc->sc_dmai.nsegs, BUS_DMA_NOWAIT); 326 if (rv) 327 panic("crmfb_attach: can't allocate DMA memory"); 328 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dmai.segs, sc->sc_dmai.nsegs, 329 sc->sc_dmai.size, &sc->sc_dmai.addr, 330 BUS_DMA_NOWAIT); 331 if (rv) 332 panic("crmfb_attach: can't map DMA memory"); 333 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dmai.size, 1, 334 sc->sc_dmai.size, 0, BUS_DMA_NOWAIT, &sc->sc_dmai.map); 335 if (rv) 336 panic("crmfb_attach: can't create DMA map"); 337 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmai.map, sc->sc_dmai.addr, 338 sc->sc_dmai.size, NULL, BUS_DMA_NOWAIT); 339 if (rv) 340 panic("crmfb_attach: can't load DMA map"); 341 342 /* allocate an extra 128Kb for a linear buffer */ 343 sc->sc_dma.size = 0x10000 * (16 * sc->sc_tiles_x + 2); 344 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0, 345 sc->sc_dma.segs, 346 sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]), 347 &sc->sc_dma.nsegs, BUS_DMA_NOWAIT); 348 if (rv) 349 panic("crmfb_attach: can't allocate DMA memory"); 350 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dma.segs, sc->sc_dma.nsegs, 351 sc->sc_dma.size, &sc->sc_dma.addr, 352 BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 353 if (rv) 354 panic("crmfb_attach: can't map DMA memory"); 355 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dma.size, 1, 356 sc->sc_dma.size, 0, BUS_DMA_NOWAIT, &sc->sc_dma.map); 357 if (rv) 358 panic("crmfb_attach: can't create DMA map"); 359 360 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr, 361 sc->sc_dma.size, NULL, BUS_DMA_NOWAIT); 362 if (rv) 363 panic("crmfb_attach: can't load DMA map"); 364 365 p = KERNADDR(sc->sc_dmai); 366 v = (unsigned long)DMAADDR(sc->sc_dma); 367 for (i = 0; i < (sc->sc_tiles_x * sc->sc_tiles_y); i++) { 368 p[i] = ((uint32_t)v >> 16) + i; 369 } 370 371 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmai.map, 0, sc->sc_dmai.size, 372 BUS_DMASYNC_PREWRITE); 373 374 sc->sc_linear = (paddr_t)DMAADDR(sc->sc_dma) + 0x100000 * sc->sc_tiles_x; 375 sc->sc_lptr = (char *)KERNADDR(sc->sc_dma) + (0x100000 * sc->sc_tiles_x); 376 377 aprint_normal_dev(sc->sc_dev, "allocated %d byte fb @ %p (%p)\n", 378 sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma)); 379 380 crmfb_setup_video(sc, sc->sc_console_depth); 381 ri = &crmfb_console_screen.scr_ri; 382 memset(ri, 0, sizeof(struct rasops_info)); 383 sc->sc_video_on = 1; 384 385 vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops); 386 sc->sc_vd.init_screen = crmfb_init_screen; 387 crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 388 vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr); 389 390 crmfb_defaultscreen.ncols = ri->ri_cols; 391 crmfb_defaultscreen.nrows = ri->ri_rows; 392 crmfb_defaultscreen.textops = &ri->ri_ops; 393 crmfb_defaultscreen.capabilities = ri->ri_caps; 394 crmfb_defaultscreen.modecookie = NULL; 395 396 crmfb_setup_palette(sc); 397 crmfb_fill_rect(sc, 0, 0, sc->sc_width, sc->sc_height, 398 ri->ri_devcmap[(defattr >> 16) & 0xff]); 399 400 consdev = arcbios_GetEnvironmentVariable("ConsoleOut"); 401 if (consdev != NULL && strcmp(consdev, "video()") == 0) { 402 wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr); 403 vcons_replay_msgbuf(&crmfb_console_screen); 404 aa.console = 1; 405 } else 406 aa.console = 0; 407 aa.scrdata = &crmfb_screenlist; 408 aa.accessops = &crmfb_accessops; 409 aa.accesscookie = &sc->sc_vd; 410 411 config_found(self, &aa, wsemuldisplaydevprint); 412 413 sc->sc_cur_x = 0; 414 sc->sc_cur_y = 0; 415 sc->sc_hot_x = 0; 416 sc->sc_hot_y = 0; 417 418 return; 419 } 420 421 int 422 crmfb_probe(void) 423 { 424 425 if (mach_type != MACH_SGI_IP32) 426 return 0; 427 428 return 1; 429 } 430 431 static int 432 crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 433 { 434 struct vcons_data *vd; 435 struct crmfb_softc *sc; 436 struct wsdisplay_fbinfo *wdf; 437 int nmode; 438 439 vd = (struct vcons_data *)v; 440 sc = (struct crmfb_softc *)vd->cookie; 441 442 switch (cmd) { 443 case WSDISPLAYIO_GTYPE: 444 /* not really, but who cares? */ 445 /* xf86-video-crime does */ 446 *(u_int *)data = WSDISPLAY_TYPE_CRIME; 447 return 0; 448 case WSDISPLAYIO_GINFO: 449 if (vd->active != NULL) { 450 wdf = (void *)data; 451 wdf->height = sc->sc_height; 452 wdf->width = sc->sc_width; 453 wdf->depth = 32; 454 wdf->cmsize = 256; 455 return 0; 456 } else 457 return ENODEV; 458 case WSDISPLAYIO_GETCMAP: 459 if (sc->sc_depth == 8) 460 return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data); 461 else 462 return EINVAL; 463 case WSDISPLAYIO_PUTCMAP: 464 if (sc->sc_depth == 8) 465 return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data); 466 else 467 return EINVAL; 468 case WSDISPLAYIO_LINEBYTES: 469 *(u_int *)data = sc->sc_width * sc->sc_depth / 8; 470 return 0; 471 case WSDISPLAYIO_SMODE: 472 nmode = *(int *)data; 473 if (nmode != sc->sc_wsmode) { 474 sc->sc_wsmode = nmode; 475 if (nmode == WSDISPLAYIO_MODE_EMUL) { 476 crmfb_setup_video(sc, sc->sc_console_depth); 477 crmfb_setup_palette(sc); 478 vcons_redraw_screen(vd->active); 479 } else { 480 crmfb_setup_video(sc, 32); 481 } 482 } 483 return 0; 484 case WSDISPLAYIO_SVIDEO: 485 { 486 int d = *(int *)data; 487 if (d == sc->sc_video_on) 488 return 0; 489 sc->sc_video_on = d; 490 if (d == WSDISPLAYIO_VIDEO_ON) { 491 crmfb_write_reg(sc, 492 CRMFB_VT_FLAGS, sc->sc_vtflags); 493 } else { 494 /* turn all SYNCs off */ 495 crmfb_write_reg(sc, CRMFB_VT_FLAGS, 496 sc->sc_vtflags | CRMFB_VT_FLAGS_VDRV_LOW | 497 CRMFB_VT_FLAGS_HDRV_LOW | 498 CRMFB_VT_FLAGS_SYNC_LOW); 499 } 500 } 501 return 0; 502 503 case WSDISPLAYIO_GVIDEO: 504 *(int *)data = sc->sc_video_on; 505 return 0; 506 507 case WSDISPLAYIO_GCURPOS: 508 { 509 struct wsdisplay_curpos *pos; 510 511 pos = (struct wsdisplay_curpos *)data; 512 pos->x = sc->sc_cur_x; 513 pos->y = sc->sc_cur_y; 514 } 515 return 0; 516 case WSDISPLAYIO_SCURPOS: 517 { 518 struct wsdisplay_curpos *pos; 519 520 pos = (struct wsdisplay_curpos *)data; 521 crmfb_set_curpos(sc, pos->x, pos->y); 522 } 523 return 0; 524 case WSDISPLAYIO_GCURMAX: 525 { 526 struct wsdisplay_curpos *pos; 527 528 pos = (struct wsdisplay_curpos *)data; 529 pos->x = 32; 530 pos->y = 32; 531 } 532 return 0; 533 case WSDISPLAYIO_GCURSOR: 534 { 535 struct wsdisplay_cursor *cu; 536 537 cu = (struct wsdisplay_cursor *)data; 538 return crmfb_gcursor(sc, cu); 539 } 540 case WSDISPLAYIO_SCURSOR: 541 { 542 struct wsdisplay_cursor *cu; 543 544 cu = (struct wsdisplay_cursor *)data; 545 return crmfb_scursor(sc, cu); 546 } 547 case WSDISPLAYIO_GET_EDID: { 548 struct wsdisplayio_edid_info *d = data; 549 550 d->data_size = 128; 551 if (d->buffer_size < 128) 552 return EAGAIN; 553 if (sc->sc_edid_data[1] == 0) 554 return ENODATA; 555 return copyout(sc->sc_edid_data, d->edid_data, 128); 556 } 557 } 558 return EPASSTHROUGH; 559 } 560 561 static paddr_t 562 crmfb_mmap(void *v, void *vs, off_t offset, int prot) 563 { 564 struct vcons_data *vd; 565 struct crmfb_softc *sc; 566 paddr_t pa; 567 568 vd = (struct vcons_data *)v; 569 sc = (struct crmfb_softc *)vd->cookie; 570 571 /* we probably shouldn't let anyone mmap the framebuffer */ 572 #if 1 573 if (offset >= 0 && offset < (0x100000 * sc->sc_tiles_x)) { 574 pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 575 sc->sc_dma.nsegs, offset, prot, 576 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE); 577 return pa; 578 } 579 #endif 580 /* 581 * here would the TLBs be but we don't want to show them to userland 582 * so we return the page containing the status register 583 */ 584 if ((offset >= 0x15000000) && (offset < 0x15002000)) 585 return bus_space_mmap(sc->sc_iot, 0x15004000, 0, prot, 0); 586 /* now the actual engine registers */ 587 if ((offset >= 0x15002000) && (offset < 0x15005000)) 588 return bus_space_mmap(sc->sc_iot, offset, 0, prot, 0); 589 /* and now the linear area */ 590 if ((offset >= 0x15010000) && (offset < 0x15030000)) 591 return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 592 sc->sc_dma.nsegs, 593 offset + (0x100000 * sc->sc_tiles_x) - 0x15010000, prot, 594 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE); 595 return -1; 596 } 597 598 static void 599 crmfb_init_screen(void *c, struct vcons_screen *scr, int existing, 600 long *defattr) 601 { 602 struct crmfb_softc *sc; 603 struct rasops_info *ri; 604 605 sc = (struct crmfb_softc *)c; 606 ri = &scr->scr_ri; 607 608 scr->scr_flags |= VCONS_LOADFONT; 609 610 ri->ri_flg = RI_CENTER | RI_FULLCLEAR | 611 RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 612 ri->ri_depth = sc->sc_console_depth; 613 ri->ri_width = sc->sc_width; 614 ri->ri_height = sc->sc_height; 615 ri->ri_stride = ri->ri_width * (ri->ri_depth / 8); 616 617 switch (ri->ri_depth) { 618 case 8: 619 ri->ri_flg |= RI_8BIT_IS_RGB; 620 break; 621 case 16: 622 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5; 623 ri->ri_rpos = 11; 624 ri->ri_gpos = 6; 625 ri->ri_bpos = 1; 626 break; 627 case 32: 628 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8; 629 ri->ri_rpos = 8; 630 ri->ri_gpos = 16; 631 ri->ri_bpos = 24; 632 break; 633 } 634 635 ri->ri_bits = NULL; 636 637 rasops_init(ri, 0, 0); 638 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_RESIZE; 639 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 640 ri->ri_width / ri->ri_font->fontwidth); 641 ri->ri_hw = scr; 642 643 ri->ri_ops.cursor = crmfb_cursor; 644 ri->ri_ops.copyrows = crmfb_copyrows; 645 ri->ri_ops.eraserows = crmfb_eraserows; 646 ri->ri_ops.copycols = crmfb_copycols; 647 ri->ri_ops.erasecols = crmfb_erasecols; 648 if (FONT_IS_ALPHA(ri->ri_font)) { 649 ri->ri_ops.putchar = crmfb_putchar_aa; 650 } else { 651 ri->ri_ops.putchar = crmfb_putchar; 652 } 653 return; 654 } 655 656 static int 657 crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 658 { 659 u_int idx, cnt; 660 u_char r[256], g[256], b[256]; 661 u_char *rp, *gp, *bp; 662 int rv, i; 663 664 idx = cm->index; 665 cnt = cm->count; 666 667 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 668 return EINVAL; 669 670 rv = copyin(cm->red, &r[idx], cnt); 671 if (rv) 672 return rv; 673 rv = copyin(cm->green, &g[idx], cnt); 674 if (rv) 675 return rv; 676 rv = copyin(cm->blue, &b[idx], cnt); 677 if (rv) 678 return rv; 679 680 memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt); 681 memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt); 682 memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt); 683 684 rp = &sc->sc_cmap_red[idx]; 685 gp = &sc->sc_cmap_green[idx]; 686 bp = &sc->sc_cmap_blue[idx]; 687 688 for (i = 0; i < cnt; i++) { 689 crmfb_set_palette(sc, idx, *rp, *gp, *bp); 690 idx++; 691 rp++, gp++, bp++; 692 } 693 694 return 0; 695 } 696 697 static int 698 crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 699 { 700 u_int idx, cnt; 701 int rv; 702 703 idx = cm->index; 704 cnt = cm->count; 705 706 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 707 return EINVAL; 708 709 rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt); 710 if (rv) 711 return rv; 712 rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt); 713 if (rv) 714 return rv; 715 rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt); 716 if (rv) 717 return rv; 718 719 return 0; 720 } 721 722 static void 723 crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g, 724 uint8_t b) 725 { 726 uint32_t val; 727 728 if (reg > 255 || sc->sc_depth != 8) 729 return; 730 731 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63) 732 DELAY(10); 733 734 val = (r << 8) | (g << 16) | (b << 24); 735 crmfb_write_reg(sc, CRMFB_CMAP + (reg * 4), val); 736 737 return; 738 } 739 740 static int 741 crmfb_set_curpos(struct crmfb_softc *sc, int x, int y) 742 { 743 uint32_t val; 744 745 sc->sc_cur_x = x; 746 sc->sc_cur_y = y; 747 748 val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16); 749 crmfb_write_reg(sc, CRMFB_CURSOR_POS, val); 750 751 return 0; 752 } 753 754 static int 755 crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 756 { 757 /* do nothing for now */ 758 return 0; 759 } 760 761 static int 762 crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 763 { 764 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 765 766 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, cur->enable ? 1 : 0); 767 } 768 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 769 770 sc->sc_hot_x = cur->hot.x; 771 sc->sc_hot_y = cur->hot.y; 772 } 773 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 774 775 crmfb_set_curpos(sc, cur->pos.x, cur->pos.y); 776 } 777 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 778 int i; 779 uint32_t val; 780 781 for (i = 0; i < cur->cmap.count; i++) { 782 val = (cur->cmap.red[i] << 24) | 783 (cur->cmap.green[i] << 16) | 784 (cur->cmap.blue[i] << 8); 785 crmfb_write_reg(sc, CRMFB_CURSOR_CMAP0 + 786 ((i + cur->cmap.index) << 2), val); 787 } 788 } 789 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 790 791 int i, j, cnt = 0; 792 uint32_t latch = 0, omask; 793 uint8_t imask; 794 for (i = 0; i < 64; i++) { 795 omask = 0x80000000; 796 imask = 0x01; 797 cur->image[cnt] &= cur->mask[cnt]; 798 for (j = 0; j < 8; j++) { 799 if (cur->image[cnt] & imask) 800 latch |= omask; 801 omask >>= 1; 802 if (cur->mask[cnt] & imask) 803 latch |= omask; 804 omask >>= 1; 805 imask <<= 1; 806 } 807 cnt++; 808 imask = 0x01; 809 cur->image[cnt] &= cur->mask[cnt]; 810 for (j = 0; j < 8; j++) { 811 if (cur->image[cnt] & imask) 812 latch |= omask; 813 omask >>= 1; 814 if (cur->mask[cnt] & imask) 815 latch |= omask; 816 omask >>= 1; 817 imask <<= 1; 818 } 819 cnt++; 820 crmfb_write_reg(sc, CRMFB_CURSOR_BITMAP + (i << 2), 821 latch); 822 latch = 0; 823 } 824 } 825 return 0; 826 } 827 828 static inline void 829 crmfb_write_reg(struct crmfb_softc *sc, int offset, uint32_t val) 830 { 831 832 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val); 833 wbflush(); 834 } 835 836 static inline uint32_t 837 crmfb_read_reg(struct crmfb_softc *sc, int offset) 838 { 839 840 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset); 841 } 842 843 static inline void 844 crmfb_wait_idle(struct crmfb_softc *sc) 845 { 846 int i = 0; 847 848 do { 849 i++; 850 } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) & 851 CRIME_DE_IDLE) == 0) && (i < 100000000)); 852 if (i >= 100000000) 853 aprint_error("crmfb_wait_idle() timed out\n"); 854 sc->sc_needs_sync = 0; 855 } 856 857 /* writes to CRIME_DE_MODE_* only take effect when the engine is idle */ 858 859 static inline void 860 crmfb_src_mode(struct crmfb_softc *sc, uint32_t mode) 861 { 862 if (mode == sc->sc_src_mode) 863 return; 864 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, mode); 865 sc->sc_needs_sync = 1; 866 sc->sc_src_mode = mode; 867 } 868 869 static inline void 870 crmfb_dst_mode(struct crmfb_softc *sc, uint32_t mode) 871 { 872 if (mode == sc->sc_dst_mode) 873 return; 874 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST, mode); 875 sc->sc_needs_sync = 1; 876 sc->sc_dst_mode = mode; 877 } 878 879 static inline void 880 crmfb_make_room(struct crmfb_softc *sc, int num) 881 { 882 int i = 0, slots; 883 uint32_t status; 884 885 if (sc->sc_needs_sync != 0) { 886 crmfb_wait_idle(sc); 887 return; 888 } 889 890 do { 891 i++; 892 status = bus_space_read_4(sc->sc_iot, sc->sc_reh, 893 CRIME_DE_STATUS); 894 slots = 60 - CRIME_PIPE_LEVEL(status); 895 } while (slots <= num); 896 } 897 898 static int 899 crmfb_wait_dma_idle(struct crmfb_softc *sc) 900 { 901 int bail = 100000, idle; 902 903 do { 904 idle = ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 905 CRMFB_OVR_CONTROL) & 1) == 0) && 906 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 907 CRMFB_FRM_CONTROL) & 1) == 0) && 908 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 909 CRMFB_DID_CONTROL) & 1) == 0); 910 if (!idle) 911 delay(10); 912 bail--; 913 } while ((!idle) && (bail > 0)); 914 return idle; 915 } 916 917 static int 918 crmfb_setup_video(struct crmfb_softc *sc, int depth) 919 { 920 uint64_t reg; 921 uint32_t d, h, page; 922 int i, bail, tile_width, tlbptr, lptr, j, tx, shift, overhang; 923 const char *wantsync; 924 uint16_t v; 925 926 /* disable DMA */ 927 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL); 928 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT); 929 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d); 930 DELAY(50000); 931 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 932 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 933 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 934 DELAY(50000); 935 crmfb_write_reg(sc, CRMFB_DID_CONTROL, d); 936 DELAY(50000); 937 938 if (!crmfb_wait_dma_idle(sc)) 939 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n"); 940 941 /* ensure that CRM starts drawing at the top left of the screen 942 * when we re-enable DMA later 943 */ 944 d = (1 << CRMFB_VT_XY_FREEZE_SHIFT); 945 crmfb_write_reg(sc, CRMFB_VT_XY, d); 946 delay(1000); 947 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 948 d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 949 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 950 951 /* wait for dotclock to turn off */ 952 bail = 10000; 953 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK) & 954 (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT)) && (bail > 0)) { 955 delay(10); 956 bail--; 957 } 958 959 /* reset FIFO */ 960 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 961 d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 962 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 963 d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 964 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 965 966 /* setup colour mode */ 967 switch (depth) { 968 case 8: 969 h = CRMFB_MODE_TYP_RG3B2; 970 tile_width = 512; 971 break; 972 case 16: 973 h = CRMFB_MODE_TYP_ARGB5; 974 tile_width = 256; 975 break; 976 case 32: 977 h = CRMFB_MODE_TYP_RGB8; 978 tile_width = 128; 979 break; 980 default: 981 panic("Unsupported depth"); 982 } 983 d = h << CRMFB_MODE_TYP_SHIFT; 984 d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT; 985 for (i = 0; i < (32 * 4); i += 4) 986 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d); 987 wbflush(); 988 989 /* setup tile pointer, but don't turn on DMA yet! */ 990 h = DMAADDR(sc->sc_dmai); 991 d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT; 992 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 993 994 /* init framebuffer width and pixel size */ 995 /*d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT);*/ 996 997 d = ((int)(sc->sc_width / tile_width)) << 998 CRMFB_FRM_TILESIZE_WIDTH_SHIFT; 999 overhang = sc->sc_width % tile_width; 1000 if (overhang != 0) { 1001 uint32_t val; 1002 DPRINTF("tile width: %d\n", tile_width); 1003 DPRINTF("overhang: %d\n", overhang); 1004 val = (overhang * (depth >> 3)) >> 5; 1005 DPRINTF("reg: %08x\n", val); 1006 d |= (val & 0x1f); 1007 DPRINTF("d: %08x\n", d); 1008 } 1009 1010 switch (depth) { 1011 case 8: 1012 h = CRMFB_FRM_TILESIZE_DEPTH_8; 1013 break; 1014 case 16: 1015 h = CRMFB_FRM_TILESIZE_DEPTH_16; 1016 break; 1017 case 32: 1018 h = CRMFB_FRM_TILESIZE_DEPTH_32; 1019 break; 1020 default: 1021 panic("Unsupported depth"); 1022 } 1023 d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT); 1024 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 1025 1026 /*h = sc->sc_width * sc->sc_height / (512 / (depth >> 3));*/ 1027 h = sc->sc_height; 1028 d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT; 1029 crmfb_write_reg(sc, CRMFB_FRM_PIXSIZE, d); 1030 1031 /* turn off firmware overlay and hardware cursor */ 1032 crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0); 1033 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0); 1034 1035 /* turn on DMA for the framebuffer */ 1036 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 1037 d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 1038 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 1039 1040 /* enable drawing again */ 1041 crmfb_write_reg(sc, CRMFB_VT_XY, 0); 1042 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 1043 d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 1044 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 1045 1046 /* turn off sync-on-green */ 1047 1048 wantsync = arcbios_GetEnvironmentVariable("SyncOnGreen"); 1049 if ( (wantsync != NULL) && (wantsync[0] == 'n') ) { 1050 sc->sc_vtflags |= CRMFB_VT_FLAGS_SYNC_LOW; 1051 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d); 1052 } 1053 1054 sc->sc_depth = depth; 1055 1056 /* finally set up the drawing engine's TLB A */ 1057 v = (DMAADDR(sc->sc_dma) >> 16) & 0xffff; 1058 tlbptr = 0; 1059 tx = ((sc->sc_width + (tile_width - 1)) & ~(tile_width - 1)) / 1060 tile_width; 1061 1062 DPRINTF("tx: %d\n", tx); 1063 1064 for (i = 0; i < 16; i++) { 1065 reg = 0; 1066 shift = 64; 1067 lptr = 0; 1068 for (j = 0; j < tx; j++) { 1069 shift -= 16; 1070 reg |= (((uint64_t)(v | 0x8000)) << shift); 1071 if (shift == 0) { 1072 shift = 64; 1073 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1074 CRIME_RE_TLB_A + tlbptr + lptr, 1075 reg); 1076 DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg); 1077 reg = 0; 1078 lptr += 8; 1079 } 1080 v++; 1081 } 1082 if (shift != 64) { 1083 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1084 CRIME_RE_TLB_A + tlbptr + lptr, reg); 1085 DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg); 1086 } 1087 tlbptr += 32; 1088 } 1089 1090 /* now put the last 128kB into the 1st linear TLB */ 1091 page = (sc->sc_linear >> 12) | 0x80000000; 1092 tlbptr = 0; 1093 for (i = 0; i < 16; i++) { 1094 reg = ((uint64_t)page << 32) | (page + 1); 1095 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1096 CRIME_RE_LINEAR_A + tlbptr, reg); 1097 page += 2; 1098 tlbptr += 8; 1099 } 1100 wbflush(); 1101 1102 /* do some very basic engine setup */ 1103 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_CLIPMODE, 0); 1104 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_SRC, 0); 1105 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_DST, 0); 1106 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PLANEMASK, 1107 0xffffffff); 1108 1109 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x20, 0); 1110 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x28, 0); 1111 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x30, 0); 1112 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x38, 0); 1113 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x40, 0); 1114 1115 switch (depth) { 1116 case 8: 1117 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 | 1118 DE_MODE_TYPE_CI | DE_MODE_PIXDEPTH_8; 1119 sc->sc_mte_mode = MTE_MODE_DST_ECC | 1120 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1121 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1122 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT); 1123 sc->sc_mte_x_shift = 0; 1124 break; 1125 case 16: 1126 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_16 | 1127 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_16; 1128 sc->sc_mte_mode = MTE_MODE_DST_ECC | 1129 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1130 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1131 (MTE_DEPTH_16 << MTE_DEPTH_SHIFT); 1132 sc->sc_mte_x_shift = 1; 1133 break; 1134 case 32: 1135 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_32 | 1136 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_32; 1137 sc->sc_mte_mode = MTE_MODE_DST_ECC | 1138 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1139 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1140 (MTE_DEPTH_32 << MTE_DEPTH_SHIFT); 1141 sc->sc_mte_x_shift = 2; 1142 break; 1143 default: 1144 panic("%s: unsuported colour depth %d\n", __func__, 1145 depth); 1146 } 1147 sc->sc_needs_sync = 0; 1148 sc->sc_src_mode = 0xffffffff; 1149 sc->sc_dst_mode = 0xffffffff; 1150 1151 crmfb_src_mode(sc, sc->sc_de_mode); 1152 crmfb_dst_mode(sc, sc->sc_de_mode); 1153 1154 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_X, 1); 1155 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_Y, 1); 1156 1157 /* initialize memory transfer engine */ 1158 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1159 sc->sc_mte_mode | MTE_MODE_COPY); 1160 sc->sc_mte_direction = 1; 1161 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, 1); 1162 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, 1); 1163 1164 return 0; 1165 } 1166 1167 static void 1168 crmfb_set_mte_direction(struct crmfb_softc *sc, int dir) 1169 { 1170 if (dir == sc->sc_mte_direction) 1171 return; 1172 1173 crmfb_make_room(sc, 2); 1174 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, dir); 1175 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, dir); 1176 sc->sc_mte_direction = dir; 1177 } 1178 1179 static void 1180 crmfb_setup_palette(struct crmfb_softc *sc) 1181 { 1182 int i, j, x; 1183 uint32_t col; 1184 struct rasops_info *ri = &crmfb_console_screen.scr_ri; 1185 1186 for (i = 0; i < 256; i++) { 1187 crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2], 1188 rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]); 1189 sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2]; 1190 sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1]; 1191 sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0]; 1192 } 1193 1194 if (FONT_IS_ALPHA(ri->ri_font)) { 1195 sc->sc_de_mode = 1196 (sc->sc_de_mode & ~DE_MODE_TYPE_MASK) | DE_MODE_TYPE_RGB; 1197 } 1198 1199 /* draw 16 character cells in 32bit RGBA for alpha blending */ 1200 crmfb_make_room(sc, 3); 1201 crmfb_dst_mode(sc, 1202 DE_MODE_TLB_A | 1203 DE_MODE_BUFDEPTH_32 | 1204 DE_MODE_TYPE_RGBA | 1205 DE_MODE_PIXDEPTH_32); 1206 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1207 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK); 1208 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1209 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1210 j = 0; 1211 x = 0; 1212 for (i = 0; i < 16; i++) { 1213 crmfb_make_room(sc, 2); 1214 col = (rasops_cmap[j] << 24) | 1215 (rasops_cmap[j + 1] << 16) | 1216 (rasops_cmap[j + 2] << 8); 1217 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, col); 1218 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1219 (x << 16) | ((sc->sc_height - 500) & 0xffff)); 1220 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1221 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1222 ((x + ri->ri_font->fontwidth - 1) << 16) | 1223 ((sc->sc_height + ri->ri_font->fontheight - 1) & 0xffff)); 1224 j += 3; 1225 x += ri->ri_font->fontwidth; 1226 } 1227 crmfb_dst_mode(sc, sc->sc_de_mode); 1228 } 1229 1230 static void 1231 crmfb_fill_rect(struct crmfb_softc *sc, int x, int y, int width, int height, 1232 uint32_t colour) 1233 { 1234 int rxa, rxe; 1235 1236 rxa = x << sc->sc_mte_x_shift; 1237 rxe = ((x + width) << sc->sc_mte_x_shift) - 1; 1238 crmfb_set_mte_direction(sc, 1); 1239 crmfb_make_room(sc, 4); 1240 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1241 sc->sc_mte_mode | 0); 1242 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, colour); 1243 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST0, 1244 (rxa << 16) | (y & 0xffff)); 1245 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1246 CRIME_MTE_DST1 | CRIME_DE_START, 1247 (rxe << 16) | ((y + height - 1) & 0xffff)); 1248 } 1249 1250 static void 1251 crmfb_bitblt(struct crmfb_softc *sc, int xs, int ys, int xd, int yd, 1252 int wi, int he, uint32_t rop) 1253 { 1254 uint32_t prim = DE_PRIM_RECTANGLE; 1255 int rxa, rya, rxe, rye, rxs, rys; 1256 crmfb_make_room(sc, 2); 1257 crmfb_src_mode(sc, sc->sc_de_mode); 1258 crmfb_make_room(sc, 6); 1259 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1260 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP | 1261 DE_DRAWMODE_XFER_EN); 1262 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, rop); 1263 if (xs < xd) { 1264 prim |= DE_PRIM_RL; 1265 rxe = xd; 1266 rxa = xd + wi - 1; 1267 rxs = xs + wi - 1; 1268 } else { 1269 prim |= DE_PRIM_LR; 1270 rxe = xd + wi - 1; 1271 rxa = xd; 1272 rxs = xs; 1273 } 1274 if (ys < yd) { 1275 prim |= DE_PRIM_BT; 1276 rye = yd; 1277 rya = yd + he - 1; 1278 rys = ys + he - 1; 1279 } else { 1280 prim |= DE_PRIM_TB; 1281 rye = yd + he - 1; 1282 rya = yd; 1283 rys = ys; 1284 } 1285 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, prim); 1286 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 1287 (rxs << 16) | (rys & 0xffff)); 1288 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1289 (rxa << 16) | (rya & 0xffff)); 1290 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1291 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1292 (rxe << 16) | (rye & 0xffff)); 1293 } 1294 1295 static void 1296 crmfb_scroll(struct crmfb_softc *sc, int xs, int ys, int xd, int yd, 1297 int wi, int he) 1298 { 1299 int rxa, rya, rxe, rye, rxd, ryd, rxde, ryde; 1300 1301 rxa = xs << sc->sc_mte_x_shift; 1302 rxd = xd << sc->sc_mte_x_shift; 1303 rxe = ((xs + wi) << sc->sc_mte_x_shift) - 1; 1304 rxde = ((xd + wi) << sc->sc_mte_x_shift) - 1; 1305 1306 crmfb_make_room(sc, 1); 1307 1308 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1309 sc->sc_mte_mode | MTE_MODE_COPY); 1310 1311 if (ys < yd) { 1312 /* bottom to top */ 1313 rye = ys; 1314 rya = ys + he - 1; 1315 ryd = yd + he - 1; 1316 ryde = yd; 1317 crmfb_set_mte_direction(sc, -1); 1318 } else { 1319 /* top to bottom */ 1320 rye = ys + he - 1; 1321 rya = ys; 1322 ryd = yd; 1323 ryde = yd + he - 1; 1324 crmfb_set_mte_direction(sc, 1); 1325 } 1326 crmfb_make_room(sc, 4); 1327 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0, 1328 (rxa << 16) | rya); 1329 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1, 1330 (rxe << 16) | rye); 1331 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1332 CRIME_MTE_DST0, 1333 (rxd << 16) | ryd); 1334 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST1 | 1335 CRIME_DE_START, 1336 (rxde << 16) | ryde); 1337 } 1338 1339 static void 1340 crmfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1341 { 1342 struct rasops_info *ri = cookie; 1343 struct vcons_screen *scr = ri->ri_hw; 1344 int32_t xs, xd, y, width, height; 1345 1346 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1347 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1348 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1349 width = ri->ri_font->fontwidth * ncols; 1350 height = ri->ri_font->fontheight; 1351 crmfb_bitblt(scr->scr_cookie, xs, y, xd, y, width, height, 3); 1352 } 1353 1354 static void 1355 crmfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1356 { 1357 struct rasops_info *ri = cookie; 1358 struct vcons_screen *scr = ri->ri_hw; 1359 int32_t x, y, width, height, bg; 1360 1361 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1362 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1363 width = ri->ri_font->fontwidth * ncols; 1364 height = ri->ri_font->fontheight; 1365 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1366 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg); 1367 } 1368 1369 static void 1370 crmfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1371 { 1372 struct rasops_info *ri = cookie; 1373 struct vcons_screen *scr = ri->ri_hw; 1374 int32_t x, ys, yd, width, height; 1375 1376 x = ri->ri_xorigin; 1377 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1378 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1379 width = ri->ri_emuwidth; 1380 height = ri->ri_font->fontheight * nrows; 1381 1382 crmfb_scroll(scr->scr_cookie, x, ys, x, yd, width, height); 1383 } 1384 1385 static void 1386 crmfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1387 { 1388 struct rasops_info *ri = cookie; 1389 struct vcons_screen *scr = ri->ri_hw; 1390 int32_t x, y, width, height, bg; 1391 1392 if ((row == 0) && (nrows == ri->ri_rows)) { 1393 x = y = 0; 1394 width = ri->ri_width; 1395 height = ri->ri_height; 1396 } else { 1397 x = ri->ri_xorigin; 1398 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1399 width = ri->ri_emuwidth; 1400 height = ri->ri_font->fontheight * nrows; 1401 } 1402 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1403 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg); 1404 } 1405 1406 static void 1407 crmfb_cursor(void *cookie, int on, int row, int col) 1408 { 1409 struct rasops_info *ri = cookie; 1410 struct vcons_screen *scr = ri->ri_hw; 1411 struct crmfb_softc *sc = scr->scr_cookie; 1412 int x, y, wi,he; 1413 1414 wi = ri->ri_font->fontwidth; 1415 he = ri->ri_font->fontheight; 1416 1417 if (ri->ri_flg & RI_CURSOR) { 1418 x = ri->ri_ccol * wi + ri->ri_xorigin; 1419 y = ri->ri_crow * he + ri->ri_yorigin; 1420 crmfb_bitblt(sc, x, y, x, y, wi, he, 12); 1421 ri->ri_flg &= ~RI_CURSOR; 1422 } 1423 1424 ri->ri_crow = row; 1425 ri->ri_ccol = col; 1426 1427 if (on) 1428 { 1429 x = ri->ri_ccol * wi + ri->ri_xorigin; 1430 y = ri->ri_crow * he + ri->ri_yorigin; 1431 crmfb_bitblt(sc, x, y, x, y, wi, he, 12); 1432 ri->ri_flg |= RI_CURSOR; 1433 } 1434 } 1435 1436 static void 1437 crmfb_putchar(void *cookie, int row, int col, u_int c, long attr) 1438 { 1439 struct rasops_info *ri = cookie; 1440 struct vcons_screen *scr = ri->ri_hw; 1441 struct crmfb_softc *sc = scr->scr_cookie; 1442 struct wsdisplay_font *font = PICK_FONT(ri, c); 1443 uint32_t bg, fg; 1444 int x, y, wi, he, i, uc; 1445 uint8_t *fd8; 1446 uint16_t *fd16; 1447 void *fd; 1448 1449 wi = font->fontwidth; 1450 he = font->fontheight; 1451 1452 x = ri->ri_xorigin + col * wi; 1453 y = ri->ri_yorigin + row * he; 1454 1455 bg = ri->ri_devcmap[(attr >> 16) & 0xff]; 1456 fg = ri->ri_devcmap[(attr >> 24) & 0xff]; 1457 uc = c - font->firstchar; 1458 fd = (uint8_t *)font->data + uc * ri->ri_fontscale; 1459 if (c == 0x20) { 1460 crmfb_fill_rect(sc, x, y, wi, he, bg); 1461 } else { 1462 crmfb_make_room(sc, 6); 1463 /* setup */ 1464 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1465 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | 1466 DE_DRAWMODE_ROP | 1467 DE_DRAWMODE_OPAQUE_STIP | DE_DRAWMODE_POLY_STIP); 1468 wbflush(); 1469 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, 3); 1470 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, fg); 1471 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_BG, bg); 1472 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1473 DE_PRIM_RECTANGLE | DE_PRIM_LR | DE_PRIM_TB); 1474 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STIPPLE_MODE, 1475 0x001f0000); 1476 /* now let's feed the engine */ 1477 crmfb_make_room(sc, 30); 1478 if (font->stride == 1) { 1479 /* shovel in 8 bit quantities */ 1480 fd8 = fd; 1481 for (i = 0; i < he; i++) { 1482 if (i & 8) 1483 crmfb_make_room(sc, 30); 1484 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1485 CRIME_DE_STIPPLE_PAT, *fd8 << 24); 1486 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1487 CRIME_DE_X_VERTEX_0, (x << 16) | y); 1488 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1489 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1490 ((x + wi) << 16) | y); 1491 y++; 1492 fd8++; 1493 } 1494 } else if (font->stride == 2) { 1495 /* shovel in 16 bit quantities */ 1496 fd16 = fd; 1497 for (i = 0; i < he; i++) { 1498 if (i & 8) 1499 crmfb_make_room(sc, 30); 1500 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1501 CRIME_DE_STIPPLE_PAT, *fd16 << 16); 1502 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1503 CRIME_DE_X_VERTEX_0, (x << 16) | y); 1504 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1505 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1506 ((x + wi) << 16) | y); 1507 y++; 1508 fd16++; 1509 } 1510 } 1511 } 1512 } 1513 1514 static void 1515 crmfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1516 { 1517 struct rasops_info *ri = cookie; 1518 struct vcons_screen *scr = ri->ri_hw; 1519 struct crmfb_softc *sc = scr->scr_cookie; 1520 struct wsdisplay_font *font = PICK_FONT(ri, c); 1521 uint32_t bg, fg; 1522 int x, y, wi, he, uc, xx; 1523 void *fd; 1524 1525 wi = font->fontwidth; 1526 he = font->fontheight; 1527 1528 x = ri->ri_xorigin + col * wi; 1529 y = ri->ri_yorigin + row * he; 1530 1531 bg = ri->ri_devcmap[(attr >> 16) & 0xff]; 1532 fg = (attr >> 24); 1533 uc = c - font->firstchar; 1534 fd = (uint8_t *)font->data + uc * ri->ri_fontscale; 1535 1536 /* fill the cell with the background colour */ 1537 crmfb_fill_rect(sc, x, y, wi, he, bg); 1538 1539 /* if all we draw is a space we're done */ 1540 if (c == 0x20) 1541 return; 1542 1543 /* copy the glyph into the linear buffer */ 1544 memcpy(sc->sc_lptr, fd, ri->ri_fontscale); 1545 wbflush(); 1546 1547 /* now blit it on top of the requested fg colour cell */ 1548 xx = fg * wi; 1549 crmfb_make_room(sc, 2); 1550 crmfb_src_mode(sc, 1551 DE_MODE_LIN_A | 1552 DE_MODE_BUFDEPTH_8 | 1553 DE_MODE_TYPE_CI | 1554 DE_MODE_PIXDEPTH_8); 1555 crmfb_dst_mode(sc, 1556 DE_MODE_TLB_A | 1557 DE_MODE_BUFDEPTH_32 | 1558 DE_MODE_TYPE_CI | 1559 DE_MODE_PIXDEPTH_8); 1560 1561 crmfb_make_room(sc, 6); 1562 /* only write into the alpha channel */ 1563 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1564 DE_DRAWMODE_PLANEMASK | 0x08 | 1565 DE_DRAWMODE_XFER_EN); 1566 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1567 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1568 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1); 1569 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 0); 1570 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1571 (xx << 16) | (sc->sc_height & 0xffff)); 1572 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1573 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1574 ((xx + wi - 1) << 16) | ((sc->sc_height + he - 1) & 0xffff)); 1575 1576 /* now draw the actual character */ 1577 crmfb_make_room(sc, 2); 1578 crmfb_src_mode(sc, 1579 DE_MODE_TLB_A | 1580 DE_MODE_BUFDEPTH_32 | 1581 DE_MODE_TYPE_RGBA | 1582 DE_MODE_PIXDEPTH_32); 1583 crmfb_dst_mode(sc, sc->sc_de_mode); 1584 1585 crmfb_make_room(sc, 6); 1586 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1587 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | 1588 DE_DRAWMODE_ALPHA_BLEND | 1589 DE_DRAWMODE_XFER_EN); 1590 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ALPHA_FUNC, 1591 DE_ALPHA_ADD | 1592 (DE_ALPHA_OP_SRC_ALPHA << DE_ALPHA_OP_SRC_SHIFT) | 1593 (DE_ALPHA_OP_1_MINUS_SRC_ALPHA << DE_ALPHA_OP_DST_SHIFT)); 1594 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1595 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1596 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 1597 (xx << 16) | (sc->sc_height & 0xffff)); 1598 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1599 (x << 16) | (y & 0xffff)); 1600 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1601 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1602 ((x + wi - 1) << 16) | ((y + he - 1) & 0xffff)); 1603 } 1604 1605 static void 1606 crmfb_setup_ddc(struct crmfb_softc *sc) 1607 { 1608 int i; 1609 1610 memset(sc->sc_edid_data, 0, 128); 1611 sc->sc_i2c.ic_cookie = sc; 1612 sc->sc_i2c.ic_acquire_bus = crmfb_i2c_acquire_bus; 1613 sc->sc_i2c.ic_release_bus = crmfb_i2c_release_bus; 1614 sc->sc_i2c.ic_send_start = crmfb_i2c_send_start; 1615 sc->sc_i2c.ic_send_stop = crmfb_i2c_send_stop; 1616 sc->sc_i2c.ic_initiate_xfer = crmfb_i2c_initiate_xfer; 1617 sc->sc_i2c.ic_read_byte = crmfb_i2c_read_byte; 1618 sc->sc_i2c.ic_write_byte = crmfb_i2c_write_byte; 1619 sc->sc_i2c.ic_exec = NULL; 1620 i = 0; 1621 while (sc->sc_edid_data[1] == 0 && i++ < 10) 1622 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128); 1623 if (i > 1) 1624 aprint_debug_dev(sc->sc_dev, 1625 "had to try %d times to get EDID data\n", i); 1626 if (i < 11) { 1627 edid_parse(sc->sc_edid_data, &sc->sc_edid_info); 1628 edid_print(&sc->sc_edid_info); 1629 } 1630 } 1631 1632 /* I2C bitbanging */ 1633 static void 1634 crmfb_i2cbb_set_bits(void *cookie, uint32_t bits) 1635 { 1636 struct crmfb_softc *sc = cookie; 1637 1638 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA, bits ^ 3); 1639 } 1640 1641 static void 1642 crmfb_i2cbb_set_dir(void *cookie, uint32_t dir) 1643 { 1644 1645 /* Nothing to do */ 1646 } 1647 1648 static uint32_t 1649 crmfb_i2cbb_read(void *cookie) 1650 { 1651 struct crmfb_softc *sc = cookie; 1652 1653 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA) ^ 3; 1654 } 1655 1656 /* higher level I2C stuff */ 1657 static int 1658 crmfb_i2c_acquire_bus(void *cookie, int flags) 1659 { 1660 1661 /* private bus */ 1662 return 0; 1663 } 1664 1665 static void 1666 crmfb_i2c_release_bus(void *cookie, int flags) 1667 { 1668 1669 /* private bus */ 1670 } 1671 1672 static int 1673 crmfb_i2c_send_start(void *cookie, int flags) 1674 { 1675 1676 return i2c_bitbang_send_start(cookie, flags, &crmfb_i2cbb_ops); 1677 } 1678 1679 static int 1680 crmfb_i2c_send_stop(void *cookie, int flags) 1681 { 1682 1683 return i2c_bitbang_send_stop(cookie, flags, &crmfb_i2cbb_ops); 1684 } 1685 1686 static int 1687 crmfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 1688 { 1689 1690 return i2c_bitbang_initiate_xfer(cookie, addr, flags, 1691 &crmfb_i2cbb_ops); 1692 } 1693 1694 static int 1695 crmfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 1696 { 1697 1698 return i2c_bitbang_read_byte(cookie, valp, flags, &crmfb_i2cbb_ops); 1699 } 1700 1701 static int 1702 crmfb_i2c_write_byte(void *cookie, uint8_t val, int flags) 1703 { 1704 1705 return i2c_bitbang_write_byte(cookie, val, flags, &crmfb_i2cbb_ops); 1706 } 1707 1708 /* mode setting stuff */ 1709 static uint32_t 1710 calc_pll(int f_out) 1711 { 1712 uint32_t ret; 1713 int f_in = 20000; /* 20MHz in */ 1714 int M, N, P; 1715 int error, div, best = 9999999; 1716 int ff1, ff2; 1717 int MM = 0, NN = 0, PP = 0, ff = 0; 1718 1719 /* f_out = M * f_in / (N * (1 << P) */ 1720 1721 for (P = 0; P < 4; P++) { 1722 for (N = 64; N > 0; N--) { 1723 div = N * (1 << P); 1724 M = f_out * div / f_in; 1725 if ((M < 257) && (M > 100)) { 1726 ff1 = M * f_in / div; 1727 ff2 = (M + 1) * f_in / div; 1728 error = abs(ff1 - f_out); 1729 if (error < best) { 1730 MM = M; 1731 NN = N; 1732 PP = P; 1733 ff = ff1; 1734 best = error; 1735 } 1736 error = abs(ff2 - f_out); 1737 if ((error < best) && ( M < 256)){ 1738 MM = M + 1; 1739 NN = N; 1740 PP = P; 1741 ff = ff2; 1742 best = error; 1743 } 1744 } 1745 } 1746 } 1747 DPRINTF("%d: M %d N %d P %d -> %d\n", f_out, MM, NN, PP, ff); 1748 /* now shove the parameters into the register's format */ 1749 ret = (MM - 1) | ((NN - 1) << 8) | (P << 14); 1750 return ret; 1751 } 1752 1753 static int 1754 crmfb_set_mode(struct crmfb_softc *sc, const struct videomode *mode) 1755 { 1756 uint32_t d, dc; 1757 int tmp, diff; 1758 1759 switch (mode->hdisplay % 32) { 1760 case 0: 1761 sc->sc_console_depth = 8; 1762 break; 1763 case 16: 1764 sc->sc_console_depth = 16; 1765 break; 1766 case 8: 1767 case 24: 1768 sc->sc_console_depth = 32; 1769 break; 1770 default: 1771 aprint_error_dev(sc->sc_dev, 1772 "hdisplay (%d) is not a multiple of 32\n", 1773 mode->hdisplay); 1774 return FALSE; 1775 } 1776 if (mode->dot_clock > 150000) { 1777 aprint_error_dev(sc->sc_dev, 1778 "requested dot clock is too high ( %d MHz )\n", 1779 mode->dot_clock / 1000); 1780 return FALSE; 1781 } 1782 1783 /* disable DMA */ 1784 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL); 1785 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT); 1786 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d); 1787 DELAY(50000); 1788 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 1789 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 1790 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 1791 DELAY(50000); 1792 crmfb_write_reg(sc, CRMFB_DID_CONTROL, d); 1793 DELAY(50000); 1794 1795 if (!crmfb_wait_dma_idle(sc)) 1796 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n"); 1797 1798 /* ok, now we're good to go */ 1799 dc = calc_pll(mode->dot_clock); 1800 1801 crmfb_write_reg(sc, CRMFB_VT_XY, 1 << CRMFB_VT_XY_FREEZE_SHIFT); 1802 delay(1000); 1803 1804 /* set the dot clock pll but don't start it yet */ 1805 crmfb_write_reg(sc, CRMFB_DOTCLOCK, dc); 1806 delay(10000); 1807 1808 /* pixel counter */ 1809 d = mode->htotal | (mode->vtotal << 12); 1810 crmfb_write_reg(sc, CRMFB_VT_XYMAX, d); 1811 1812 /* video timings */ 1813 d = mode->vsync_end | (mode->vsync_start << 12); 1814 crmfb_write_reg(sc, CRMFB_VT_VSYNC, d); 1815 1816 d = mode->hsync_end | (mode->hsync_start << 12); 1817 crmfb_write_reg(sc, CRMFB_VT_HSYNC, d); 1818 1819 d = mode->vtotal | (mode->vdisplay << 12); 1820 crmfb_write_reg(sc, CRMFB_VT_VBLANK, d); 1821 1822 d = (mode->htotal - 5) | ((mode->hdisplay - 5) << 12); 1823 crmfb_write_reg(sc, CRMFB_VT_HBLANK, d); 1824 1825 d = mode->vtotal | (mode->vdisplay << 12); 1826 crmfb_write_reg(sc, CRMFB_VT_VCMAP, d); 1827 d = mode->htotal | (mode->hdisplay << 12); 1828 crmfb_write_reg(sc, CRMFB_VT_HCMAP, d); 1829 1830 d = 0; 1831 if (mode->flags & VID_NHSYNC) d |= CRMFB_VT_FLAGS_HDRV_INVERT; 1832 if (mode->flags & VID_NVSYNC) d |= CRMFB_VT_FLAGS_VDRV_INVERT; 1833 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d); 1834 sc->sc_vtflags = d; 1835 1836 diff = -abs(mode->vtotal - mode->vdisplay - 1); 1837 d = ((uint32_t)diff << 12) & 0x00fff000; 1838 d |= (mode->htotal - 20); 1839 crmfb_write_reg(sc, CRMFB_VT_DID_STARTXY, d); 1840 1841 d = ((uint32_t)(diff + 1) << 12) & 0x00fff000; 1842 d |= (mode->htotal - 54); 1843 crmfb_write_reg(sc, CRMFB_VT_CRS_STARTXY, d); 1844 1845 d = ((uint32_t)diff << 12) & 0x00fff000; 1846 d |= (mode->htotal - 4); 1847 crmfb_write_reg(sc, CRMFB_VT_VC_STARTXY, d); 1848 1849 tmp = mode->htotal - 19; 1850 d = tmp << 12; 1851 d |= ((tmp + mode->hdisplay - 2) % mode->htotal); 1852 crmfb_write_reg(sc, CRMFB_VT_HPIX_EN, d); 1853 1854 d = mode->vdisplay | (mode->vtotal << 12); 1855 crmfb_write_reg(sc, CRMFB_VT_VPIX_EN, d); 1856 1857 sc->sc_width = mode->hdisplay; 1858 sc->sc_height = mode->vdisplay; 1859 1860 return TRUE; 1861 } 1862