1 /* $NetBSD: crmfb.c,v 1.28 2011/03/01 21:47:13 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * 2008 Michael Lorenz <macallan@netbsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * SGI-CRM (O2) Framebuffer driver 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.28 2011/03/01 21:47:13 macallan Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 42 #define _SGIMIPS_BUS_DMA_PRIVATE 43 #include <machine/autoconf.h> 44 #include <machine/bus.h> 45 #include <machine/machtype.h> 46 #include <machine/vmparam.h> 47 48 #include <dev/arcbios/arcbios.h> 49 #include <dev/arcbios/arcbiosvar.h> 50 51 #include <dev/wscons/wsdisplayvar.h> 52 #include <dev/wscons/wsconsio.h> 53 #include <dev/wsfont/wsfont.h> 54 #include <dev/rasops/rasops.h> 55 #include <dev/wscons/wsdisplay_vconsvar.h> 56 57 #include <arch/sgimips/dev/crmfbreg.h> 58 59 /*#define CRMFB_DEBUG*/ 60 61 struct wsscreen_descr crmfb_defaultscreen = { 62 "default", 63 0, 0, 64 NULL, 65 8, 16, 66 WSSCREEN_WSCOLORS, 67 NULL, 68 }; 69 70 const struct wsscreen_descr *_crmfb_scrlist[] = { 71 &crmfb_defaultscreen, 72 }; 73 74 struct wsscreen_list crmfb_screenlist = { 75 sizeof(_crmfb_scrlist) / sizeof(struct wsscreen_descr *), 76 _crmfb_scrlist 77 }; 78 79 static struct vcons_screen crmfb_console_screen; 80 81 static int crmfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 82 static paddr_t crmfb_mmap(void *, void *, off_t, int); 83 static void crmfb_init_screen(void *, struct vcons_screen *, int, long *); 84 85 struct wsdisplay_accessops crmfb_accessops = { 86 crmfb_ioctl, 87 crmfb_mmap, 88 NULL, /* alloc_screen */ 89 NULL, /* free_screen */ 90 NULL, /* show_screen */ 91 NULL, /* load_font */ 92 NULL, /* pollc */ 93 NULL, /* scroll */ 94 }; 95 96 /* Memory to allocate to SGI-CRM -- remember, this is stolen from 97 * host memory! 98 */ 99 #define CRMFB_TILESIZE (512*128) 100 101 static int crmfb_match(struct device *, struct cfdata *, void *); 102 static void crmfb_attach(struct device *, struct device *, void *); 103 int crmfb_probe(void); 104 105 #define KERNADDR(p) ((void *)((p).addr)) 106 #define DMAADDR(p) ((p).map->dm_segs[0].ds_addr) 107 108 #define CRMFB_REG_MASK(msb, lsb) \ 109 ( (((uint32_t) 1 << ((msb)-(lsb)+1)) - 1) << (lsb) ) 110 111 112 struct crmfb_dma { 113 bus_dmamap_t map; 114 void *addr; 115 bus_dma_segment_t segs[1]; 116 int nsegs; 117 size_t size; 118 }; 119 120 struct crmfb_softc { 121 struct device sc_dev; 122 struct vcons_data sc_vd; 123 124 bus_space_tag_t sc_iot; 125 bus_space_handle_t sc_ioh; 126 bus_space_handle_t sc_reh; 127 128 bus_dma_tag_t sc_dmat; 129 130 struct crmfb_dma sc_dma; 131 struct crmfb_dma sc_dmai; 132 133 int sc_width; 134 int sc_height; 135 int sc_depth; 136 int sc_tiles_x, sc_tiles_y; 137 uint32_t sc_fbsize; 138 int sc_mte_direction; 139 uint8_t *sc_scratch; 140 paddr_t sc_linear; 141 int sc_wsmode; 142 143 /* cursor stuff */ 144 int sc_cur_x; 145 int sc_cur_y; 146 int sc_hot_x; 147 int sc_hot_y; 148 149 u_char sc_cmap_red[256]; 150 u_char sc_cmap_green[256]; 151 u_char sc_cmap_blue[256]; 152 }; 153 154 static int crmfb_putcmap(struct crmfb_softc *, struct wsdisplay_cmap *); 155 static int crmfb_getcmap(struct crmfb_softc *, struct wsdisplay_cmap *); 156 static void crmfb_set_palette(struct crmfb_softc *, 157 int, uint8_t, uint8_t, uint8_t); 158 static int crmfb_set_curpos(struct crmfb_softc *, int, int); 159 static int crmfb_gcursor(struct crmfb_softc *, struct wsdisplay_cursor *); 160 static int crmfb_scursor(struct crmfb_softc *, struct wsdisplay_cursor *); 161 static inline void crmfb_write_reg(struct crmfb_softc *, int, uint32_t); 162 static inline uint32_t crmfb_read_reg(struct crmfb_softc *, int); 163 static int crmfb_wait_dma_idle(struct crmfb_softc *); 164 165 /* setup video hw in given colour depth */ 166 static int crmfb_setup_video(struct crmfb_softc *, int); 167 static void crmfb_setup_palette(struct crmfb_softc *); 168 169 #ifdef CRMFB_DEBUG 170 void crmfb_test_mte(struct crmfb_softc *); 171 #endif 172 173 static void crmfb_fill_rect(struct crmfb_softc *, int, int, int, int, uint32_t); 174 static void crmfb_bitblt(struct crmfb_softc *, int, int, int, int, int, int, 175 uint32_t); 176 static void crmfb_scroll(struct crmfb_softc *, int, int, int, int, int, int); 177 178 static void crmfb_copycols(void *, int, int, int, int); 179 static void crmfb_erasecols(void *, int, int, int, long); 180 static void crmfb_copyrows(void *, int, int, int); 181 static void crmfb_eraserows(void *, int, int, long); 182 static void crmfb_cursor(void *, int, int, int); 183 static void crmfb_putchar(void *, int, int, u_int, long); 184 185 CFATTACH_DECL(crmfb, sizeof(struct crmfb_softc), 186 crmfb_match, crmfb_attach, NULL, NULL); 187 188 static int 189 crmfb_match(struct device *parent, struct cfdata *cf, void *opaque) 190 { 191 return crmfb_probe(); 192 } 193 194 static void 195 crmfb_attach(struct device *parent, struct device *self, void *opaque) 196 { 197 struct mainbus_attach_args *ma; 198 struct crmfb_softc *sc; 199 struct rasops_info *ri; 200 struct wsemuldisplaydev_attach_args aa; 201 uint32_t d, h; 202 uint16_t *p; 203 unsigned long v; 204 long defattr; 205 const char *consdev; 206 int rv, i; 207 208 sc = (struct crmfb_softc *)self; 209 ma = (struct mainbus_attach_args *)opaque; 210 211 sc->sc_iot = SGIMIPS_BUS_SPACE_CRIME; 212 sc->sc_dmat = &sgimips_default_bus_dma_tag; 213 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL; 214 215 aprint_normal(": SGI CRIME Graphics Display Engine\n"); 216 rv = bus_space_map(sc->sc_iot, ma->ma_addr, 0 /* XXX */, 217 BUS_SPACE_MAP_LINEAR, &sc->sc_ioh); 218 if (rv) 219 panic("crmfb_attach: can't map I/O space"); 220 rv = bus_space_map(sc->sc_iot, 0x15000000, 0x6000, 0, &sc->sc_reh); 221 if (rv) 222 panic("crmfb_attach: can't map rendering engine"); 223 224 /* determine mode configured by firmware */ 225 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP); 226 sc->sc_width = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff; 227 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_VCMAP); 228 sc->sc_height = (d >> CRMFB_VT_VCMAP_ON_SHIFT) & 0xfff; 229 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 230 h = (d >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 0x3; 231 if (h == 0) 232 sc->sc_depth = 8; 233 else if (h == 1) 234 sc->sc_depth = 16; 235 else 236 sc->sc_depth = 32; 237 238 if (sc->sc_width == 0 || sc->sc_height == 0) { 239 aprint_error("%s: device unusable if not setup by firmware\n", 240 sc->sc_dev.dv_xname); 241 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0 /* XXX */); 242 return; 243 } 244 245 aprint_normal("%s: initial resolution %dx%d\n", 246 sc->sc_dev.dv_xname, sc->sc_width, sc->sc_height); 247 248 /* 249 * first determine how many tiles we need 250 * in 32bit each tile is 128x128 pixels 251 */ 252 sc->sc_tiles_x = (sc->sc_width + 127) >> 7; 253 sc->sc_tiles_y = (sc->sc_height + 127) >> 7; 254 sc->sc_fbsize = 0x10000 * sc->sc_tiles_x * sc->sc_tiles_y; 255 256 sc->sc_dmai.size = 256 * sizeof(uint16_t); 257 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmai.size, 65536, 0, 258 sc->sc_dmai.segs, 259 sizeof(sc->sc_dmai.segs) / sizeof(sc->sc_dmai.segs[0]), 260 &sc->sc_dmai.nsegs, BUS_DMA_NOWAIT); 261 if (rv) 262 panic("crmfb_attach: can't allocate DMA memory"); 263 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dmai.segs, sc->sc_dmai.nsegs, 264 sc->sc_dmai.size, &sc->sc_dmai.addr, 265 BUS_DMA_NOWAIT); 266 if (rv) 267 panic("crmfb_attach: can't map DMA memory"); 268 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dmai.size, 1, 269 sc->sc_dmai.size, 0, BUS_DMA_NOWAIT, &sc->sc_dmai.map); 270 if (rv) 271 panic("crmfb_attach: can't create DMA map"); 272 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmai.map, sc->sc_dmai.addr, 273 sc->sc_dmai.size, NULL, BUS_DMA_NOWAIT); 274 if (rv) 275 panic("crmfb_attach: can't load DMA map"); 276 277 /* allocate an extra 64Kb for a linear buffer */ 278 sc->sc_dma.size = 0x10000 * (16 * sc->sc_tiles_x + 1); 279 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0, 280 sc->sc_dma.segs, 281 sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]), 282 &sc->sc_dma.nsegs, BUS_DMA_NOWAIT); 283 if (rv) 284 panic("crmfb_attach: can't allocate DMA memory"); 285 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dma.segs, sc->sc_dma.nsegs, 286 sc->sc_dma.size, &sc->sc_dma.addr, 287 BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 288 if (rv) 289 panic("crmfb_attach: can't map DMA memory"); 290 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dma.size, 1, 291 sc->sc_dma.size, 0, BUS_DMA_NOWAIT, &sc->sc_dma.map); 292 if (rv) 293 panic("crmfb_attach: can't create DMA map"); 294 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr, 295 sc->sc_dma.size, NULL, BUS_DMA_NOWAIT); 296 if (rv) 297 panic("crmfb_attach: can't load DMA map"); 298 299 p = KERNADDR(sc->sc_dmai); 300 v = (unsigned long)DMAADDR(sc->sc_dma); 301 for (i = 0; i < (sc->sc_tiles_x * sc->sc_tiles_y); i++) { 302 p[i] = ((uint32_t)v >> 16) + i; 303 } 304 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmai.map, 0, sc->sc_dmai.size, 305 BUS_DMASYNC_PREWRITE); 306 sc->sc_scratch = (char *)KERNADDR(sc->sc_dma) + (0xf0000 * sc->sc_tiles_x); 307 sc->sc_linear = (paddr_t)DMAADDR(sc->sc_dma) + 0x100000 * sc->sc_tiles_x; 308 309 aprint_normal("%s: allocated %d byte fb @ %p (%p)\n", 310 sc->sc_dev.dv_xname, 311 sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma)); 312 313 crmfb_setup_video(sc, 8); 314 ri = &crmfb_console_screen.scr_ri; 315 memset(ri, 0, sizeof(struct rasops_info)); 316 317 vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops); 318 sc->sc_vd.init_screen = crmfb_init_screen; 319 crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 320 vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr); 321 322 crmfb_defaultscreen.ncols = ri->ri_cols; 323 crmfb_defaultscreen.nrows = ri->ri_rows; 324 crmfb_defaultscreen.textops = &ri->ri_ops; 325 crmfb_defaultscreen.capabilities = ri->ri_caps; 326 crmfb_defaultscreen.modecookie = NULL; 327 328 crmfb_setup_palette(sc); 329 crmfb_fill_rect(sc, 0, 0, sc->sc_width, sc->sc_height, 330 ri->ri_devcmap[(defattr >> 16) & 0xff]); 331 332 consdev = arcbios_GetEnvironmentVariable("ConsoleOut"); 333 if (consdev != NULL && strcmp(consdev, "video()") == 0) { 334 wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr); 335 vcons_replay_msgbuf(&crmfb_console_screen); 336 aa.console = 1; 337 } else 338 aa.console = 0; 339 aa.scrdata = &crmfb_screenlist; 340 aa.accessops = &crmfb_accessops; 341 aa.accesscookie = &sc->sc_vd; 342 343 config_found(self, &aa, wsemuldisplaydevprint); 344 345 sc->sc_cur_x = 0; 346 sc->sc_cur_y = 0; 347 sc->sc_hot_x = 0; 348 sc->sc_hot_y = 0; 349 350 #ifdef CRMFB_DEBUG 351 crmfb_test_mte(sc); 352 #endif 353 return; 354 } 355 356 int 357 crmfb_probe(void) 358 { 359 360 if (mach_type != MACH_SGI_IP32) 361 return 0; 362 363 return 1; 364 } 365 366 static int 367 crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 368 { 369 struct vcons_data *vd; 370 struct crmfb_softc *sc; 371 struct vcons_screen *ms; 372 struct wsdisplay_fbinfo *wdf; 373 int nmode; 374 375 vd = (struct vcons_data *)v; 376 sc = (struct crmfb_softc *)vd->cookie; 377 ms = (struct vcons_screen *)vd->active; 378 379 switch (cmd) { 380 case WSDISPLAYIO_GTYPE: 381 /* not really, but who cares? */ 382 /* wsfb does */ 383 *(u_int *)data = WSDISPLAY_TYPE_CRIME; 384 return 0; 385 case WSDISPLAYIO_GINFO: 386 if (vd->active != NULL) { 387 wdf = (void *)data; 388 wdf->height = sc->sc_height; 389 wdf->width = sc->sc_width; 390 wdf->depth = 32; 391 wdf->cmsize = 256; 392 return 0; 393 } else 394 return ENODEV; 395 case WSDISPLAYIO_GETCMAP: 396 if (sc->sc_depth == 8) 397 return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data); 398 else 399 return EINVAL; 400 case WSDISPLAYIO_PUTCMAP: 401 if (sc->sc_depth == 8) 402 return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data); 403 else 404 return EINVAL; 405 case WSDISPLAYIO_LINEBYTES: 406 *(u_int *)data = sc->sc_width * sc->sc_depth / 8; 407 return 0; 408 case WSDISPLAYIO_SMODE: 409 nmode = *(int *)data; 410 if (nmode != sc->sc_wsmode) { 411 sc->sc_wsmode = nmode; 412 if (nmode == WSDISPLAYIO_MODE_EMUL) { 413 crmfb_setup_video(sc, 8); 414 crmfb_setup_palette(sc); 415 vcons_redraw_screen(vd->active); 416 } else { 417 crmfb_setup_video(sc, 32); 418 } 419 } 420 return 0; 421 case WSDISPLAYIO_SVIDEO: 422 case WSDISPLAYIO_GVIDEO: 423 return ENODEV; /* not supported yet */ 424 425 case WSDISPLAYIO_GCURPOS: 426 { 427 struct wsdisplay_curpos *pos; 428 429 pos = (struct wsdisplay_curpos *)data; 430 pos->x = sc->sc_cur_x; 431 pos->y = sc->sc_cur_y; 432 } 433 return 0; 434 case WSDISPLAYIO_SCURPOS: 435 { 436 struct wsdisplay_curpos *pos; 437 438 pos = (struct wsdisplay_curpos *)data; 439 crmfb_set_curpos(sc, pos->x, pos->y); 440 } 441 return 0; 442 case WSDISPLAYIO_GCURMAX: 443 { 444 struct wsdisplay_curpos *pos; 445 446 pos = (struct wsdisplay_curpos *)data; 447 pos->x = 32; 448 pos->y = 32; 449 } 450 return 0; 451 case WSDISPLAYIO_GCURSOR: 452 { 453 struct wsdisplay_cursor *cu; 454 455 cu = (struct wsdisplay_cursor *)data; 456 return crmfb_gcursor(sc, cu); 457 } 458 case WSDISPLAYIO_SCURSOR: 459 { 460 struct wsdisplay_cursor *cu; 461 462 cu = (struct wsdisplay_cursor *)data; 463 return crmfb_scursor(sc, cu); 464 } 465 } 466 return EPASSTHROUGH; 467 } 468 469 static paddr_t 470 crmfb_mmap(void *v, void *vs, off_t offset, int prot) 471 { 472 struct vcons_data *vd; 473 struct crmfb_softc *sc; 474 paddr_t pa; 475 476 vd = (struct vcons_data *)v; 477 sc = (struct crmfb_softc *)vd->cookie; 478 479 /* we probably shouldn't let anyone mmap the framebuffer */ 480 #if 1 481 if (offset >= 0 && offset < (0x100000 * sc->sc_tiles_x)) { 482 pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 483 sc->sc_dma.nsegs, offset, prot, 484 BUS_DMA_WAITOK | BUS_DMA_COHERENT); 485 return pa; 486 } 487 #endif 488 /* 489 * here would the TLBs be but we don't want to show them to userland 490 * so we return the page containing the status register 491 */ 492 if ((offset >= 0x15000000) && (offset < 0x15002000)) 493 return bus_space_mmap(sc->sc_iot, 0x15004000, 0, prot, 0); 494 /* now the actual engine registers */ 495 if ((offset >= 0x15002000) && (offset < 0x15005000)) 496 return bus_space_mmap(sc->sc_iot, offset, 0, prot, 0); 497 /* and now the scratch area */ 498 if ((offset >= 0x15010000) && (offset < 0x15020000)) 499 return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 500 sc->sc_dma.nsegs, 501 offset + (0x100000 * sc->sc_tiles_x) - 0x15010000, 502 prot, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 503 return -1; 504 } 505 506 static void 507 crmfb_init_screen(void *c, struct vcons_screen *scr, int existing, 508 long *defattr) 509 { 510 struct crmfb_softc *sc; 511 struct rasops_info *ri; 512 513 sc = (struct crmfb_softc *)c; 514 ri = &scr->scr_ri; 515 516 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 517 ri->ri_depth = sc->sc_depth; 518 ri->ri_width = sc->sc_width; 519 ri->ri_height = sc->sc_height; 520 ri->ri_stride = ri->ri_width * (ri->ri_depth / 8); 521 522 switch (ri->ri_depth) { 523 case 16: 524 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5; 525 ri->ri_rpos = 10; 526 ri->ri_gpos = 5; 527 ri->ri_bpos = 0; 528 break; 529 case 32: 530 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8; 531 ri->ri_rpos = 8; 532 ri->ri_gpos = 16; 533 ri->ri_bpos = 24; 534 break; 535 } 536 537 ri->ri_bits = KERNADDR(sc->sc_dma); 538 539 if (existing) 540 ri->ri_flg |= RI_CLEAR; 541 542 rasops_init(ri, ri->ri_height / 16, ri->ri_width / 8); 543 ri->ri_caps = WSSCREEN_WSCOLORS; 544 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 545 ri->ri_width / ri->ri_font->fontwidth); 546 ri->ri_hw = scr; 547 548 ri->ri_ops.cursor = crmfb_cursor; 549 ri->ri_ops.copyrows = crmfb_copyrows; 550 ri->ri_ops.eraserows = crmfb_eraserows; 551 ri->ri_ops.copycols = crmfb_copycols; 552 ri->ri_ops.erasecols = crmfb_erasecols; 553 ri->ri_ops.putchar = crmfb_putchar; 554 555 return; 556 } 557 558 static int 559 crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 560 { 561 u_int idx, cnt; 562 u_char r[256], g[256], b[256]; 563 u_char *rp, *gp, *bp; 564 int rv, i; 565 566 idx = cm->index; 567 cnt = cm->count; 568 569 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 570 return EINVAL; 571 572 rv = copyin(cm->red, &r[idx], cnt); 573 if (rv) 574 return rv; 575 rv = copyin(cm->green, &g[idx], cnt); 576 if (rv) 577 return rv; 578 rv = copyin(cm->blue, &b[idx], cnt); 579 if (rv) 580 return rv; 581 582 memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt); 583 memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt); 584 memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt); 585 586 rp = &sc->sc_cmap_red[idx]; 587 gp = &sc->sc_cmap_green[idx]; 588 bp = &sc->sc_cmap_blue[idx]; 589 590 for (i = 0; i < cnt; i++) { 591 crmfb_set_palette(sc, idx, *rp, *gp, *bp); 592 idx++; 593 rp++, gp++, bp++; 594 } 595 596 return 0; 597 } 598 599 static int 600 crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 601 { 602 u_int idx, cnt; 603 int rv; 604 605 idx = cm->index; 606 cnt = cm->count; 607 608 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 609 return EINVAL; 610 611 rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt); 612 if (rv) 613 return rv; 614 rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt); 615 if (rv) 616 return rv; 617 rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt); 618 if (rv) 619 return rv; 620 621 return 0; 622 } 623 624 static void 625 crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g, 626 uint8_t b) 627 { 628 uint32_t val; 629 630 if (reg > 255 || sc->sc_depth != 8) 631 return; 632 633 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63) 634 DELAY(10); 635 636 val = (r << 8) | (g << 16) | (b << 24); 637 crmfb_write_reg(sc, CRMFB_CMAP + (reg * 4), val); 638 639 return; 640 } 641 642 static int 643 crmfb_set_curpos(struct crmfb_softc *sc, int x, int y) 644 { 645 uint32_t val; 646 647 sc->sc_cur_x = x; 648 sc->sc_cur_y = y; 649 650 val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16); 651 crmfb_write_reg(sc, CRMFB_CURSOR_POS, val); 652 653 return 0; 654 } 655 656 static int 657 crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 658 { 659 /* do nothing for now */ 660 return 0; 661 } 662 663 static int 664 crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 665 { 666 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 667 668 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, cur->enable ? 1 : 0); 669 } 670 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 671 672 sc->sc_hot_x = cur->hot.x; 673 sc->sc_hot_y = cur->hot.y; 674 } 675 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 676 677 crmfb_set_curpos(sc, cur->pos.x, cur->pos.y); 678 } 679 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 680 int i; 681 uint32_t val; 682 683 for (i = 0; i < cur->cmap.count; i++) { 684 val = (cur->cmap.red[i] << 24) | 685 (cur->cmap.green[i] << 16) | 686 (cur->cmap.blue[i] << 8); 687 crmfb_write_reg(sc, CRMFB_CURSOR_CMAP0 + 688 ((i + cur->cmap.index) << 2), val); 689 } 690 } 691 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 692 693 int i, j, cnt = 0; 694 uint32_t latch = 0, omask; 695 uint8_t imask; 696 for (i = 0; i < 64; i++) { 697 omask = 0x80000000; 698 imask = 0x01; 699 cur->image[cnt] &= cur->mask[cnt]; 700 for (j = 0; j < 8; j++) { 701 if (cur->image[cnt] & imask) 702 latch |= omask; 703 omask >>= 1; 704 if (cur->mask[cnt] & imask) 705 latch |= omask; 706 omask >>= 1; 707 imask <<= 1; 708 } 709 cnt++; 710 imask = 0x01; 711 cur->image[cnt] &= cur->mask[cnt]; 712 for (j = 0; j < 8; j++) { 713 if (cur->image[cnt] & imask) 714 latch |= omask; 715 omask >>= 1; 716 if (cur->mask[cnt] & imask) 717 latch |= omask; 718 omask >>= 1; 719 imask <<= 1; 720 } 721 cnt++; 722 crmfb_write_reg(sc, CRMFB_CURSOR_BITMAP + (i << 2), 723 latch); 724 latch = 0; 725 } 726 } 727 return 0; 728 } 729 730 static inline void 731 crmfb_write_reg(struct crmfb_softc *sc, int offset, uint32_t val) 732 { 733 734 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val); 735 wbflush(); 736 } 737 738 static inline uint32_t 739 crmfb_read_reg(struct crmfb_softc *sc, int offset) 740 { 741 742 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset); 743 } 744 745 static int 746 crmfb_wait_dma_idle(struct crmfb_softc *sc) 747 { 748 int bail = 100000, idle; 749 750 do { 751 idle = ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 752 CRMFB_OVR_CONTROL) & 1) == 0) && 753 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 754 CRMFB_FRM_CONTROL) & 1) == 0) && 755 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, 756 CRMFB_DID_CONTROL) & 1) == 0); 757 if (!idle) 758 delay(10); 759 bail--; 760 } while ((!idle) && (bail > 0)); 761 return idle; 762 } 763 764 static int 765 crmfb_setup_video(struct crmfb_softc *sc, int depth) 766 { 767 uint64_t reg; 768 uint32_t d, h, mode, page; 769 int i, bail, tile_width, tlbptr, lptr, j, tx, shift; 770 const char *wantsync; 771 uint16_t v; 772 773 /* disable DMA */ 774 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL); 775 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT); 776 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d); 777 DELAY(50000); 778 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 779 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 780 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 781 DELAY(50000); 782 crmfb_write_reg(sc, CRMFB_DID_CONTROL, 0); 783 DELAY(50000); 784 785 if (!crmfb_wait_dma_idle(sc)) 786 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n"); 787 788 /* ensure that CRM starts drawing at the top left of the screen 789 * when we re-enable DMA later 790 */ 791 d = (1 << CRMFB_VT_XY_FREEZE_SHIFT); 792 crmfb_write_reg(sc, CRMFB_VT_XY, d); 793 delay(1000); 794 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 795 d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 796 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 797 798 /* wait for dotclock to turn off */ 799 bail = 10000; 800 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK) & 801 (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT)) && (bail > 0)) { 802 delay(10); 803 bail--; 804 } 805 806 /* reset FIFO */ 807 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 808 d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 809 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 810 d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 811 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 812 813 /* setup colour mode */ 814 switch (depth) { 815 case 8: 816 h = CRMFB_MODE_TYP_I8; 817 tile_width = 512; 818 break; 819 case 16: 820 h = CRMFB_MODE_TYP_ARGB5; 821 tile_width = 256; 822 break; 823 case 32: 824 h = CRMFB_MODE_TYP_RGB8; 825 tile_width = 128; 826 break; 827 default: 828 panic("Unsupported depth"); 829 } 830 d = h << CRMFB_MODE_TYP_SHIFT; 831 d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT; 832 for (i = 0; i < (32 * 4); i += 4) 833 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d); 834 wbflush(); 835 836 /* setup tile pointer, but don't turn on DMA yet! */ 837 h = DMAADDR(sc->sc_dmai); 838 d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT; 839 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 840 841 /* init framebuffer width and pixel size */ 842 /*d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT);*/ 843 844 d = ((int)(sc->sc_width / tile_width)) << 845 CRMFB_FRM_TILESIZE_WIDTH_SHIFT; 846 if ((sc->sc_width & (tile_width - 1)) != 0) 847 d |= sc->sc_tiles_y; 848 849 switch (depth) { 850 case 8: 851 h = CRMFB_FRM_TILESIZE_DEPTH_8; 852 break; 853 case 16: 854 h = CRMFB_FRM_TILESIZE_DEPTH_16; 855 break; 856 case 32: 857 h = CRMFB_FRM_TILESIZE_DEPTH_32; 858 break; 859 default: 860 panic("Unsupported depth"); 861 } 862 d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT); 863 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 864 865 /*h = sc->sc_width * sc->sc_height / (512 / (depth >> 3));*/ 866 h = sc->sc_height; 867 d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT; 868 crmfb_write_reg(sc, CRMFB_FRM_PIXSIZE, d); 869 870 /* turn off firmware overlay and hardware cursor */ 871 crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0); 872 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0); 873 874 /* enable drawing again */ 875 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 876 d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 877 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 878 crmfb_write_reg(sc, CRMFB_VT_XY, 0); 879 880 /* turn on DMA for the framebuffer */ 881 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 882 d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 883 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 884 885 /* turn off sync-on-green */ 886 887 wantsync = arcbios_GetEnvironmentVariable("SyncOnGreen"); 888 if ( (wantsync != NULL) && (wantsync[0] == 'n') ) { 889 d = ( 1 << CRMFB_VT_FLAGS_SYNC_LOW_LSB) & 890 CRMFB_REG_MASK(CRMFB_VT_FLAGS_SYNC_LOW_MSB, 891 CRMFB_VT_FLAGS_SYNC_LOW_LSB); 892 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d); 893 } 894 895 sc->sc_depth = depth; 896 897 /* finally set up the drawing engine's TLB A */ 898 v = (DMAADDR(sc->sc_dma) >> 16) & 0xffff; 899 tlbptr = 0; 900 tx = ((sc->sc_width + (tile_width - 1)) & ~(tile_width - 1)) / 901 tile_width; 902 903 #ifdef CRMFB_DEBUG 904 printf("tx: %d\n", tx); 905 #endif 906 907 for (i = 0; i < 16; i++) { 908 reg = 0; 909 shift = 64; 910 lptr = 0; 911 for (j = 0; j < tx; j++) { 912 shift -= 16; 913 reg |= (((uint64_t)(v | 0x8000)) << shift); 914 if (shift == 0) { 915 shift = 64; 916 bus_space_write_8(sc->sc_iot, sc->sc_reh, 917 CRIME_RE_TLB_A + tlbptr + lptr, 918 reg); 919 #ifdef CRMFB_DEBUG 920 printf("%04x: %016llx\n", tlbptr + lptr, reg); 921 #endif 922 reg = 0; 923 lptr += 8; 924 } 925 v++; 926 } 927 if (shift != 64) { 928 bus_space_write_8(sc->sc_iot, sc->sc_reh, 929 CRIME_RE_TLB_A + tlbptr + lptr, reg); 930 #ifdef CRMFB_DEBUG 931 printf("%04x: %016llx\n", tlbptr + lptr, reg); 932 #endif 933 } 934 tlbptr += 32; 935 } 936 sc->sc_scratch = (char *)KERNADDR(sc->sc_dma) + (0xf0000 * tx); 937 938 /* now put the last 64kB into the 1st linear TLB */ 939 page = (sc->sc_linear >> 12) | 0x80000000; 940 tlbptr = 0; 941 for (i = 0; i < 8; i++) { 942 reg = ((uint64_t)page << 32) | (page + 1); 943 bus_space_write_8(sc->sc_iot, sc->sc_reh, 944 CRIME_RE_LINEAR_A + tlbptr, reg); 945 page += 2; 946 tlbptr += 8; 947 } 948 wbflush(); 949 950 /* do some very basic engine setup */ 951 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_CLIPMODE, 0); 952 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_SRC, 0); 953 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_DST, 0); 954 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PLANEMASK, 955 0xffffffff); 956 957 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x20, 0); 958 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x28, 0); 959 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x30, 0); 960 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x38, 0); 961 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x40, 0); 962 963 switch (depth) { 964 case 8: 965 mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 | 966 DE_MODE_TYPE_CI | DE_MODE_PIXDEPTH_8; 967 break; 968 case 16: 969 mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_16 | 970 DE_MODE_TYPE_RGB | DE_MODE_PIXDEPTH_16; 971 break; 972 case 32: 973 mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_32 | 974 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_32; 975 break; 976 default: 977 panic("%s: unsuported colour depth %d\n", __func__, 978 depth); 979 } 980 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST, mode); 981 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, mode); 982 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_X, 1); 983 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_Y, 1); 984 985 /* initialize memory transfer engine */ 986 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 987 MTE_MODE_DST_ECC | 988 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 989 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 990 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT) | 991 MTE_MODE_COPY); 992 sc->sc_mte_direction = 1; 993 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, 1); 994 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, 1); 995 996 return 0; 997 } 998 999 static void 1000 crmfb_set_mte_direction(struct crmfb_softc *sc, int dir) 1001 { 1002 if (dir == sc->sc_mte_direction) 1003 return; 1004 1005 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, dir); 1006 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, dir); 1007 sc->sc_mte_direction = dir; 1008 } 1009 1010 static void 1011 crmfb_setup_palette(struct crmfb_softc *sc) 1012 { 1013 int i; 1014 1015 for (i = 0; i < 256; i++) { 1016 crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2], 1017 rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]); 1018 sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2]; 1019 sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1]; 1020 sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0]; 1021 } 1022 } 1023 1024 static inline void 1025 crmfb_wait_idle(struct crmfb_softc *sc) 1026 { 1027 int i = 0; 1028 1029 do { 1030 i++; 1031 } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) & 1032 CRIME_DE_IDLE) == 0) && (i < 100000000)); 1033 if (i >= 100000000) 1034 aprint_error("crmfb_wait_idle() timed out\n"); 1035 } 1036 1037 static void 1038 crmfb_fill_rect(struct crmfb_softc *sc, int x, int y, int width, int height, 1039 uint32_t colour) 1040 { 1041 crmfb_wait_idle(sc); 1042 crmfb_set_mte_direction(sc, 1); 1043 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1044 MTE_MODE_DST_ECC | 1045 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1046 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1047 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT) | 1048 0); 1049 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, colour); 1050 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST0, 1051 (x << 16) | (y & 0xffff)); 1052 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1053 CRIME_MTE_DST1 | CRIME_DE_START, 1054 ((x + width - 1) << 16) | ((y + height - 1) & 0xffff)); 1055 } 1056 1057 static void 1058 crmfb_bitblt(struct crmfb_softc *sc, int xs, int ys, int xd, int yd, 1059 int wi, int he, uint32_t rop) 1060 { 1061 uint32_t prim = DE_PRIM_RECTANGLE; 1062 int rxa, rya, rxe, rye, rxs, rys; 1063 crmfb_wait_idle(sc); 1064 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1065 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP | 1066 DE_DRAWMODE_XFER_EN); 1067 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, rop); 1068 if (xs < xd) { 1069 prim |= DE_PRIM_RL; 1070 rxe = xd; 1071 rxa = xd + wi - 1; 1072 rxs = xs + wi - 1; 1073 } else { 1074 prim |= DE_PRIM_LR; 1075 rxe = xd + wi - 1; 1076 rxa = xd; 1077 rxs = xs; 1078 } 1079 if (ys < yd) { 1080 prim |= DE_PRIM_BT; 1081 rye = yd; 1082 rya = yd + he - 1; 1083 rys = ys + he - 1; 1084 } else { 1085 prim |= DE_PRIM_TB; 1086 rye = yd + he - 1; 1087 rya = yd; 1088 rys = ys; 1089 } 1090 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, prim); 1091 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 1092 (rxs << 16) | (rys & 0xffff)); 1093 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1094 (rxa << 16) | (rya & 0xffff)); 1095 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1096 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1097 (rxe << 16) | (rye & 0xffff)); 1098 } 1099 1100 static void 1101 crmfb_scroll(struct crmfb_softc *sc, int xs, int ys, int xd, int yd, 1102 int wi, int he) 1103 { 1104 int rxa, rya, rxe, rye, rxd, ryd, rxde, ryde; 1105 1106 rxa = xs; 1107 rxe = xs + wi - 1; 1108 rxd = xd; 1109 rxde = xd + wi - 1; 1110 1111 crmfb_wait_idle(sc); 1112 1113 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1114 MTE_MODE_DST_ECC | 1115 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1116 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1117 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT) | 1118 MTE_MODE_COPY); 1119 1120 if (ys < yd) { 1121 /* bottom to top */ 1122 rye = ys; 1123 rya = ys + he - 1; 1124 ryd = yd + he - 1; 1125 ryde = yd; 1126 crmfb_set_mte_direction(sc, -1); 1127 } else { 1128 /* top to bottom */ 1129 rye = ys + he - 1; 1130 rya = ys; 1131 ryd = yd; 1132 ryde = yd + he - 1; 1133 crmfb_set_mte_direction(sc, 1); 1134 } 1135 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0, 1136 (rxa << 16) | rya); 1137 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1, 1138 (rxe << 16) | rye); 1139 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1140 CRIME_MTE_DST0, 1141 (rxd << 16) | ryd); 1142 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST1 | 1143 CRIME_DE_START, 1144 (rxde << 16) | ryde); 1145 } 1146 1147 #ifdef CRMFB_DEBUG 1148 void 1149 crmfb_test_mte(struct crmfb_softc *sc) 1150 { 1151 uint64_t addr, reg; 1152 uint32_t addrs[256]; 1153 int i, j, boo; 1154 1155 crmfb_wait_idle(sc); 1156 addr = (uint64_t)(DMAADDR(sc->sc_dma) + sc->sc_fbsize); 1157 addr = addr >> 12; 1158 for (i = 0; i < 64; i += 8) { 1159 #if 1 1160 reg = (addr << 32) | (addr + 1) | 0x8000000080000000LL; 1161 bus_space_write_8(sc->sc_iot, sc->sc_reh, 1162 CRIME_RE_LINEAR_A + i, reg); 1163 printf(" %08x", (uint32_t)(addr & 0xffffffff)); 1164 #endif 1165 addr += 2; 1166 } 1167 printf("\n"); 1168 memset(sc->sc_scratch, 4, 0x10000); 1169 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, 1170 DE_MODE_LIN_A | DE_MODE_BUFDEPTH_8 | DE_MODE_TYPE_CI | 1171 DE_MODE_PIXDEPTH_8); 1172 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1); 1173 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1174 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP | 1175 DE_DRAWMODE_XFER_EN); 1176 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, 3); 1177 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1178 DE_PRIM_RECTANGLE | DE_PRIM_TB); 1179 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 0); 1180 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0, 1181 0x02000000); 1182 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1183 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1184 0x04000100); 1185 1186 crmfb_wait_idle(sc); 1187 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, 1188 DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 | DE_MODE_TYPE_CI | 1189 DE_MODE_PIXDEPTH_8); 1190 1191 #if 1 1192 delay(4000000); 1193 1194 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, 0x15151515); 1195 crmfb_wait_idle(sc); 1196 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1197 MTE_MODE_DST_ECC | 1198 (MTE_TLB_LIN_A << MTE_DST_TLB_SHIFT) | 1199 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1200 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT) | 1201 0/*MTE_MODE_COPY*/); 1202 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_STRIDE, 1); 1203 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_STRIDE, 1); 1204 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0, 0x00000000); 1205 //bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1, 0x01000100); 1206 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST0, 0x00000000); 1207 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST1 | 1208 CRIME_DE_START, 0x00010000); 1209 //status[9] = bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS); 1210 crmfb_wait_idle(sc); 1211 /* now look for 0x05050505 in RAM */ 1212 1213 boo = 0; 1214 for (i = 0xA0000000; i < 0xB0000000; i += 0x1000) 1215 if (*((uint32_t *)i) == 0x15151515) { 1216 /* see if there's more */ 1217 j = 4; 1218 while ((j < 0x100) && (*((uint32_t *)(i + j)) == 1219 0x15151515)) 1220 j += 4; 1221 if (j > 0x20) { 1222 addrs[boo] = i; 1223 boo++; 1224 } 1225 } 1226 printf("..."); 1227 for (i = 0; i < boo; i++) 1228 printf(" %08x", addrs[i]); 1229 printf("\n"); 1230 #endif 1231 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, 1232 DE_MODE_LIN_A | DE_MODE_BUFDEPTH_8 | DE_MODE_TYPE_CI | 1233 DE_MODE_PIXDEPTH_8); 1234 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1); 1235 crmfb_bitblt(sc, 0, 0, 400, 0, 512, 64, 3); 1236 crmfb_wait_idle(sc); 1237 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, 1238 DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 | DE_MODE_TYPE_CI | 1239 DE_MODE_PIXDEPTH_8); 1240 #if 0 1241 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE, 1242 MTE_MODE_DST_ECC | 1243 (MTE_TLB_A << MTE_DST_TLB_SHIFT) | 1244 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) | 1245 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT) | 1246 0/*MTE_MODE_COPY*/); 1247 #endif 1248 delay(4000000); 1249 #if 0 1250 for (i = 0; i < 128; i+=8) 1251 printf("%016llx\n", bus_space_read_8(sc->sc_iot, sc->sc_reh, 1252 CRIME_RE_LINEAR_B + i)); 1253 #endif 1254 #if 0 1255 printf("flush: %08x\n", 1256 bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FLUSH)); 1257 #endif 1258 } 1259 #endif /* CRMFB_DEBUG */ 1260 1261 static void 1262 crmfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1263 { 1264 struct rasops_info *ri = cookie; 1265 struct vcons_screen *scr = ri->ri_hw; 1266 int32_t xs, xd, y, width, height; 1267 1268 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1269 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1270 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1271 width = ri->ri_font->fontwidth * ncols; 1272 height = ri->ri_font->fontheight; 1273 crmfb_bitblt(scr->scr_cookie, xs, y, xd, y, width, height, 3); 1274 } 1275 1276 static void 1277 crmfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1278 { 1279 struct rasops_info *ri = cookie; 1280 struct vcons_screen *scr = ri->ri_hw; 1281 int32_t x, y, width, height, bg; 1282 1283 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1284 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1285 width = ri->ri_font->fontwidth * ncols; 1286 height = ri->ri_font->fontheight; 1287 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1288 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg); 1289 } 1290 1291 static void 1292 crmfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1293 { 1294 struct rasops_info *ri = cookie; 1295 struct vcons_screen *scr = ri->ri_hw; 1296 int32_t x, ys, yd, width, height; 1297 1298 x = ri->ri_xorigin; 1299 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1300 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1301 width = ri->ri_emuwidth; 1302 height = ri->ri_font->fontheight * nrows; 1303 1304 crmfb_scroll(scr->scr_cookie, x, ys, x, yd, width, height); 1305 } 1306 1307 static void 1308 crmfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1309 { 1310 struct rasops_info *ri = cookie; 1311 struct vcons_screen *scr = ri->ri_hw; 1312 int32_t x, y, width, height, bg; 1313 1314 if ((row == 0) && (nrows == ri->ri_rows)) { 1315 x = y = 0; 1316 width = ri->ri_width; 1317 height = ri->ri_height; 1318 } else { 1319 x = ri->ri_xorigin; 1320 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1321 width = ri->ri_emuwidth; 1322 height = ri->ri_font->fontheight * nrows; 1323 } 1324 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1325 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg); 1326 } 1327 1328 static void 1329 crmfb_cursor(void *cookie, int on, int row, int col) 1330 { 1331 struct rasops_info *ri = cookie; 1332 struct vcons_screen *scr = ri->ri_hw; 1333 struct crmfb_softc *sc = scr->scr_cookie; 1334 int x, y, wi,he; 1335 1336 wi = ri->ri_font->fontwidth; 1337 he = ri->ri_font->fontheight; 1338 1339 if (ri->ri_flg & RI_CURSOR) { 1340 x = ri->ri_ccol * wi + ri->ri_xorigin; 1341 y = ri->ri_crow * he + ri->ri_yorigin; 1342 crmfb_bitblt(sc, x, y, x, y, wi, he, 12); 1343 ri->ri_flg &= ~RI_CURSOR; 1344 } 1345 1346 ri->ri_crow = row; 1347 ri->ri_ccol = col; 1348 1349 if (on) 1350 { 1351 x = ri->ri_ccol * wi + ri->ri_xorigin; 1352 y = ri->ri_crow * he + ri->ri_yorigin; 1353 crmfb_bitblt(sc, x, y, x, y, wi, he, 12); 1354 ri->ri_flg |= RI_CURSOR; 1355 } 1356 } 1357 1358 static void 1359 crmfb_putchar(void *cookie, int row, int col, u_int c, long attr) 1360 { 1361 struct rasops_info *ri = cookie; 1362 struct vcons_screen *scr = ri->ri_hw; 1363 struct crmfb_softc *sc = scr->scr_cookie; 1364 struct wsdisplay_font *font = PICK_FONT(ri, c); 1365 uint32_t bg, fg; 1366 int x, y, wi, he, i, uc; 1367 uint8_t *fd8; 1368 uint16_t *fd16; 1369 void *fd; 1370 1371 wi = font->fontwidth; 1372 he = font->fontheight; 1373 1374 x = ri->ri_xorigin + col * wi; 1375 y = ri->ri_yorigin + row * he; 1376 1377 bg = ri->ri_devcmap[(attr >> 16) & 0xff]; 1378 fg = ri->ri_devcmap[(attr >> 24) & 0xff]; 1379 uc = c - font->firstchar; 1380 fd = (uint8_t *)font->data + uc * ri->ri_fontscale; 1381 if (c == 0x20) { 1382 crmfb_fill_rect(sc, x, y, wi, he, bg); 1383 } else { 1384 crmfb_wait_idle(sc); 1385 /* setup */ 1386 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, 3); 1387 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, fg); 1388 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_BG, bg); 1389 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE, 1390 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | 1391 DE_DRAWMODE_ROP | 1392 DE_DRAWMODE_OPAQUE_STIP | DE_DRAWMODE_POLY_STIP); 1393 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, 1394 DE_PRIM_RECTANGLE | DE_PRIM_LR | DE_PRIM_TB); 1395 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STIPPLE_MODE, 1396 0x001f0000); 1397 /* now let's feed the engine */ 1398 if (font->stride == 1) { 1399 /* shovel in 8 bit quantities */ 1400 fd8 = fd; 1401 for (i = 0; i < he; i++) { 1402 /* 1403 * the pipeline should be long enough to 1404 * draw any character without having to wait 1405 */ 1406 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1407 CRIME_DE_STIPPLE_PAT, *fd8 << 24); 1408 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1409 CRIME_DE_X_VERTEX_0, (x << 16) | y); 1410 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1411 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1412 ((x + wi) << 16) | y); 1413 y++; 1414 fd8++; 1415 } 1416 } else if (font->stride == 2) { 1417 /* shovel in 16 bit quantities */ 1418 fd16 = fd; 1419 for (i = 0; i < he; i++) { 1420 /* 1421 * the pipeline should be long enough to 1422 * draw any character without having to wait 1423 */ 1424 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1425 CRIME_DE_STIPPLE_PAT, *fd16 << 16); 1426 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1427 CRIME_DE_X_VERTEX_0, (x << 16) | y); 1428 bus_space_write_4(sc->sc_iot, sc->sc_reh, 1429 CRIME_DE_X_VERTEX_1 | CRIME_DE_START, 1430 ((x + wi) << 16) | y); 1431 y++; 1432 fd16++; 1433 } 1434 } 1435 } 1436 } 1437