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