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