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