1 /* $NetBSD: crmfb.c,v 1.8 2007/10/17 19:57:03 garbled Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jared D. McNeill. 18 * 4. Neither the name of The NetBSD Foundation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * SGI-CRM (O2) Framebuffer driver 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.8 2007/10/17 19:57:03 garbled Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 47 #define _SGIMIPS_BUS_DMA_PRIVATE 48 #include <machine/autoconf.h> 49 #include <machine/bus.h> 50 #include <machine/machtype.h> 51 #include <machine/vmparam.h> 52 53 #include <dev/arcbios/arcbios.h> 54 #include <dev/arcbios/arcbiosvar.h> 55 56 #include <dev/wscons/wsdisplayvar.h> 57 #include <dev/wscons/wsconsio.h> 58 #include <dev/wsfont/wsfont.h> 59 #include <dev/rasops/rasops.h> 60 #include <dev/wscons/wsdisplay_vconsvar.h> 61 62 #include <arch/sgimips/dev/crmfbreg.h> 63 64 #define CRMFB_SHADOWFB 65 66 struct wsscreen_descr crmfb_defaultscreen = { 67 "default", 68 0, 0, 69 NULL, 70 8, 16, 71 WSSCREEN_WSCOLORS, 72 NULL, 73 }; 74 75 const struct wsscreen_descr *_crmfb_scrlist[] = { 76 &crmfb_defaultscreen, 77 }; 78 79 struct wsscreen_list crmfb_screenlist = { 80 sizeof(_crmfb_scrlist) / sizeof(struct wsscreen_descr *), 81 _crmfb_scrlist 82 }; 83 84 static struct vcons_screen crmfb_console_screen; 85 86 static int crmfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 87 static paddr_t crmfb_mmap(void *, void *, off_t, int); 88 static void crmfb_init_screen(void *, struct vcons_screen *, int, long *); 89 90 struct wsdisplay_accessops crmfb_accessops = { 91 crmfb_ioctl, 92 crmfb_mmap, 93 NULL, /* alloc_screen */ 94 NULL, /* free_screen */ 95 NULL, /* show_screen */ 96 NULL, /* load_font */ 97 NULL, /* pollc */ 98 NULL, /* scroll */ 99 }; 100 101 /* Memory to allocate to SGI-CRM -- remember, this is stolen from 102 * host memory! 103 */ 104 #define CRMFB_TILESIZE (512*128) 105 106 static int crmfb_match(struct device *, struct cfdata *, void *); 107 static void crmfb_attach(struct device *, struct device *, void *); 108 int crmfb_probe(void); 109 110 #define KERNADDR(p) ((void *)((p).addr)) 111 #define DMAADDR(p) ((p).map->dm_segs[0].ds_addr) 112 113 struct crmfb_dma { 114 bus_dmamap_t map; 115 void *addr; 116 bus_dma_segment_t segs[1]; 117 int nsegs; 118 size_t size; 119 }; 120 121 struct crmfb_softc { 122 struct device sc_dev; 123 struct vcons_data sc_vd; 124 125 bus_space_tag_t sc_iot; 126 bus_space_handle_t sc_ioh; 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 uint32_t sc_fbsize; 137 uint8_t *sc_shadowfb; 138 139 int sc_wsmode; 140 141 /* cursor stuff */ 142 int sc_cur_x; 143 int sc_cur_y; 144 int sc_hot_x; 145 int sc_hot_y; 146 147 u_char sc_cmap_red[256]; 148 u_char sc_cmap_green[256]; 149 u_char sc_cmap_blue[256]; 150 }; 151 152 static int crmfb_putcmap(struct crmfb_softc *, struct wsdisplay_cmap *); 153 static int crmfb_getcmap(struct crmfb_softc *, struct wsdisplay_cmap *); 154 static void crmfb_set_palette(struct crmfb_softc *, 155 int, uint8_t, uint8_t, uint8_t); 156 static int crmfb_set_curpos(struct crmfb_softc *, int, int); 157 static int crmfb_gcursor(struct crmfb_softc *, struct wsdisplay_cursor *); 158 static int crmfb_scursor(struct crmfb_softc *, struct wsdisplay_cursor *); 159 static inline void crmfb_write_reg(struct crmfb_softc *, int, uint32_t); 160 161 /* setup video hw in given colour depth */ 162 static int crmfb_setup_video(struct crmfb_softc *, int); 163 static void crmfb_setup_palette(struct crmfb_softc *); 164 165 CFATTACH_DECL(crmfb, sizeof(struct crmfb_softc), 166 crmfb_match, crmfb_attach, NULL, NULL); 167 168 static int 169 crmfb_match(struct device *parent, struct cfdata *cf, void *opaque) 170 { 171 return crmfb_probe(); 172 } 173 174 static void 175 crmfb_attach(struct device *parent, struct device *self, void *opaque) 176 { 177 struct mainbus_attach_args *ma; 178 struct crmfb_softc *sc; 179 struct rasops_info *ri; 180 struct wsemuldisplaydev_attach_args aa; 181 uint32_t d, h; 182 uint16_t *p; 183 unsigned long v; 184 long defattr; 185 const char *consdev; 186 int rv, i, tiles_x, tiles_y; 187 188 sc = (struct crmfb_softc *)self; 189 ma = (struct mainbus_attach_args *)opaque; 190 191 sc->sc_iot = SGIMIPS_BUS_SPACE_CRIME; 192 sc->sc_dmat = &sgimips_default_bus_dma_tag; 193 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL; 194 195 aprint_normal(": SGI CRIME Graphics Display Engine\n"); 196 rv = bus_space_map(sc->sc_iot, ma->ma_addr, 0 /* XXX */, 197 BUS_SPACE_MAP_LINEAR, &sc->sc_ioh); 198 if (rv) 199 panic("crmfb_attach: can't map I/O space"); 200 201 /* determine mode configured by firmware */ 202 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_VCMAP); 203 sc->sc_width = (d >> CRMFB_VT_VCMAP_ON_SHIFT) & 0xfff; 204 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP); 205 sc->sc_height = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff; 206 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 207 h = (d >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 0x3; 208 if (h == 0) 209 sc->sc_depth = 8; 210 else if (h == 1) 211 sc->sc_depth = 16; 212 else 213 sc->sc_depth = 32; 214 215 if (sc->sc_width == 0 || sc->sc_height == 0) { 216 printf("%s: device unusable if not setup by firmware\n", 217 sc->sc_dev.dv_xname); 218 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0 /* XXX */); 219 return; 220 } 221 222 printf("%s: initial resolution %dx%d\n", 223 sc->sc_dev.dv_xname, sc->sc_width, sc->sc_height); 224 225 /* 226 * first determine how many tiles we need 227 * in 32bit each tile is 128x128 pixels 228 */ 229 tiles_x = (sc->sc_width + 127) >> 7; 230 tiles_y = (sc->sc_height + 127) >> 7; 231 sc->sc_fbsize = 0x10000 * tiles_x * tiles_y; 232 printf("so we need %d x %d tiles -> %08x\n", tiles_x, tiles_y, 233 sc->sc_fbsize); 234 235 sc->sc_dmai.size = 256 * sizeof(uint16_t); 236 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmai.size, 65536, 0, 237 sc->sc_dmai.segs, 238 sizeof(sc->sc_dmai.segs) / sizeof(sc->sc_dmai.segs[0]), 239 &sc->sc_dmai.nsegs, BUS_DMA_NOWAIT); 240 if (rv) 241 panic("crmfb_attach: can't allocate DMA memory"); 242 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dmai.segs, sc->sc_dmai.nsegs, 243 sc->sc_dmai.size, &sc->sc_dmai.addr, 244 BUS_DMA_NOWAIT); 245 if (rv) 246 panic("crmfb_attach: can't map DMA memory"); 247 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dmai.size, 1, 248 sc->sc_dmai.size, 0, BUS_DMA_NOWAIT, &sc->sc_dmai.map); 249 if (rv) 250 panic("crmfb_attach: can't create DMA map"); 251 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmai.map, sc->sc_dmai.addr, 252 sc->sc_dmai.size, NULL, BUS_DMA_NOWAIT); 253 if (rv) 254 panic("crmfb_attach: can't load DMA map"); 255 256 sc->sc_dma.size = sc->sc_fbsize; 257 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0, 258 sc->sc_dma.segs, 259 sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]), 260 &sc->sc_dma.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_dma.segs, sc->sc_dma.nsegs, 264 sc->sc_dma.size, &sc->sc_dma.addr, 265 BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 266 if (rv) 267 panic("crmfb_attach: can't map DMA memory"); 268 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dma.size, 1, 269 sc->sc_dma.size, 0, BUS_DMA_NOWAIT, &sc->sc_dma.map); 270 if (rv) 271 panic("crmfb_attach: can't create DMA map"); 272 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr, 273 sc->sc_dma.size, NULL, BUS_DMA_NOWAIT); 274 if (rv) 275 panic("crmfb_attach: can't load DMA map"); 276 277 p = KERNADDR(sc->sc_dmai); 278 v = (unsigned long)DMAADDR(sc->sc_dma); 279 for (i = 0; i < (sc->sc_fbsize >> 16); i++) { 280 p[i] = ((uint32_t)v >> 16) + i; 281 } 282 283 memset(KERNADDR(sc->sc_dma), 0x00, sc->sc_fbsize); 284 285 printf("%s: allocated %d byte fb @ %p (%p)\n", sc->sc_dev.dv_xname, 286 sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma)); 287 288 #ifdef CRMFB_SHADOWFB 289 /* setup shadow framebuffer */ 290 sc->sc_shadowfb = malloc(sc->sc_fbsize, M_DEVBUF, M_NOWAIT | M_ZERO); 291 if (sc->sc_shadowfb == NULL) 292 aprint_error("%s: WARNING: couldn't allocate shadow fb\n", 293 sc->sc_dev.dv_xname); 294 #endif 295 296 ri = &crmfb_console_screen.scr_ri; 297 memset(ri, 0, sizeof(struct rasops_info)); 298 299 vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops); 300 sc->sc_vd.init_screen = crmfb_init_screen; 301 crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 302 vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr); 303 304 crmfb_defaultscreen.ncols = ri->ri_cols; 305 crmfb_defaultscreen.nrows = ri->ri_rows; 306 crmfb_defaultscreen.textops = &ri->ri_ops; 307 crmfb_defaultscreen.capabilities = ri->ri_caps; 308 crmfb_defaultscreen.modecookie = NULL; 309 310 crmfb_setup_video(sc, 8); 311 crmfb_setup_palette(sc); 312 313 consdev = ARCBIOS->GetEnvironmentVariable("ConsoleOut"); 314 if (consdev != NULL && strcmp(consdev, "video()") == 0) { 315 wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr); 316 aa.console = 1; 317 } else 318 aa.console = 0; 319 aa.scrdata = &crmfb_screenlist; 320 aa.accessops = &crmfb_accessops; 321 aa.accesscookie = &sc->sc_vd; 322 323 config_found(self, &aa, wsemuldisplaydevprint); 324 325 sc->sc_cur_x = 0; 326 sc->sc_cur_y = 0; 327 sc->sc_hot_x = 0; 328 sc->sc_hot_y = 0; 329 330 return; 331 } 332 333 int 334 crmfb_probe(void) 335 { 336 337 if (mach_type != MACH_SGI_IP32) 338 return 0; 339 340 return 1; 341 } 342 343 static int 344 crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 345 { 346 struct vcons_data *vd; 347 struct crmfb_softc *sc; 348 struct vcons_screen *ms; 349 struct wsdisplay_fbinfo *wdf; 350 int nmode; 351 352 vd = (struct vcons_data *)v; 353 sc = (struct crmfb_softc *)vd->cookie; 354 ms = (struct vcons_screen *)vd->active; 355 356 switch (cmd) { 357 case WSDISPLAYIO_GTYPE: 358 /* not really, but who cares? */ 359 /* wsfb does */ 360 *(u_int *)data = WSDISPLAY_TYPE_CRIME; 361 return 0; 362 case WSDISPLAYIO_GINFO: 363 if (vd->active != NULL) { 364 wdf = (void *)data; 365 wdf->height = sc->sc_height; 366 wdf->width = sc->sc_width; 367 wdf->depth = 32; 368 wdf->cmsize = 256; 369 return 0; 370 } else 371 return ENODEV; 372 case WSDISPLAYIO_GETCMAP: 373 if (sc->sc_depth == 8) 374 return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data); 375 else 376 return EINVAL; 377 case WSDISPLAYIO_PUTCMAP: 378 if (sc->sc_depth == 8) 379 return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data); 380 else 381 return EINVAL; 382 case WSDISPLAYIO_LINEBYTES: 383 *(u_int *)data = sc->sc_width * sc->sc_depth / 8; 384 return 0; 385 case WSDISPLAYIO_SMODE: 386 nmode = *(int *)data; 387 if (nmode != sc->sc_wsmode) { 388 sc->sc_wsmode = nmode; 389 if (nmode == WSDISPLAYIO_MODE_EMUL) { 390 crmfb_setup_video(sc, 8); 391 crmfb_setup_palette(sc); 392 vcons_redraw_screen(vd->active); 393 } else { 394 crmfb_setup_video(sc, 32); 395 } 396 } 397 return 0; 398 case WSDISPLAYIO_SVIDEO: 399 case WSDISPLAYIO_GVIDEO: 400 return ENODEV; /* not supported yet */ 401 402 case WSDISPLAYIO_GCURPOS: 403 { 404 struct wsdisplay_curpos *pos; 405 406 pos = (struct wsdisplay_curpos *)data; 407 pos->x = sc->sc_cur_x; 408 pos->y = sc->sc_cur_y; 409 } 410 return 0; 411 case WSDISPLAYIO_SCURPOS: 412 { 413 struct wsdisplay_curpos *pos; 414 415 pos = (struct wsdisplay_curpos *)data; 416 crmfb_set_curpos(sc, pos->x, pos->y); 417 } 418 return 0; 419 case WSDISPLAYIO_GCURMAX: 420 { 421 struct wsdisplay_curpos *pos; 422 423 pos = (struct wsdisplay_curpos *)data; 424 pos->x = 32; 425 pos->y = 32; 426 } 427 return 0; 428 case WSDISPLAYIO_GCURSOR: 429 { 430 struct wsdisplay_cursor *cu; 431 432 cu = (struct wsdisplay_cursor *)data; 433 return crmfb_gcursor(sc, cu); 434 } 435 case WSDISPLAYIO_SCURSOR: 436 { 437 struct wsdisplay_cursor *cu; 438 439 cu = (struct wsdisplay_cursor *)data; 440 return crmfb_scursor(sc, cu); 441 } 442 } 443 return EPASSTHROUGH; 444 } 445 446 static paddr_t 447 crmfb_mmap(void *v, void *vs, off_t offset, int prot) 448 { 449 struct vcons_data *vd; 450 struct crmfb_softc *sc; 451 paddr_t pa; 452 453 vd = (struct vcons_data *)v; 454 sc = (struct crmfb_softc *)vd->cookie; 455 456 #if 1 457 if (offset >= 0 && offset < sc->sc_fbsize) { 458 pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs, 459 sc->sc_dma.nsegs, offset, prot, 460 BUS_DMA_WAITOK | BUS_DMA_COHERENT); 461 return pa; 462 } 463 #else 464 if (offset >= 0 && offset < sc->sc_fbsize) { 465 pa = bus_space_mmap(SGIMIPS_BUS_SPACE_NORMAL, sc->sc_fbh, 466 offset, prot, SGIMIPS_BUS_SPACE_NORMAL); 467 printf("%s: %08llx -> %llx\n", __func__, offset, pa); 468 return pa; 469 } 470 #endif 471 return -1; 472 } 473 474 static void 475 crmfb_init_screen(void *c, struct vcons_screen *scr, int existing, 476 long *defattr) 477 { 478 struct crmfb_softc *sc; 479 struct rasops_info *ri; 480 481 sc = (struct crmfb_softc *)c; 482 ri = &scr->scr_ri; 483 484 ri->ri_flg = RI_CENTER; 485 ri->ri_depth = sc->sc_depth; 486 ri->ri_width = sc->sc_width; 487 ri->ri_height = sc->sc_height; 488 ri->ri_stride = ri->ri_width * (ri->ri_depth / 8); 489 490 switch (ri->ri_depth) { 491 case 16: 492 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5; 493 ri->ri_rpos = 10; 494 ri->ri_gpos = 5; 495 ri->ri_bpos = 0; 496 break; 497 case 32: 498 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8; 499 ri->ri_rpos = 8; 500 ri->ri_gpos = 16; 501 ri->ri_bpos = 24; 502 break; 503 } 504 505 if (sc->sc_shadowfb == NULL) 506 ri->ri_bits = KERNADDR(sc->sc_dma); 507 else { 508 ri->ri_bits = sc->sc_shadowfb; 509 ri->ri_hwbits = KERNADDR(sc->sc_dma); 510 } 511 512 if (existing) 513 ri->ri_flg |= RI_CLEAR; 514 515 rasops_init(ri, ri->ri_height / 16, ri->ri_width / 8); 516 ri->ri_caps = WSSCREEN_WSCOLORS; 517 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 518 ri->ri_width / ri->ri_font->fontwidth); 519 ri->ri_hw = scr; 520 521 return; 522 } 523 524 static int 525 crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 526 { 527 u_int idx, cnt; 528 u_char r[256], g[256], b[256]; 529 u_char *rp, *gp, *bp; 530 int rv, i; 531 532 idx = cm->index; 533 cnt = cm->count; 534 535 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 536 return EINVAL; 537 538 rv = copyin(cm->red, &r[idx], cnt); 539 if (rv) 540 return rv; 541 rv = copyin(cm->green, &g[idx], cnt); 542 if (rv) 543 return rv; 544 rv = copyin(cm->blue, &b[idx], cnt); 545 if (rv) 546 return rv; 547 548 memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt); 549 memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt); 550 memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt); 551 552 rp = &sc->sc_cmap_red[idx]; 553 gp = &sc->sc_cmap_green[idx]; 554 bp = &sc->sc_cmap_blue[idx]; 555 556 for (i = 0; i < cnt; i++) { 557 crmfb_set_palette(sc, idx, *rp, *gp, *bp); 558 idx++; 559 rp++, gp++, bp++; 560 } 561 562 return 0; 563 } 564 565 static int 566 crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm) 567 { 568 u_int idx, cnt; 569 int rv; 570 571 idx = cm->index; 572 cnt = cm->count; 573 574 if (idx >= 255 || cnt > 256 || idx + cnt > 256) 575 return EINVAL; 576 577 rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt); 578 if (rv) 579 return rv; 580 rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt); 581 if (rv) 582 return rv; 583 rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt); 584 if (rv) 585 return rv; 586 587 return 0; 588 } 589 590 static void 591 crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g, 592 uint8_t b) 593 { 594 uint32_t val; 595 596 if (reg > 255 || sc->sc_depth != 8) 597 return; 598 599 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63) 600 DELAY(10); 601 602 val = (r << 24) | (g << 16) | (b << 8); 603 crmfb_write_reg(sc, CRMFB_CMAP + (reg * 4), val); 604 605 return; 606 } 607 608 static int 609 crmfb_set_curpos(struct crmfb_softc *sc, int x, int y) 610 { 611 uint32_t val; 612 613 sc->sc_cur_x = x; 614 sc->sc_cur_y = y; 615 616 val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16); 617 crmfb_write_reg(sc, CRMFB_CURSOR_POS, val); 618 619 return 0; 620 } 621 622 static int 623 crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 624 { 625 /* do nothing for now */ 626 return 0; 627 } 628 629 static int 630 crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur) 631 { 632 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 633 634 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, cur->enable ? 1 : 0); 635 } 636 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 637 638 sc->sc_hot_x = cur->hot.x; 639 sc->sc_hot_y = cur->hot.y; 640 } 641 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 642 643 crmfb_set_curpos(sc, cur->pos.x, cur->pos.y); 644 } 645 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 646 int i; 647 uint32_t val; 648 649 for (i = 0; i < cur->cmap.count; i++) { 650 val = (cur->cmap.red[i] << 24) | 651 (cur->cmap.green[i] << 16) | 652 (cur->cmap.blue[i] << 8); 653 crmfb_write_reg(sc, CRMFB_CURSOR_CMAP0 + 654 ((i + cur->cmap.index) << 2), val); 655 } 656 } 657 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 658 659 int i, j, cnt = 0; 660 uint32_t latch = 0, omask; 661 uint8_t imask; 662 for (i = 0; i < 64; i++) { 663 omask = 0x80000000; 664 imask = 0x01; 665 cur->image[cnt] &= cur->mask[cnt]; 666 for (j = 0; j < 8; j++) { 667 if (cur->image[cnt] & imask) 668 latch |= omask; 669 omask >>= 1; 670 if (cur->mask[cnt] & imask) 671 latch |= omask; 672 omask >>= 1; 673 imask <<= 1; 674 } 675 cnt++; 676 imask = 0x01; 677 cur->image[cnt] &= cur->mask[cnt]; 678 for (j = 0; j < 8; j++) { 679 if (cur->image[cnt] & imask) 680 latch |= omask; 681 omask >>= 1; 682 if (cur->mask[cnt] & imask) 683 latch |= omask; 684 omask >>= 1; 685 imask <<= 1; 686 } 687 cnt++; 688 crmfb_write_reg(sc, CRMFB_CURSOR_BITMAP + (i << 2), 689 latch); 690 latch = 0; 691 } 692 } 693 return 0; 694 } 695 696 static inline void 697 crmfb_write_reg(struct crmfb_softc *sc, int offset, uint32_t val) 698 { 699 700 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val); 701 wbflush(); 702 } 703 704 static int 705 crmfb_setup_video(struct crmfb_softc *sc, int depth) 706 { 707 uint32_t d, h; 708 int i; 709 710 /* disable DMA */ 711 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL); 712 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT); 713 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d); 714 DELAY(50000); 715 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 716 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 717 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 718 DELAY(50000); 719 crmfb_write_reg(sc, CRMFB_DID_CONTROL, 0); 720 DELAY(50000); 721 722 /* ensure that CRM starts drawing at the top left of the screen 723 * when we re-enable DMA later 724 */ 725 d = (1 << CRMFB_VT_XY_FREEZE_SHIFT); 726 crmfb_write_reg(sc, CRMFB_VT_XY, d); 727 delay(1000); 728 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 729 d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 730 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 731 delay(1000); 732 733 /* reset FIFO */ 734 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE); 735 d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 736 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 737 d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT); 738 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 739 740 /* setup colour mode */ 741 switch (depth) { 742 case 8: 743 h = CRMFB_MODE_TYP_I8; 744 break; 745 case 16: 746 h = CRMFB_MODE_TYP_ARGB5; 747 break; 748 case 32: 749 h = CRMFB_MODE_TYP_RGB8; 750 break; 751 default: 752 panic("Unsupported depth"); 753 } 754 d = h << CRMFB_MODE_TYP_SHIFT; 755 d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT; 756 for (i = 0; i < (32 * 4); i += 4) 757 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d); 758 wbflush(); 759 760 /* setup tile pointer, but don't turn on DMA yet! */ 761 h = DMAADDR(sc->sc_dmai); 762 d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT; 763 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 764 765 /* init framebuffer width and pixel size */ 766 d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT); 767 switch (depth) { 768 case 8: 769 h = CRMFB_FRM_TILESIZE_DEPTH_8; 770 break; 771 case 16: 772 h = CRMFB_FRM_TILESIZE_DEPTH_16; 773 break; 774 case 32: 775 h = CRMFB_FRM_TILESIZE_DEPTH_32; 776 break; 777 default: 778 panic("Unsupported depth"); 779 } 780 d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT); 781 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d); 782 783 /* init framebuffer height, we use the trick that the Linux 784 * driver uses to fool the CRM out of tiled mode and into 785 * linear mode 786 */ 787 h = sc->sc_width * sc->sc_height / (512 / (depth >> 3)); 788 d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT; 789 crmfb_write_reg(sc, CRMFB_FRM_PIXSIZE, d); 790 791 /* turn off firmware overlay and hardware cursor */ 792 crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0); 793 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0); 794 795 /* enable drawing again */ 796 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK); 797 d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT); 798 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d); 799 crmfb_write_reg(sc, CRMFB_VT_XY, 0); 800 801 /* turn on DMA for the framebuffer */ 802 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL); 803 d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT); 804 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d); 805 806 sc->sc_depth = depth; 807 return 0; 808 } 809 810 static void 811 crmfb_setup_palette(struct crmfb_softc *sc) 812 { 813 int i; 814 815 for (i = 0; i < 256; i++) { 816 crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2], 817 rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]); 818 sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2]; 819 sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1]; 820 sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0]; 821 } 822 } 823