1 /* $NetBSD: crmfb.c,v 1.40 2015/02/18 16:47:58 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.40 2015/02/18 16:47:58 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, 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 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr, 360 sc->sc_dma.size, NULL, BUS_DMA_NOWAIT); 361 if (rv) 362 panic("crmfb_attach: can't load DMA map"); 363 364 p = KERNADDR(sc->sc_dmai); 365 v = (unsigned long)DMAADDR(sc->sc_dma); 366 for (i = 0; i < (sc->sc_tiles_x * sc->sc_tiles_y); i++) { 367 p[i] = ((uint32_t)v >> 16) + i; 368 } 369 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmai.map, 0, sc->sc_dmai.size, 370 BUS_DMASYNC_PREWRITE); 371 sc->sc_linear = (paddr_t)DMAADDR(sc->sc_dma) + 0x100000 * sc->sc_tiles_x; 372 sc->sc_lptr = (char *)KERNADDR(sc->sc_dma) + (0x100000 * sc->sc_tiles_x); 373 374 aprint_normal_dev(sc->sc_dev, "allocated %d byte fb @ %p (%p)\n", 375 sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma)); 376 377 crmfb_setup_video(sc, sc->sc_console_depth); 378 ri = &crmfb_console_screen.scr_ri; 379 memset(ri, 0, sizeof(struct rasops_info)); 380 sc->sc_video_on = 1; 381 382 vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops); 383 sc->sc_vd.init_screen = crmfb_init_screen; 384 crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 385 vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr); 386 387 crmfb_defaultscreen.ncols = ri->ri_cols; 388 crmfb_defaultscreen.nrows = ri->ri_rows; 389 crmfb_defaultscreen.textops = &ri->ri_ops; 390 crmfb_defaultscreen.capabilities = ri->ri_caps; 391 crmfb_defaultscreen.modecookie = NULL; 392 393 crmfb_setup_palette(sc); 394 crmfb_fill_rect(sc, 0, 0, sc->sc_width, sc->sc_height, 395 ri->ri_devcmap[(defattr >> 16) & 0xff]); 396 397 consdev = arcbios_GetEnvironmentVariable("ConsoleOut"); 398 if (consdev != NULL && strcmp(consdev, "video()") == 0) { 399 wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr); 400 vcons_replay_msgbuf(&crmfb_console_screen); 401 aa.console = 1; 402 } else 403 aa.console = 0; 404 aa.scrdata = &crmfb_screenlist; 405 aa.accessops = &crmfb_accessops; 406 aa.accesscookie = &sc->sc_vd; 407 408 config_found(self, &aa, wsemuldisplaydevprint); 409 410 sc->sc_cur_x = 0; 411 sc->sc_cur_y = 0; 412 sc->sc_hot_x = 0; 413 sc->sc_hot_y = 0; 414 415 return; 416 } 417 418 int 419 crmfb_probe(void) 420 { 421 422 if (mach_type != MACH_SGI_IP32) 423 return 0; 424 425 return 1; 426 } 427 428 static int 429 crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 430 { 431 struct vcons_data *vd; 432 struct crmfb_softc *sc; 433 struct wsdisplay_fbinfo *wdf; 434 int nmode; 435 436 vd = (struct vcons_data *)v; 437 sc = (struct crmfb_softc *)vd->cookie; 438 439 switch (cmd) { 440 case WSDISPLAYIO_GTYPE: 441 /* not really, but who cares? */ 442 /* xf86-video-crime does */ 443 *(u_int *)data = WSDISPLAY_TYPE_CRIME; 444 return 0; 445 case WSDISPLAYIO_GINFO: 446 if (vd->active != NULL) { 447 wdf = (void *)data; 448 wdf->height = sc->sc_height; 449 wdf->width = sc->sc_width; 450 wdf->depth = 32; 451 wdf->cmsize = 256; 452 return 0; 453 } else 454 return ENODEV; 455 case WSDISPLAYIO_GETCMAP: 456 if (sc->sc_depth == 8) 457 return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data); 458 else 459 return EINVAL; 460 case WSDISPLAYIO_PUTCMAP: 461 if (sc->sc_depth == 8) 462 return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data); 463 else 464 return EINVAL; 465 case WSDISPLAYIO_LINEBYTES: 466 *(u_int *)data = sc->sc_width * sc->sc_depth / 8; 467 return 0; 468 case WSDISPLAYIO_SMODE: 469 nmode = *(int *)data; 470 if (nmode != sc->sc_wsmode) { 471 sc->sc_wsmode = nmode; 472 if (nmode == WSDISPLAYIO_MODE_EMUL) { 473 crmfb_setup_video(sc, sc->sc_console_depth); 474 crmfb_setup_palette(sc); 475 vcons_redraw_screen(vd->active); 476 } else { 477 crmfb_setup_video(sc, 32); 478 } 479 } 480 return 0; 481 case WSDISPLAYIO_SVIDEO: 482 { 483 int d = *(int *)data; 484 if (d == sc->sc_video_on) 485 return 0; 486 sc->sc_video_on = d; 487 if (d == WSDISPLAYIO_VIDEO_ON) { 488 crmfb_write_reg(sc, 489 CRMFB_VT_FLAGS, sc->sc_vtflags); 490 } else { 491 /* turn all SYNCs off */ 492 crmfb_write_reg(sc, CRMFB_VT_FLAGS, 493 sc->sc_vtflags | CRMFB_VT_FLAGS_VDRV_LOW | 494 CRMFB_VT_FLAGS_HDRV_LOW | 495 CRMFB_VT_FLAGS_SYNC_LOW); 496 } 497 } 498 return 0; 499 500 case WSDISPLAYIO_GVIDEO: 501 *(int *)data = sc->sc_video_on; 502 return 0; 503 504 case WSDISPLAYIO_GCURPOS: 505 { 506 struct wsdisplay_curpos *pos; 507 508 pos = (struct wsdisplay_curpos *)data; 509 pos->x = sc->sc_cur_x; 510 pos->y = sc->sc_cur_y; 511 } 512 return 0; 513 case WSDISPLAYIO_SCURPOS: 514 { 515 struct wsdisplay_curpos *pos; 516 517 pos = (struct wsdisplay_curpos *)data; 518 crmfb_set_curpos(sc, pos->x, pos->y); 519 } 520 return 0; 521 case WSDISPLAYIO_GCURMAX: 522 { 523 struct wsdisplay_curpos *pos; 524 525 pos = (struct wsdisplay_curpos *)data; 526 pos->x = 32; 527 pos->y = 32; 528 } 529 return 0; 530 case WSDISPLAYIO_GCURSOR: 531 { 532 struct wsdisplay_cursor *cu; 533 534 cu = (struct wsdisplay_cursor *)data; 535 return crmfb_gcursor(sc, cu); 536 } 537 case WSDISPLAYIO_SCURSOR: 538 { 539 struct wsdisplay_cursor *cu; 540 541 cu = (struct wsdisplay_cursor *)data; 542 return crmfb_scursor(sc, cu); 543 } 544 case WSDISPLAYIO_GET_EDID: { 545 struct wsdisplayio_edid_info *d = data; 546 547 d->data_size = 128; 548 if (d->buffer_size < 128) 549 return EAGAIN; 550 if (sc->sc_edid_data[1] == 0) 551 return ENODATA; 552 return copyout(sc->sc_edid_data, d->edid_data, 128); 553 } 554 } 555 return EPASSTHROUGH; 556 } 557 558 static paddr_t 559 crmfb_mmap(void *v, void *vs, off_t offset, int prot) 560 { 561 struct vcons_data *vd; 562 struct crmfb_softc *sc; 563 paddr_t pa; 564 565 vd = (struct vcons_data *)v; 566 sc = (struct crmfb_softc *)vd->cookie; 567 568 /* we probably shouldn't let anyone mmap the framebuffer */ 569 #if 1 570 if (offset >= 0 && offset < (0x100000 * sc->sc_tiles_x)) { 571 pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 572 sc->sc_dma.nsegs, offset, prot, 573 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE); 574 return pa; 575 } 576 #endif 577 /* 578 * here would the TLBs be but we don't want to show them to userland 579 * so we return the page containing the status register 580 */ 581 if ((offset >= 0x15000000) && (offset < 0x15002000)) 582 return bus_space_mmap(sc->sc_iot, 0x15004000, 0, prot, 0); 583 /* now the actual engine registers */ 584 if ((offset >= 0x15002000) && (offset < 0x15005000)) 585 return bus_space_mmap(sc->sc_iot, offset, 0, prot, 0); 586 /* and now the linear area */ 587 if ((offset >= 0x15010000) && (offset < 0x15030000)) 588 return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 589 sc->sc_dma.nsegs, 590 offset + (0x100000 * sc->sc_tiles_x) - 0x15010000, prot, 591 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE); 592 return -1; 593 } 594 595 static void 596 crmfb_init_screen(void *c, struct vcons_screen *scr, int existing, 597 long *defattr) 598 { 599 struct crmfb_softc *sc; 600 struct rasops_info *ri; 601 602 sc = (struct crmfb_softc *)c; 603 ri = &scr->scr_ri; 604 605 ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_ENABLE_ALPHA; 606 ri->ri_depth = sc->sc_console_depth; 607 ri->ri_width = sc->sc_width; 608 ri->ri_height = sc->sc_height; 609 ri->ri_stride = ri->ri_width * (ri->ri_depth / 8); 610 611 switch (ri->ri_depth) { 612 case 8: 613 ri->ri_flg |= RI_8BIT_IS_RGB; 614 break; 615 case 16: 616 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5; 617 ri->ri_rpos = 11; 618 ri->ri_gpos = 6; 619 ri->ri_bpos = 1; 620 break; 621 case 32: 622 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8; 623 ri->ri_rpos = 8; 624 ri->ri_gpos = 16; 625 ri->ri_bpos = 24; 626 break; 627 } 628 629 ri->ri_bits = KERNADDR(sc->sc_dma); 630 631 if (existing) 632 ri->ri_flg |= RI_CLEAR; 633 634 rasops_init(ri, 0, 0); 635 ri->ri_caps = WSSCREEN_WSCOLORS; 636 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 637 ri->ri_width / ri->ri_font->fontwidth); 638 ri->ri_hw = scr; 639 640 ri->ri_ops.cursor = crmfb_cursor; 641 ri->ri_ops.copyrows = crmfb_copyrows; 642 ri->ri_ops.eraserows = crmfb_eraserows; 643 ri->ri_ops.copycols = crmfb_copycols; 644 ri->ri_ops.erasecols = crmfb_erasecols; 645 if (FONT_IS_ALPHA(ri->ri_font)) { 646 ri->ri_ops.putchar = crmfb_putchar_aa; 647 } else { 648 ri->ri_ops.putchar = crmfb_putchar; 649 } 650 return; 651 } 652 653 static int 654 crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 655 { 656 u_int idx, cnt; 657 u_char r[256], g[256], b[256]; 658 u_char *rp, *gp, *bp; 659 int rv, i; 660 661 idx = cm->index; 662 cnt = cm->count; 663 664 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 665 return EINVAL; 666 667 rv = copyin(cm->red, &r[idx], cnt); 668 if (rv) 669 return rv; 670 rv = copyin(cm->green, &g[idx], cnt); 671 if (rv) 672 return rv; 673 rv = copyin(cm->blue, &b[idx], cnt); 674 if (rv) 675 return rv; 676 677 memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt); 678 memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt); 679 memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt); 680 681 rp = &sc->sc_cmap_red[idx]; 682 gp = &sc->sc_cmap_green[idx]; 683 bp = &sc->sc_cmap_blue[idx]; 684 685 for (i = 0; i < cnt; i++) { 686 crmfb_set_palette(sc, idx, *rp, *gp, *bp); 687 idx++; 688 rp++, gp++, bp++; 689 } 690 691 return 0; 692 } 693 694 static int 695 crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 696 { 697 u_int idx, cnt; 698 int rv; 699 700 idx = cm->index; 701 cnt = cm->count; 702 703 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 704 return EINVAL; 705 706 rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt); 707 if (rv) 708 return rv; 709 rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt); 710 if (rv) 711 return rv; 712 rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt); 713 if (rv) 714 return rv; 715 716 return 0; 717 } 718 719 static void 720 crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g, 721 uint8_t b) 722 { 723 uint32_t val; 724 725 if (reg > 255 || sc->sc_depth != 8) 726 return; 727 728 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63) 729 DELAY(10); 730 731 val = (r << 8) | (g << 16) | (b << 24); 732 crmfb_write_reg(sc, CRMFB_CMAP + (reg * 4), val); 733 734 return; 735 } 736 737 static int 738 crmfb_set_curpos(struct crmfb_softc *sc, int x, int y) 739 { 740 uint32_t val; 741 742 sc->sc_cur_x = x; 743 sc->sc_cur_y = y; 744 745 val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16); 746 crmfb_write_reg(sc, CRMFB_CURSOR_POS, val); 747 748 return 0; 749 } 750 751 static int 752 crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 753 { 754 /* do nothing for now */ 755 return 0; 756 } 757 758 static int 759 crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 760 { 761 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 762 763 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, cur->enable ? 1 : 0); 764 } 765 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 766 767 sc->sc_hot_x = cur->hot.x; 768 sc->sc_hot_y = cur->hot.y; 769 } 770 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 771 772 crmfb_set_curpos(sc, cur->pos.x, cur->pos.y); 773 } 774 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 775 int i; 776 uint32_t val; 777 778 for (i = 0; i < cur->cmap.count; i++) { 779 val = (cur->cmap.red[i] << 24) | 780 (cur->cmap.green[i] << 16) | 781 (cur->cmap.blue[i] << 8); 782 crmfb_write_reg(sc, CRMFB_CURSOR_CMAP0 + 783 ((i + cur->cmap.index) << 2), val); 784 } 785 } 786 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 787 788 int i, j, cnt = 0; 789 uint32_t latch = 0, omask; 790 uint8_t imask; 791 for (i = 0; i < 64; i++) { 792 omask = 0x80000000; 793 imask = 0x01; 794 cur->image[cnt] &= cur->mask[cnt]; 795 for (j = 0; j < 8; j++) { 796 if (cur->image[cnt] & imask) 797 latch |= omask; 798 omask >>= 1; 799 if (cur->mask[cnt] & imask) 800 latch |= omask; 801 omask >>= 1; 802 imask <<= 1; 803 } 804 cnt++; 805 imask = 0x01; 806 cur->image[cnt] &= cur->mask[cnt]; 807 for (j = 0; j < 8; j++) { 808 if (cur->image[cnt] & imask) 809 latch |= omask; 810 omask >>= 1; 811 if (cur->mask[cnt] & imask) 812 latch |= omask; 813 omask >>= 1; 814 imask <<= 1; 815 } 816 cnt++; 817 crmfb_write_reg(sc, CRMFB_CURSOR_BITMAP + (i << 2), 818 latch); 819 latch = 0; 820 } 821 } 822 return 0; 823 } 824 825 static inline void 826 crmfb_write_reg(struct crmfb_softc *sc, int offset, uint32_t val) 827 { 828 829 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val); 830 wbflush(); 831 } 832 833 static inline uint32_t 834 crmfb_read_reg(struct crmfb_softc *sc, int offset) 835 { 836 837 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset); 838 } 839 840 static inline void 841 crmfb_wait_idle(struct crmfb_softc *sc) 842 { 843 int i = 0; 844 845 do { 846 i++; 847 } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) & 848 CRIME_DE_IDLE) == 0) && (i < 100000000)); 849 if (i >= 100000000) 850 aprint_error("crmfb_wait_idle() timed out\n"); 851 sc->sc_needs_sync = 0; 852 } 853 854 /* writes to CRIME_DE_MODE_* only take effect when the engine is idle */ 855 856 static inline void 857 crmfb_src_mode(struct crmfb_softc *sc, uint32_t mode) 858 { 859 if (mode == sc->sc_src_mode) 860 return; 861 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, mode); 862 sc->sc_needs_sync = 1; 863 sc->sc_src_mode = mode; 864 } 865 866 static inline void 867 crmfb_dst_mode(struct crmfb_softc *sc, uint32_t mode) 868 { 869 if (mode == sc->sc_dst_mode) 870 return; 871 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST, mode); 872 sc->sc_needs_sync = 1; 873 sc->sc_dst_mode = mode; 874 } 875 876 static inline void 877 crmfb_make_room(struct crmfb_softc *sc, int num) 878 { 879 int i = 0, slots; 880 uint32_t status; 881 882 if (sc->sc_needs_sync != 0) { 883 crmfb_wait_idle(sc); 884 return; 885 } 886 887 do { 888 i++; 889 status = bus_space_read_4(sc->sc_iot, sc->sc_reh, 890 CRIME_DE_STATUS); 891 slots = 60 - CRIME_PIPE_LEVEL(status); 892 } while (slots <= num); 893 } 894 895 static int 896 crmfb_wait_dma_idle(struct crmfb_softc *sc) 897 { 898 int bail = 100000, idle; 899 900 do { 901 idle = ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 902 CRMFB_OVR_CONTROL) & 1) == 0) && 903 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 904 CRMFB_FRM_CONTROL) & 1) == 0) && 905 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 906 CRMFB_DID_CONTROL) & 1) == 0); 907 if (!idle) 908 delay(10); 909 bail--; 910 } while ((!idle) && (bail > 0)); 911 return idle; 912 } 913 914 static int 915 crmfb_setup_video(struct crmfb_softc *sc, int depth) 916 { 917 uint64_t reg; 918 uint32_t d, h, page; 919 int i, bail, tile_width, tlbptr, lptr, j, tx, shift, overhang; 920 const char *wantsync; 921 uint16_t v; 922 923 /* disable DMA */ 924 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL); 925 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT); 926 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d); 927 DELAY(50000); 928 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 929 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 930 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 931 DELAY(50000); 932 crmfb_write_reg(sc, CRMFB_DID_CONTROL, d); 933 DELAY(50000); 934 935 if (!crmfb_wait_dma_idle(sc)) 936 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n"); 937 938 /* ensure that CRM starts drawing at the top left of the screen 939 * when we re-enable DMA later 940 */ 941 d = (1 << CRMFB_VT_XY_FREEZE_SHIFT); 942 crmfb_write_reg(sc, CRMFB_VT_XY, d); 943 delay(1000); 944 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 945 d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 946 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 947 948 /* wait for dotclock to turn off */ 949 bail = 10000; 950 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK) & 951 (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT)) && (bail > 0)) { 952 delay(10); 953 bail--; 954 } 955 956 /* reset FIFO */ 957 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 958 d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 959 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 960 d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 961 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 962 963 /* setup colour mode */ 964 switch (depth) { 965 case 8: 966 h = CRMFB_MODE_TYP_RG3B2; 967 tile_width = 512; 968 break; 969 case 16: 970 h = CRMFB_MODE_TYP_ARGB5; 971 tile_width = 256; 972 break; 973 case 32: 974 h = CRMFB_MODE_TYP_RGB8; 975 tile_width = 128; 976 break; 977 default: 978 panic("Unsupported depth"); 979 } 980 d = h << CRMFB_MODE_TYP_SHIFT; 981 d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT; 982 for (i = 0; i < (32 * 4); i += 4) 983 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d); 984 wbflush(); 985 986 /* setup tile pointer, but don't turn on DMA yet! */ 987 h = DMAADDR(sc->sc_dmai); 988 d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT; 989 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 990 991 /* init framebuffer width and pixel size */ 992 /*d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT);*/ 993 994 d = ((int)(sc->sc_width / tile_width)) << 995 CRMFB_FRM_TILESIZE_WIDTH_SHIFT; 996 overhang = sc->sc_width % tile_width; 997 if (overhang != 0) { 998 uint32_t val; 999 DPRINTF("tile width: %d\n", tile_width); 1000 DPRINTF("overhang: %d\n", overhang); 1001 val = (overhang * (depth >> 3)) >> 5; 1002 DPRINTF("reg: %08x\n", val); 1003 d |= (val & 0x1f); 1004 DPRINTF("d: %08x\n", d); 1005 } 1006 1007 switch (depth) { 1008 case 8: 1009 h = CRMFB_FRM_TILESIZE_DEPTH_8; 1010 break; 1011 case 16: 1012 h = CRMFB_FRM_TILESIZE_DEPTH_16; 1013 break; 1014 case 32: 1015 h = CRMFB_FRM_TILESIZE_DEPTH_32; 1016 break; 1017 default: 1018 panic("Unsupported depth"); 1019 } 1020 d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT); 1021 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 1022 1023 /*h = sc->sc_width * sc->sc_height / (512 / (depth >> 3));*/ 1024 h = sc->sc_height; 1025 d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT; 1026 crmfb_write_reg(sc, CRMFB_FRM_PIXSIZE, d); 1027 1028 /* turn off firmware overlay and hardware cursor */ 1029 crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0); 1030 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0); 1031 1032 /* turn on DMA for the framebuffer */ 1033 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 1034 d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 1035 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 1036 1037 /* enable drawing again */ 1038 crmfb_write_reg(sc, CRMFB_VT_XY, 0); 1039 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 1040 d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 1041 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 1042 1043 /* turn off sync-on-green */ 1044 1045 wantsync = arcbios_GetEnvironmentVariable("SyncOnGreen"); 1046 if ( (wantsync != NULL) && (wantsync[0] == 'n') ) { 1047 sc->sc_vtflags |= CRMFB_VT_FLAGS_SYNC_LOW; 1048 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d); 1049 } 1050 1051 sc->sc_depth = depth; 1052 1053 /* finally set up the drawing engine's TLB A */ 1054 v = (DMAADDR(sc->sc_dma) >> 16) & 0xffff; 1055 tlbptr = 0; 1056 tx = ((sc->sc_width + (tile_width - 1)) & ~(tile_width - 1)) / 1057 tile_width; 1058 1059 DPRINTF("tx: %d\n", tx); 1060 1061 for (i = 0; i < 16; i++) { 1062 reg = 0; 1063 shift = 64; 1064 lptr = 0; 1065 for (j = 0; j < tx; j++) { 1066 shift -= 16; 1067 reg |= (((uint64_t)(v | 0x8000)) << shift); 1068 if (shift == 0) { 1069 shift = 64; 1070 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1071 CRIME_RE_TLB_A + tlbptr + lptr, 1072 reg); 1073 DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg); 1074 reg = 0; 1075 lptr += 8; 1076 } 1077 v++; 1078 } 1079 if (shift != 64) { 1080 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1081 CRIME_RE_TLB_A + tlbptr + lptr, reg); 1082 DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg); 1083 } 1084 tlbptr += 32; 1085 } 1086 1087 /* now put the last 128kB into the 1st linear TLB */ 1088 page = (sc->sc_linear >> 12) | 0x80000000; 1089 tlbptr = 0; 1090 for (i = 0; i < 16; i++) { 1091 reg = ((uint64_t)page << 32) | (page + 1); 1092 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1093 CRIME_RE_LINEAR_A + tlbptr, reg); 1094 page += 2; 1095 tlbptr += 8; 1096 } 1097 wbflush(); 1098 1099 /* do some very basic engine setup */ 1100 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_CLIPMODE, 0); 1101 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_SRC, 0); 1102 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_DST, 0); 1103 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PLANEMASK, 1104 0xffffffff); 1105 1106 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x20, 0); 1107 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x28, 0); 1108 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x30, 0); 1109 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x38, 0); 1110 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x40, 0); 1111 1112 switch (depth) { 1113 case 8: 1114 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 | 1115 DE_MODE_TYPE_CI | DE_MODE_PIXDEPTH_8; 1116 sc->sc_mte_mode = MTE_MODE_DST_ECC | 1117 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1118 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1119 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT); 1120 sc->sc_mte_x_shift = 0; 1121 break; 1122 case 16: 1123 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_16 | 1124 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_16; 1125 sc->sc_mte_mode = MTE_MODE_DST_ECC | 1126 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1127 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1128 (MTE_DEPTH_16 << MTE_DEPTH_SHIFT); 1129 sc->sc_mte_x_shift = 1; 1130 break; 1131 case 32: 1132 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_32 | 1133 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_32; 1134 break; 1135 sc->sc_mte_mode = MTE_MODE_DST_ECC | 1136 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1137 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1138 (MTE_DEPTH_32 << MTE_DEPTH_SHIFT); 1139 sc->sc_mte_x_shift = 2; 1140 default: 1141 panic("%s: unsuported colour depth %d\n", __func__, 1142 depth); 1143 } 1144 sc->sc_needs_sync = 0; 1145 sc->sc_src_mode = 0xffffffff; 1146 sc->sc_dst_mode = 0xffffffff; 1147 1148 crmfb_src_mode(sc, sc->sc_de_mode); 1149 crmfb_dst_mode(sc, sc->sc_de_mode); 1150 1151 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_X, 1); 1152 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_Y, 1); 1153 1154 /* initialize memory transfer engine */ 1155 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1156 sc->sc_mte_mode | MTE_MODE_COPY); 1157 sc->sc_mte_direction = 1; 1158 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, 1); 1159 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, 1); 1160 1161 return 0; 1162 } 1163 1164 static void 1165 crmfb_set_mte_direction(struct crmfb_softc *sc, int dir) 1166 { 1167 if (dir == sc->sc_mte_direction) 1168 return; 1169 1170 crmfb_make_room(sc, 2); 1171 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, dir); 1172 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, dir); 1173 sc->sc_mte_direction = dir; 1174 } 1175 1176 static void 1177 crmfb_setup_palette(struct crmfb_softc *sc) 1178 { 1179 int i, j, x; 1180 uint32_t col; 1181 struct rasops_info *ri = &crmfb_console_screen.scr_ri; 1182 1183 for (i = 0; i < 256; i++) { 1184 crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2], 1185 rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]); 1186 sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2]; 1187 sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1]; 1188 sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0]; 1189 } 1190 1191 if (FONT_IS_ALPHA(ri->ri_font)) { 1192 sc->sc_de_mode = 1193 (sc->sc_de_mode & ~DE_MODE_TYPE_MASK) | DE_MODE_TYPE_RGB; 1194 } 1195 1196 /* draw 16 character cells in 32bit RGBA for alpha blending */ 1197 crmfb_make_room(sc, 3); 1198 crmfb_dst_mode(sc, 1199 DE_MODE_TLB_A | 1200 DE_MODE_BUFDEPTH_32 | 1201 DE_MODE_TYPE_RGBA | 1202 DE_MODE_PIXDEPTH_32); 1203 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1204 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK); 1205 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1206 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1207 j = 0; 1208 x = 0; 1209 for (i = 0; i < 16; i++) { 1210 crmfb_make_room(sc, 2); 1211 col = (rasops_cmap[j] << 24) | 1212 (rasops_cmap[j + 1] << 16) | 1213 (rasops_cmap[j + 2] << 8); 1214 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, col); 1215 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1216 (x << 16) | ((sc->sc_height - 500) & 0xffff)); 1217 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1218 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1219 ((x + ri->ri_font->fontwidth - 1) << 16) | 1220 ((sc->sc_height + ri->ri_font->fontheight - 1) & 0xffff)); 1221 j += 3; 1222 x += ri->ri_font->fontwidth; 1223 } 1224 crmfb_dst_mode(sc, sc->sc_de_mode); 1225 } 1226 1227 static void 1228 crmfb_fill_rect(struct crmfb_softc *sc, int x, int y, int width, int height, 1229 uint32_t colour) 1230 { 1231 int rxa, rxe; 1232 1233 rxa = x << sc->sc_mte_x_shift; 1234 rxe = ((x + width) << sc->sc_mte_x_shift) - 1; 1235 crmfb_set_mte_direction(sc, 1); 1236 crmfb_make_room(sc, 4); 1237 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1238 sc->sc_mte_mode | 0); 1239 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, colour); 1240 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST0, 1241 (rxa << 16) | (y & 0xffff)); 1242 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1243 CRIME_MTE_DST1 | CRIME_DE_START, 1244 (rxe << 16) | ((y + height - 1) & 0xffff)); 1245 } 1246 1247 static void 1248 crmfb_bitblt(struct crmfb_softc *sc, int xs, int ys, int xd, int yd, 1249 int wi, int he, uint32_t rop) 1250 { 1251 uint32_t prim = DE_PRIM_RECTANGLE; 1252 int rxa, rya, rxe, rye, rxs, rys; 1253 crmfb_make_room(sc, 2); 1254 crmfb_src_mode(sc, sc->sc_de_mode); 1255 crmfb_make_room(sc, 6); 1256 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1257 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP | 1258 DE_DRAWMODE_XFER_EN); 1259 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, rop); 1260 if (xs < xd) { 1261 prim |= DE_PRIM_RL; 1262 rxe = xd; 1263 rxa = xd + wi - 1; 1264 rxs = xs + wi - 1; 1265 } else { 1266 prim |= DE_PRIM_LR; 1267 rxe = xd + wi - 1; 1268 rxa = xd; 1269 rxs = xs; 1270 } 1271 if (ys < yd) { 1272 prim |= DE_PRIM_BT; 1273 rye = yd; 1274 rya = yd + he - 1; 1275 rys = ys + he - 1; 1276 } else { 1277 prim |= DE_PRIM_TB; 1278 rye = yd + he - 1; 1279 rya = yd; 1280 rys = ys; 1281 } 1282 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, prim); 1283 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 1284 (rxs << 16) | (rys & 0xffff)); 1285 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1286 (rxa << 16) | (rya & 0xffff)); 1287 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1288 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1289 (rxe << 16) | (rye & 0xffff)); 1290 } 1291 1292 static void 1293 crmfb_scroll(struct crmfb_softc *sc, int xs, int ys, int xd, int yd, 1294 int wi, int he) 1295 { 1296 int rxa, rya, rxe, rye, rxd, ryd, rxde, ryde; 1297 1298 rxa = xs << sc->sc_mte_x_shift; 1299 rxd = xd << sc->sc_mte_x_shift; 1300 rxe = ((xs + wi) << sc->sc_mte_x_shift) - 1; 1301 rxde = ((xd + wi) << sc->sc_mte_x_shift) - 1; 1302 1303 crmfb_make_room(sc, 1); 1304 1305 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1306 sc->sc_mte_mode | MTE_MODE_COPY); 1307 1308 if (ys < yd) { 1309 /* bottom to top */ 1310 rye = ys; 1311 rya = ys + he - 1; 1312 ryd = yd + he - 1; 1313 ryde = yd; 1314 crmfb_set_mte_direction(sc, -1); 1315 } else { 1316 /* top to bottom */ 1317 rye = ys + he - 1; 1318 rya = ys; 1319 ryd = yd; 1320 ryde = yd + he - 1; 1321 crmfb_set_mte_direction(sc, 1); 1322 } 1323 crmfb_make_room(sc, 4); 1324 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0, 1325 (rxa << 16) | rya); 1326 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1, 1327 (rxe << 16) | rye); 1328 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1329 CRIME_MTE_DST0, 1330 (rxd << 16) | ryd); 1331 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST1 | 1332 CRIME_DE_START, 1333 (rxde << 16) | ryde); 1334 } 1335 1336 static void 1337 crmfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1338 { 1339 struct rasops_info *ri = cookie; 1340 struct vcons_screen *scr = ri->ri_hw; 1341 int32_t xs, xd, y, width, height; 1342 1343 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1344 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1345 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1346 width = ri->ri_font->fontwidth * ncols; 1347 height = ri->ri_font->fontheight; 1348 crmfb_bitblt(scr->scr_cookie, xs, y, xd, y, width, height, 3); 1349 } 1350 1351 static void 1352 crmfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1353 { 1354 struct rasops_info *ri = cookie; 1355 struct vcons_screen *scr = ri->ri_hw; 1356 int32_t x, y, width, height, bg; 1357 1358 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1359 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1360 width = ri->ri_font->fontwidth * ncols; 1361 height = ri->ri_font->fontheight; 1362 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1363 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg); 1364 } 1365 1366 static void 1367 crmfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1368 { 1369 struct rasops_info *ri = cookie; 1370 struct vcons_screen *scr = ri->ri_hw; 1371 int32_t x, ys, yd, width, height; 1372 1373 x = ri->ri_xorigin; 1374 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1375 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1376 width = ri->ri_emuwidth; 1377 height = ri->ri_font->fontheight * nrows; 1378 1379 crmfb_scroll(scr->scr_cookie, x, ys, x, yd, width, height); 1380 } 1381 1382 static void 1383 crmfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1384 { 1385 struct rasops_info *ri = cookie; 1386 struct vcons_screen *scr = ri->ri_hw; 1387 int32_t x, y, width, height, bg; 1388 1389 if ((row == 0) && (nrows == ri->ri_rows)) { 1390 x = y = 0; 1391 width = ri->ri_width; 1392 height = ri->ri_height; 1393 } else { 1394 x = ri->ri_xorigin; 1395 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1396 width = ri->ri_emuwidth; 1397 height = ri->ri_font->fontheight * nrows; 1398 } 1399 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1400 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg); 1401 } 1402 1403 static void 1404 crmfb_cursor(void *cookie, int on, int row, int col) 1405 { 1406 struct rasops_info *ri = cookie; 1407 struct vcons_screen *scr = ri->ri_hw; 1408 struct crmfb_softc *sc = scr->scr_cookie; 1409 int x, y, wi,he; 1410 1411 wi = ri->ri_font->fontwidth; 1412 he = ri->ri_font->fontheight; 1413 1414 if (ri->ri_flg & RI_CURSOR) { 1415 x = ri->ri_ccol * wi + ri->ri_xorigin; 1416 y = ri->ri_crow * he + ri->ri_yorigin; 1417 crmfb_bitblt(sc, x, y, x, y, wi, he, 12); 1418 ri->ri_flg &= ~RI_CURSOR; 1419 } 1420 1421 ri->ri_crow = row; 1422 ri->ri_ccol = col; 1423 1424 if (on) 1425 { 1426 x = ri->ri_ccol * wi + ri->ri_xorigin; 1427 y = ri->ri_crow * he + ri->ri_yorigin; 1428 crmfb_bitblt(sc, x, y, x, y, wi, he, 12); 1429 ri->ri_flg |= RI_CURSOR; 1430 } 1431 } 1432 1433 static void 1434 crmfb_putchar(void *cookie, int row, int col, u_int c, long attr) 1435 { 1436 struct rasops_info *ri = cookie; 1437 struct vcons_screen *scr = ri->ri_hw; 1438 struct crmfb_softc *sc = scr->scr_cookie; 1439 struct wsdisplay_font *font = PICK_FONT(ri, c); 1440 uint32_t bg, fg; 1441 int x, y, wi, he, i, uc; 1442 uint8_t *fd8; 1443 uint16_t *fd16; 1444 void *fd; 1445 1446 wi = font->fontwidth; 1447 he = font->fontheight; 1448 1449 x = ri->ri_xorigin + col * wi; 1450 y = ri->ri_yorigin + row * he; 1451 1452 bg = ri->ri_devcmap[(attr >> 16) & 0xff]; 1453 fg = ri->ri_devcmap[(attr >> 24) & 0xff]; 1454 uc = c - font->firstchar; 1455 fd = (uint8_t *)font->data + uc * ri->ri_fontscale; 1456 if (c == 0x20) { 1457 crmfb_fill_rect(sc, x, y, wi, he, bg); 1458 } else { 1459 crmfb_make_room(sc, 6); 1460 /* setup */ 1461 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1462 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | 1463 DE_DRAWMODE_ROP | 1464 DE_DRAWMODE_OPAQUE_STIP | DE_DRAWMODE_POLY_STIP); 1465 wbflush(); 1466 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, 3); 1467 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, fg); 1468 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_BG, bg); 1469 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1470 DE_PRIM_RECTANGLE | DE_PRIM_LR | DE_PRIM_TB); 1471 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STIPPLE_MODE, 1472 0x001f0000); 1473 /* now let's feed the engine */ 1474 crmfb_make_room(sc, 30); 1475 if (font->stride == 1) { 1476 /* shovel in 8 bit quantities */ 1477 fd8 = fd; 1478 for (i = 0; i < he; i++) { 1479 if (i & 8) 1480 crmfb_make_room(sc, 30); 1481 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1482 CRIME_DE_STIPPLE_PAT, *fd8 << 24); 1483 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1484 CRIME_DE_X_VERTEX_0, (x << 16) | y); 1485 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1486 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1487 ((x + wi) << 16) | y); 1488 y++; 1489 fd8++; 1490 } 1491 } else if (font->stride == 2) { 1492 /* shovel in 16 bit quantities */ 1493 fd16 = fd; 1494 for (i = 0; i < he; i++) { 1495 if (i & 8) 1496 crmfb_make_room(sc, 30); 1497 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1498 CRIME_DE_STIPPLE_PAT, *fd16 << 16); 1499 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1500 CRIME_DE_X_VERTEX_0, (x << 16) | y); 1501 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1502 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1503 ((x + wi) << 16) | y); 1504 y++; 1505 fd16++; 1506 } 1507 } 1508 } 1509 } 1510 1511 static void 1512 crmfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1513 { 1514 struct rasops_info *ri = cookie; 1515 struct vcons_screen *scr = ri->ri_hw; 1516 struct crmfb_softc *sc = scr->scr_cookie; 1517 struct wsdisplay_font *font = PICK_FONT(ri, c); 1518 uint32_t bg, fg; 1519 int x, y, wi, he, uc, xx; 1520 void *fd; 1521 1522 wi = font->fontwidth; 1523 he = font->fontheight; 1524 1525 x = ri->ri_xorigin + col * wi; 1526 y = ri->ri_yorigin + row * he; 1527 1528 bg = ri->ri_devcmap[(attr >> 16) & 0xff]; 1529 fg = (attr >> 24); 1530 uc = c - font->firstchar; 1531 fd = (uint8_t *)font->data + uc * ri->ri_fontscale; 1532 1533 /* fill the cell with the background colour */ 1534 crmfb_fill_rect(sc, x, y, wi, he, bg); 1535 1536 /* if all we draw is a space we're done */ 1537 if (c == 0x20) 1538 return; 1539 1540 /* copy the glyph into the linear buffer */ 1541 memcpy(sc->sc_lptr, fd, ri->ri_fontscale); 1542 wbflush(); 1543 1544 /* now blit it on top of the requested fg colour cell */ 1545 xx = fg * wi; 1546 crmfb_make_room(sc, 2); 1547 crmfb_src_mode(sc, 1548 DE_MODE_LIN_A | 1549 DE_MODE_BUFDEPTH_8 | 1550 DE_MODE_TYPE_CI | 1551 DE_MODE_PIXDEPTH_8); 1552 crmfb_dst_mode(sc, 1553 DE_MODE_TLB_A | 1554 DE_MODE_BUFDEPTH_32 | 1555 DE_MODE_TYPE_CI | 1556 DE_MODE_PIXDEPTH_8); 1557 1558 crmfb_make_room(sc, 6); 1559 /* only write into the alpha channel */ 1560 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1561 DE_DRAWMODE_PLANEMASK | 0x08 | 1562 DE_DRAWMODE_XFER_EN); 1563 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1564 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1565 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1); 1566 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 0); 1567 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1568 (xx << 16) | (sc->sc_height & 0xffff)); 1569 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1570 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1571 ((xx + wi - 1) << 16) | ((sc->sc_height + he - 1) & 0xffff)); 1572 1573 /* now draw the actual character */ 1574 crmfb_make_room(sc, 2); 1575 crmfb_src_mode(sc, 1576 DE_MODE_TLB_A | 1577 DE_MODE_BUFDEPTH_32 | 1578 DE_MODE_TYPE_RGBA | 1579 DE_MODE_PIXDEPTH_32); 1580 crmfb_dst_mode(sc, sc->sc_de_mode); 1581 1582 crmfb_make_room(sc, 6); 1583 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1584 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | 1585 DE_DRAWMODE_ALPHA_BLEND | 1586 DE_DRAWMODE_XFER_EN); 1587 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ALPHA_FUNC, 1588 DE_ALPHA_ADD | 1589 (DE_ALPHA_OP_SRC_ALPHA << DE_ALPHA_OP_SRC_SHIFT) | 1590 (DE_ALPHA_OP_1_MINUS_SRC_ALPHA << DE_ALPHA_OP_DST_SHIFT)); 1591 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1592 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1593 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 1594 (xx << 16) | (sc->sc_height & 0xffff)); 1595 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1596 (x << 16) | (y & 0xffff)); 1597 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1598 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1599 ((x + wi - 1) << 16) | ((y + he - 1) & 0xffff)); 1600 } 1601 1602 static void 1603 crmfb_setup_ddc(struct crmfb_softc *sc) 1604 { 1605 int i; 1606 1607 memset(sc->sc_edid_data, 0, 128); 1608 sc->sc_i2c.ic_cookie = sc; 1609 sc->sc_i2c.ic_acquire_bus = crmfb_i2c_acquire_bus; 1610 sc->sc_i2c.ic_release_bus = crmfb_i2c_release_bus; 1611 sc->sc_i2c.ic_send_start = crmfb_i2c_send_start; 1612 sc->sc_i2c.ic_send_stop = crmfb_i2c_send_stop; 1613 sc->sc_i2c.ic_initiate_xfer = crmfb_i2c_initiate_xfer; 1614 sc->sc_i2c.ic_read_byte = crmfb_i2c_read_byte; 1615 sc->sc_i2c.ic_write_byte = crmfb_i2c_write_byte; 1616 sc->sc_i2c.ic_exec = NULL; 1617 i = 0; 1618 while (sc->sc_edid_data[1] == 0 && i++ < 10) 1619 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128); 1620 if (i > 1) 1621 aprint_debug_dev(sc->sc_dev, 1622 "had to try %d times to get EDID data\n", i); 1623 if (i < 11) { 1624 edid_parse(sc->sc_edid_data, &sc->sc_edid_info); 1625 edid_print(&sc->sc_edid_info); 1626 } 1627 } 1628 1629 /* I2C bitbanging */ 1630 static void 1631 crmfb_i2cbb_set_bits(void *cookie, uint32_t bits) 1632 { 1633 struct crmfb_softc *sc = cookie; 1634 1635 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA, bits ^ 3); 1636 } 1637 1638 static void 1639 crmfb_i2cbb_set_dir(void *cookie, uint32_t dir) 1640 { 1641 1642 /* Nothing to do */ 1643 } 1644 1645 static uint32_t 1646 crmfb_i2cbb_read(void *cookie) 1647 { 1648 struct crmfb_softc *sc = cookie; 1649 1650 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA) ^ 3; 1651 } 1652 1653 /* higher level I2C stuff */ 1654 static int 1655 crmfb_i2c_acquire_bus(void *cookie, int flags) 1656 { 1657 1658 /* private bus */ 1659 return 0; 1660 } 1661 1662 static void 1663 crmfb_i2c_release_bus(void *cookie, int flags) 1664 { 1665 1666 /* private bus */ 1667 } 1668 1669 static int 1670 crmfb_i2c_send_start(void *cookie, int flags) 1671 { 1672 1673 return i2c_bitbang_send_start(cookie, flags, &crmfb_i2cbb_ops); 1674 } 1675 1676 static int 1677 crmfb_i2c_send_stop(void *cookie, int flags) 1678 { 1679 1680 return i2c_bitbang_send_stop(cookie, flags, &crmfb_i2cbb_ops); 1681 } 1682 1683 static int 1684 crmfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 1685 { 1686 1687 return i2c_bitbang_initiate_xfer(cookie, addr, flags, 1688 &crmfb_i2cbb_ops); 1689 } 1690 1691 static int 1692 crmfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 1693 { 1694 1695 return i2c_bitbang_read_byte(cookie, valp, flags, &crmfb_i2cbb_ops); 1696 } 1697 1698 static int 1699 crmfb_i2c_write_byte(void *cookie, uint8_t val, int flags) 1700 { 1701 1702 return i2c_bitbang_write_byte(cookie, val, flags, &crmfb_i2cbb_ops); 1703 } 1704 1705 /* mode setting stuff */ 1706 static uint32_t 1707 calc_pll(int f_out) 1708 { 1709 uint32_t ret; 1710 int f_in = 20000; /* 20MHz in */ 1711 int M, N, P; 1712 int error, div, best = 9999999; 1713 int ff1, ff2; 1714 int MM = 0, NN = 0, PP = 0, ff = 0; 1715 1716 /* f_out = M * f_in / (N * (1 << P) */ 1717 1718 for (P = 0; P < 4; P++) { 1719 for (N = 64; N > 0; N--) { 1720 div = N * (1 << P); 1721 M = f_out * div / f_in; 1722 if ((M < 257) && (M > 100)) { 1723 ff1 = M * f_in / div; 1724 ff2 = (M + 1) * f_in / div; 1725 error = abs(ff1 - f_out); 1726 if (error < best) { 1727 MM = M; 1728 NN = N; 1729 PP = P; 1730 ff = ff1; 1731 best = error; 1732 } 1733 error = abs(ff2 - f_out); 1734 if ((error < best) && ( M < 256)){ 1735 MM = M + 1; 1736 NN = N; 1737 PP = P; 1738 ff = ff2; 1739 best = error; 1740 } 1741 } 1742 } 1743 } 1744 DPRINTF("%d: M %d N %d P %d -> %d\n", f_out, MM, NN, PP, ff); 1745 /* now shove the parameters into the register's format */ 1746 ret = (MM - 1) | ((NN - 1) << 8) | (P << 14); 1747 return ret; 1748 } 1749 1750 static int 1751 crmfb_set_mode(struct crmfb_softc *sc, const struct videomode *mode) 1752 { 1753 uint32_t d, dc; 1754 int tmp, diff; 1755 1756 switch (mode->hdisplay % 32) { 1757 case 0: 1758 sc->sc_console_depth = 8; 1759 break; 1760 case 16: 1761 sc->sc_console_depth = 16; 1762 break; 1763 case 8: 1764 case 24: 1765 sc->sc_console_depth = 32; 1766 break; 1767 default: 1768 aprint_error_dev(sc->sc_dev, 1769 "hdisplay (%d) is not a multiple of 32\n", 1770 mode->hdisplay); 1771 return FALSE; 1772 } 1773 if (mode->dot_clock > 150000) { 1774 aprint_error_dev(sc->sc_dev, 1775 "requested dot clock is too high ( %d MHz )\n", 1776 mode->dot_clock / 1000); 1777 return FALSE; 1778 } 1779 1780 /* disable DMA */ 1781 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL); 1782 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT); 1783 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d); 1784 DELAY(50000); 1785 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 1786 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 1787 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 1788 DELAY(50000); 1789 crmfb_write_reg(sc, CRMFB_DID_CONTROL, d); 1790 DELAY(50000); 1791 1792 if (!crmfb_wait_dma_idle(sc)) 1793 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n"); 1794 1795 /* ok, now we're good to go */ 1796 dc = calc_pll(mode->dot_clock); 1797 1798 crmfb_write_reg(sc, CRMFB_VT_XY, 1 << CRMFB_VT_XY_FREEZE_SHIFT); 1799 delay(1000); 1800 1801 /* set the dot clock pll but don't start it yet */ 1802 crmfb_write_reg(sc, CRMFB_DOTCLOCK, dc); 1803 delay(10000); 1804 1805 /* pixel counter */ 1806 d = mode->htotal | (mode->vtotal << 12); 1807 crmfb_write_reg(sc, CRMFB_VT_XYMAX, d); 1808 1809 /* video timings */ 1810 d = mode->vsync_end | (mode->vsync_start << 12); 1811 crmfb_write_reg(sc, CRMFB_VT_VSYNC, d); 1812 1813 d = mode->hsync_end | (mode->hsync_start << 12); 1814 crmfb_write_reg(sc, CRMFB_VT_HSYNC, d); 1815 1816 d = mode->vtotal | (mode->vdisplay << 12); 1817 crmfb_write_reg(sc, CRMFB_VT_VBLANK, d); 1818 1819 d = (mode->htotal - 5) | ((mode->hdisplay - 5) << 12); 1820 crmfb_write_reg(sc, CRMFB_VT_HBLANK, d); 1821 1822 d = mode->vtotal | (mode->vdisplay << 12); 1823 crmfb_write_reg(sc, CRMFB_VT_VCMAP, d); 1824 d = mode->htotal | (mode->hdisplay << 12); 1825 crmfb_write_reg(sc, CRMFB_VT_HCMAP, d); 1826 1827 d = 0; 1828 if (mode->flags & VID_NHSYNC) d |= CRMFB_VT_FLAGS_HDRV_INVERT; 1829 if (mode->flags & VID_NVSYNC) d |= CRMFB_VT_FLAGS_VDRV_INVERT; 1830 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d); 1831 sc->sc_vtflags = d; 1832 1833 diff = -abs(mode->vtotal - mode->vdisplay - 1); 1834 d = ((uint32_t)diff << 12) & 0x00fff000; 1835 d |= (mode->htotal - 20); 1836 crmfb_write_reg(sc, CRMFB_VT_DID_STARTXY, d); 1837 1838 d = ((uint32_t)(diff + 1) << 12) & 0x00fff000; 1839 d |= (mode->htotal - 54); 1840 crmfb_write_reg(sc, CRMFB_VT_CRS_STARTXY, d); 1841 1842 d = ((uint32_t)diff << 12) & 0x00fff000; 1843 d |= (mode->htotal - 4); 1844 crmfb_write_reg(sc, CRMFB_VT_VC_STARTXY, d); 1845 1846 tmp = mode->htotal - 19; 1847 d = tmp << 12; 1848 d |= ((tmp + mode->hdisplay - 2) % mode->htotal); 1849 crmfb_write_reg(sc, CRMFB_VT_HPIX_EN, d); 1850 1851 d = mode->vdisplay | (mode->vtotal << 12); 1852 crmfb_write_reg(sc, CRMFB_VT_VPIX_EN, d); 1853 1854 sc->sc_width = mode->hdisplay; 1855 sc->sc_height = mode->vdisplay; 1856 1857 return TRUE; 1858 } 1859