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