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