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