1/* $NetBSD: ct65550.c,v 1.15 2021/08/07 16:19:12 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2006 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/* 29 * A console driver for Chips & Technologies 65550 graphics controllers 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: ct65550.c,v 1.15 2021/08/07 16:19:12 thorpej Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/device.h> 39#include <sys/kauth.h> 40#include <sys/bus.h> 41#include <dev/videomode/videomode.h> 42 43#include <dev/ic/ct65550reg.h> 44#include <dev/ic/ct65550var.h> 45 46#include "opt_wsemul.h" 47#include "opt_chipsfb.h" 48 49static struct vcons_screen chipsfb_console_screen; 50 51extern const u_char rasops_cmap[768]; 52 53static void chipsfb_init(struct chipsfb_softc *); 54 55static void chipsfb_cursor(void *, int, int, int); 56static void chipsfb_copycols(void *, int, int, int, int); 57static void chipsfb_erasecols(void *, int, int, int, long); 58static void chipsfb_copyrows(void *, int, int, int); 59static void chipsfb_eraserows(void *, int, int, long); 60 61#if 0 62static int chipsfb_allocattr(void *, int, int, int, long *); 63static void chipsfb_scroll(void *, void *, int); 64static int chipsfb_load_font(void *, void *, struct wsdisplay_font *); 65#endif 66 67static int chipsfb_putcmap(struct chipsfb_softc *, 68 struct wsdisplay_cmap *); 69static int chipsfb_getcmap(struct chipsfb_softc *, 70 struct wsdisplay_cmap *); 71static int chipsfb_putpalreg(struct chipsfb_softc *, uint8_t, uint8_t, 72 uint8_t, uint8_t); 73 74static void chipsfb_bitblt(void *, int, int, int, int, 75 int, int, int); 76static void chipsfb_rectfill(struct chipsfb_softc *, int, int, int, int, 77 int); 78static void chipsfb_putchar(void *, int, int, u_int, long); 79static void chipsfb_putchar_aa(void *, int, int, u_int, long); 80static void chipsfb_setup_mono(struct chipsfb_softc *, int, int, int, 81 int, uint32_t, uint32_t); 82static void chipsfb_feed(struct chipsfb_softc *, int, uint8_t *); 83 84#if 0 85static void chipsfb_showpal(struct chipsfb_softc *); 86#endif 87static void chipsfb_restore_palette(struct chipsfb_softc *); 88 89static void chipsfb_wait_idle(struct chipsfb_softc *); 90 91struct wsscreen_descr chipsfb_defaultscreen = { 92 "default", /* name */ 93 0, 0, /* ncols, nrows */ 94 NULL, /* textops */ 95 8, 16, /* fontwidth, fontheight */ 96 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, /* capabilities */ 97 NULL, /* modecookie */ 98}; 99 100const struct wsscreen_descr *_chipsfb_scrlist[] = { 101 &chipsfb_defaultscreen, 102 /* XXX other formats, graphics screen? */ 103}; 104 105struct wsscreen_list chipsfb_screenlist = { 106 sizeof(_chipsfb_scrlist) / sizeof(struct wsscreen_descr *), _chipsfb_scrlist 107}; 108 109static int chipsfb_ioctl(void *, void *, u_long, void *, int, 110 struct lwp *); 111static paddr_t chipsfb_mmap(void *, void *, off_t, int); 112static void chipsfb_clearscreen(struct chipsfb_softc *); 113static void chipsfb_init_screen(void *, struct vcons_screen *, int, 114 long *); 115 116 117struct wsdisplay_accessops chipsfb_accessops = { 118 chipsfb_ioctl, 119 chipsfb_mmap, 120 NULL, /* vcons_alloc_screen */ 121 NULL, /* vcons_free_screen */ 122 NULL, /* vcons_show_screen */ 123 NULL, /* load_font */ 124 NULL, /* polls */ 125 NULL, /* scroll */ 126}; 127 128/* 129 * Inline functions for getting access to register aperture. 130 */ 131static inline void 132chipsfb_write32(struct chipsfb_softc *sc, uint32_t reg, uint32_t val) 133{ 134 bus_space_write_4(sc->sc_memt, sc->sc_mmregh, reg, val); 135} 136 137static inline uint32_t 138chipsfb_read32(struct chipsfb_softc *sc, uint32_t reg) 139{ 140 return bus_space_read_4(sc->sc_memt, sc->sc_mmregh, reg); 141} 142 143static inline void 144chipsfb_write_vga(struct chipsfb_softc *sc, uint32_t reg, uint8_t val) 145{ 146 bus_space_write_1(sc->sc_iot, sc->sc_ioregh, reg, val); 147} 148 149static inline uint8_t 150chipsfb_read_vga(struct chipsfb_softc *sc, uint32_t reg) 151{ 152 return bus_space_read_1(sc->sc_iot, sc->sc_ioregh, reg); 153} 154 155static inline uint8_t 156chipsfb_read_indexed(struct chipsfb_softc *sc, uint32_t reg, uint8_t index) 157{ 158 159 chipsfb_write_vga(sc, reg & 0xfffe, index); 160 return chipsfb_read_vga(sc, reg | 0x0001); 161} 162 163static inline void 164chipsfb_write_indexed(struct chipsfb_softc *sc, uint32_t reg, uint8_t index, 165 uint8_t val) 166{ 167 168 chipsfb_write_vga(sc, reg & 0xfffe, index); 169 chipsfb_write_vga(sc, reg | 0x0001, val); 170} 171 172static void 173chipsfb_wait_idle(struct chipsfb_softc *sc) 174{ 175 176#ifdef CHIPSFB_DEBUG 177 chipsfb_write32(sc, CT_OFF_FB + (800 * 598) - 4, 0); 178#endif 179 180 /* spin until the blitter is idle */ 181 while ((chipsfb_read32(sc, CT_BLT_CONTROL) & BLT_IS_BUSY) != 0) { 182 } 183 184#ifdef CHIPSFB_DEBUG 185 chipsfb_write32(sc, CT_OFF_FB + (800 * 598) - 4, 0xffffffff); 186#endif 187} 188 189void 190chipsfb_do_attach(struct chipsfb_softc *sc) 191{ 192 struct wsemuldisplaydev_attach_args aa; 193 struct rasops_info *ri; 194 prop_dictionary_t dict; 195 ulong defattr; 196 bool console = false; 197 int width, height, i, j; 198 uint32_t bg, fg, ul; 199 uint8_t cmap[768]; 200 201 dict = device_properties(sc->sc_dev); 202 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 203 sc->sc_dacw = -1; 204 205#ifdef CHIPSFB_DEBUG 206 printf(prop_dictionary_externalize(dict)); 207#endif 208 chipsfb_init(sc); 209 210 width = height = -1; 211 212 /* detect panel size */ 213 width = chipsfb_read_indexed(sc, CT_FP_INDEX, FP_HSIZE_LSB); 214 width |= (chipsfb_read_indexed(sc, CT_FP_INDEX, FP_HORZ_OVERFLOW_1) 215 & 0x0f) << 8; 216 width = (width + 1) * 8; 217 height = chipsfb_read_indexed(sc, CT_FP_INDEX, FP_VSIZE_LSB); 218 height |= (chipsfb_read_indexed(sc, CT_FP_INDEX, FP_VERT_OVERFLOW_1) 219 & 0x0f) << 8; 220 height++; 221 if ((width < 640) || ( width > 1280) || (height < 480) || 222 (height > 1024)) { 223 /* no sane values in the panel registers */ 224 width = height = -1; 225 } else 226 aprint_verbose("Panel size: %d x %d\n", width, height); 227 228 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) 229 sc->sc_width = width; 230 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) 231 sc->sc_height = height; 232 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_bits_per_pixel)) 233 sc->sc_bits_per_pixel = 8; 234 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_linebytes)) 235 sc->sc_linebytes = (sc->sc_width * sc->sc_bits_per_pixel) >> 3; 236 237 prop_dictionary_get_bool(dict, "is_console", &console); 238 239#ifdef notyet 240 /* XXX this should at least be configurable via kernel config */ 241 chipsfb_set_videomode(sc, &videomode_list[16]); 242#endif 243 244 vcons_init(&sc->vd, sc, &chipsfb_defaultscreen, &chipsfb_accessops); 245 sc->vd.init_screen = chipsfb_init_screen; 246 247 sc->sc_gc.gc_bitblt = chipsfb_bitblt; 248 sc->sc_gc.gc_blitcookie = sc; 249 sc->sc_gc.gc_rop = ROP_COPY; 250 251 ri = &chipsfb_console_screen.scr_ri; 252 if (console) { 253 vcons_init_screen(&sc->vd, &chipsfb_console_screen, 1, 254 &defattr); 255 chipsfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 256 257 chipsfb_defaultscreen.textops = &ri->ri_ops; 258 chipsfb_defaultscreen.capabilities = ri->ri_caps; 259 chipsfb_defaultscreen.nrows = ri->ri_rows; 260 chipsfb_defaultscreen.ncols = ri->ri_cols; 261 glyphcache_init(&sc->sc_gc, sc->sc_height + 1, 262 (sc->sc_fbsize / sc->sc_linebytes) - sc->sc_height - 1, 263 sc->sc_width, 264 ri->ri_font->fontwidth, 265 ri->ri_font->fontheight, 266 defattr); 267 wsdisplay_cnattach(&chipsfb_defaultscreen, ri, 0, 0, defattr); 268 } else { 269 if (chipsfb_console_screen.scr_ri.ri_rows == 0) { 270 /* do some minimal setup to avoid weirdnesses later */ 271 vcons_init_screen(&sc->vd, &chipsfb_console_screen, 1, 272 &defattr); 273 } else 274 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 275 276 glyphcache_init(&sc->sc_gc, sc->sc_height + 1, 277 (sc->sc_fbsize / sc->sc_linebytes) - sc->sc_height - 1, 278 sc->sc_width, 279 ri->ri_font->fontwidth, 280 ri->ri_font->fontheight, 281 defattr); 282 } 283 284 rasops_unpack_attr(defattr, &fg, &bg, &ul); 285 sc->sc_bg = ri->ri_devcmap[bg]; 286 chipsfb_clearscreen(sc); 287 288 if (console) 289 vcons_replay_msgbuf(&chipsfb_console_screen); 290 291 aprint_normal_dev(sc->sc_dev, "%d MB aperture, %d MB VRAM at 0x%08x\n", 292 (u_int)(sc->sc_fbsize >> 20), 293 (int)sc->memsize >> 20, (u_int)sc->sc_fb); 294#ifdef CHIPSFB_DEBUG 295 aprint_debug("fb: %08lx\n", (ulong)ri->ri_bits); 296#endif 297 298 j = 0; 299 rasops_get_cmap(ri, cmap, sizeof(cmap)); 300 for (i = 0; i < 256; i++) { 301 chipsfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 302 j += 3; 303 } 304 305 aa.console = console; 306 aa.scrdata = &chipsfb_screenlist; 307 aa.accessops = &chipsfb_accessops; 308 aa.accesscookie = &sc->vd; 309 310 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 311} 312 313static int 314chipsfb_putpalreg(struct chipsfb_softc *sc, uint8_t index, uint8_t r, 315 uint8_t g, uint8_t b) 316{ 317 318 sc->sc_cmap_red[index] = r; 319 sc->sc_cmap_green[index] = g; 320 sc->sc_cmap_blue[index] = b; 321 322 chipsfb_write_vga(sc, CT_DACMASK, 0xff); 323 chipsfb_write_vga(sc, CT_WRITEINDEX, index); 324 chipsfb_write_vga(sc, CT_DACDATA, r); 325 chipsfb_write_vga(sc, CT_DACDATA, g); 326 chipsfb_write_vga(sc, CT_DACDATA, b); 327 328 return 0; 329} 330 331static int 332chipsfb_putcmap(struct chipsfb_softc *sc, struct wsdisplay_cmap *cm) 333{ 334 u_char *r, *g, *b; 335 u_int index = cm->index; 336 u_int count = cm->count; 337 int i, error; 338 u_char rbuf[256], gbuf[256], bbuf[256]; 339 340#ifdef CHIPSFB_DEBUG 341 aprint_debug("putcmap: %d %d\n",index, count); 342#endif 343 if (cm->index >= 256 || cm->count > 256 || 344 (cm->index + cm->count) > 256) 345 return EINVAL; 346 error = copyin(cm->red, &rbuf[index], count); 347 if (error) 348 return error; 349 error = copyin(cm->green, &gbuf[index], count); 350 if (error) 351 return error; 352 error = copyin(cm->blue, &bbuf[index], count); 353 if (error) 354 return error; 355 356 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 357 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 358 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 359 360 r = &sc->sc_cmap_red[index]; 361 g = &sc->sc_cmap_green[index]; 362 b = &sc->sc_cmap_blue[index]; 363 364 for (i = 0; i < count; i++) { 365 chipsfb_putpalreg(sc, index, *r, *g, *b); 366 index++; 367 r++, g++, b++; 368 } 369 return 0; 370} 371 372static int 373chipsfb_getcmap(struct chipsfb_softc *sc, struct wsdisplay_cmap *cm) 374{ 375 u_int index = cm->index; 376 u_int count = cm->count; 377 int error; 378 379 if (index >= 255 || count > 256 || index + count > 256) 380 return EINVAL; 381 382 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 383 if (error) 384 return error; 385 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 386 if (error) 387 return error; 388 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 389 if (error) 390 return error; 391 392 return 0; 393} 394 395static void 396chipsfb_clearscreen(struct chipsfb_softc *sc) 397{ 398 chipsfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, sc->sc_bg); 399} 400 401/* 402 * wsdisplay_emulops 403 */ 404 405static void 406chipsfb_cursor(void *cookie, int on, int row, int col) 407{ 408 struct rasops_info *ri = cookie; 409 struct vcons_screen *scr = ri->ri_hw; 410 struct chipsfb_softc *sc = scr->scr_cookie; 411 int x, y, wi, he; 412 413 wi = ri->ri_font->fontwidth; 414 he = ri->ri_font->fontheight; 415 416 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 417 x = ri->ri_ccol * wi + ri->ri_xorigin; 418 y = ri->ri_crow * he + ri->ri_yorigin; 419 if (ri->ri_flg & RI_CURSOR) { 420 chipsfb_bitblt(sc, x, y, x, y, wi, he, ROP_NOT_DST); 421 ri->ri_flg &= ~RI_CURSOR; 422 } 423 ri->ri_crow = row; 424 ri->ri_ccol = col; 425 if (on) { 426 x = ri->ri_ccol * wi + ri->ri_xorigin; 427 y = ri->ri_crow * he + ri->ri_yorigin; 428 chipsfb_bitblt(sc, x, y, x, y, wi, he, ROP_NOT_DST); 429 ri->ri_flg |= RI_CURSOR; 430 } 431 } else { 432 ri->ri_flg &= ~RI_CURSOR; 433 ri->ri_crow = row; 434 ri->ri_ccol = col; 435 } 436} 437 438#if 0 439int 440chipsfb_mapchar(void *cookie, int uni, u_int *index) 441{ 442 return 0; 443} 444#endif 445 446static void 447chipsfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 448{ 449 struct rasops_info *ri = cookie; 450 struct vcons_screen *scr = ri->ri_hw; 451 struct chipsfb_softc *sc = scr->scr_cookie; 452 int32_t xs, xd, y, width, height; 453 454 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 455 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 456 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 457 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 458 width = ri->ri_font->fontwidth * ncols; 459 height = ri->ri_font->fontheight; 460 chipsfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY); 461 } 462} 463 464static void 465chipsfb_erasecols(void *cookie, int row, int startcol, int ncols, 466 long fillattr) 467{ 468 struct rasops_info *ri = cookie; 469 struct vcons_screen *scr = ri->ri_hw; 470 struct chipsfb_softc *sc = scr->scr_cookie; 471 int32_t x, y, width, height, fg, bg, ul; 472 473 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 474 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 475 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 476 width = ri->ri_font->fontwidth * ncols; 477 height = ri->ri_font->fontheight; 478 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 479 480 chipsfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 481 } 482} 483 484static void 485chipsfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 486{ 487 struct rasops_info *ri = cookie; 488 struct vcons_screen *scr = ri->ri_hw; 489 struct chipsfb_softc *sc = scr->scr_cookie; 490 int32_t x, ys, yd, width, height; 491 492 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 493 x = ri->ri_xorigin; 494 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 495 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 496 width = ri->ri_emuwidth; 497 height = ri->ri_font->fontheight * nrows; 498 chipsfb_bitblt(sc, x, ys, x, yd, width, height, ROP_COPY); 499 } 500} 501 502static void 503chipsfb_eraserows(void *cookie, int row, int nrows, long fillattr) 504{ 505 struct rasops_info *ri = cookie; 506 struct vcons_screen *scr = ri->ri_hw; 507 struct chipsfb_softc *sc = scr->scr_cookie; 508 int32_t x, y, width, height, fg, bg, ul; 509 510 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 511 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 512 if ((row == 0) && (nrows == ri->ri_rows)) { 513 /* clear the whole screen */ 514 chipsfb_rectfill(sc, 0, 0, ri->ri_width, 515 ri->ri_height, ri->ri_devcmap[bg]); 516 } else { 517 x = ri->ri_xorigin; 518 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 519 width = ri->ri_emuwidth; 520 height = ri->ri_font->fontheight * nrows; 521 chipsfb_rectfill(sc, x, y, width, height, 522 ri->ri_devcmap[bg]); 523 } 524 } 525} 526 527static void 528chipsfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, 529 int width, int height, int rop) 530{ 531 struct chipsfb_softc *sc = cookie; 532 uint32_t src, dst, cmd = rop, stride, size; 533 534 cmd |= BLT_PAT_IS_SOLID; 535 536 /* we assume 8 bit for now */ 537 src = xs + ys * sc->sc_linebytes; 538 dst = xd + yd * sc->sc_linebytes; 539 540 if (xs < xd) { 541 /* right-to-left operation */ 542 cmd |= BLT_START_RIGHT; 543 src += width - 1; 544 dst += width - 1; 545 } 546 547 if (ys < yd) { 548 /* bottom-to-top operation */ 549 cmd |= BLT_START_BOTTOM; 550 src += (height - 1) * sc->sc_linebytes; 551 dst += (height - 1) * sc->sc_linebytes; 552 } 553 554 stride = (sc->sc_linebytes << 16) | sc->sc_linebytes; 555 size = (height << 16) | width; 556 557 chipsfb_wait_idle(sc); 558 chipsfb_write32(sc, CT_BLT_STRIDE, stride); 559 chipsfb_write32(sc, CT_BLT_SRCADDR, src); 560 chipsfb_write32(sc, CT_BLT_DSTADDR, dst); 561 chipsfb_write32(sc, CT_BLT_CONTROL, cmd); 562 chipsfb_write32(sc, CT_BLT_SIZE, size); 563#ifdef CHIPSFB_WAIT 564 chipsfb_wait_idle(sc); 565#endif 566} 567 568static void 569chipsfb_rectfill(struct chipsfb_softc *sc, int x, int y, int width, 570 int height, int colour) 571{ 572 uint32_t dst, cmd, stride, size; 573 574 cmd = BLT_PAT_IS_SOLID | BLT_PAT_IS_MONO | ROP_PAT; 575 576 /* we assume 8 bit for now */ 577 dst = x + y * sc->sc_linebytes; 578 579 stride = (sc->sc_linebytes << 16) | sc->sc_linebytes; 580 size = (height << 16) | width; 581 582 chipsfb_wait_idle(sc); 583 chipsfb_write32(sc, CT_BLT_STRIDE, stride); 584 chipsfb_write32(sc, CT_BLT_SRCADDR, dst); 585 chipsfb_write32(sc, CT_BLT_DSTADDR, dst); 586 chipsfb_write32(sc, CT_BLT_CONTROL, cmd); 587 chipsfb_write32(sc, CT_BLT_BG, colour); 588 chipsfb_write32(sc, CT_BLT_FG, colour); 589 chipsfb_write32(sc, CT_BLT_SIZE, size); 590#ifdef CHIPSFB_WAIT 591 chipsfb_wait_idle(sc); 592#endif 593} 594 595static void 596chipsfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 597{ 598 struct rasops_info *ri = cookie; 599 struct wsdisplay_font *font = PICK_FONT(ri, c); 600 struct vcons_screen *scr = ri->ri_hw; 601 struct chipsfb_softc *sc = scr->scr_cookie; 602 uint32_t bg, latch = 0, bg8, fg8, pixel, dst, stride, size; 603 int i, l, x, y, wi, he, r, g, b, aval; 604 int r1, g1, b1, r0, g0, b0, fgo, bgo, off, pad; 605 uint8_t *data8; 606 int rv; 607 608 if (__predict_false((unsigned int)row > ri->ri_rows || 609 (unsigned int)col > ri->ri_cols)) 610 return; 611 612 if (__predict_false((sc->sc_mode != WSDISPLAYIO_MODE_EMUL))) 613 return; 614 615 if (__predict_false((!CHAR_IN_FONT(c, font)))) 616 return; 617 618 wi = font->fontwidth; 619 he = font->fontheight; 620 621 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 622 x = ri->ri_xorigin + col * wi; 623 y = ri->ri_yorigin + row * he; 624 625 if (c == 0x20) { 626 chipsfb_rectfill(sc, x, y, wi, he, bg); 627 return; 628 } 629 630 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 631 if (rv == GC_OK) 632 return; 633 634 data8 = WSFONT_GLYPH(c, font); 635 636 /* we assume 8 bit for now */ 637 dst = x + y * sc->sc_linebytes; 638 639 stride = sc->sc_linebytes << 16; 640 size = (he << 16) | wi; 641 642 /* set up for host blit */ 643 chipsfb_wait_idle(sc); 644 chipsfb_write32(sc, CT_BLT_STRIDE, stride); 645 chipsfb_write32(sc, CT_BLT_DSTADDR, dst); 646 chipsfb_write32(sc, CT_BLT_SRCADDR, 0); 647 chipsfb_write32(sc, CT_BLT_CONTROL, 648 BLT_PAT_IS_SOLID | BLT_SRC_IS_CPU | ROP_COPY); 649 chipsfb_write32(sc, CT_BLT_SIZE, size); 650 651 /* 652 * we need the RGB colours here, so get offsets into rasops_cmap 653 */ 654 fgo = ((attr >> 24) & 0xf) * 3; 655 bgo = ((attr >> 16) & 0xf) * 3; 656 657 r0 = rasops_cmap[bgo]; 658 r1 = rasops_cmap[fgo]; 659 g0 = rasops_cmap[bgo + 1]; 660 g1 = rasops_cmap[fgo + 1]; 661 b0 = rasops_cmap[bgo + 2]; 662 b1 = rasops_cmap[fgo + 2]; 663#define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 664 bg8 = R3G3B2(r0, g0, b0); 665 fg8 = R3G3B2(r1, g1, b1); 666 667 /* see if we need to pad lines to 64bit */ 668 pad = (wi + 3) & 4; 669 for (l = 0; l < he; l++) { 670 off = 0; 671 latch = 0; 672 for (i = 0; i < wi; i++) { 673 aval = *data8; 674 if (aval == 0) { 675 pixel = bg8; 676 } else if (aval == 255) { 677 pixel = fg8; 678 } else { 679 r = aval * r1 + (255 - aval) * r0; 680 g = aval * g1 + (255 - aval) * g0; 681 b = aval * b1 + (255 - aval) * b0; 682 pixel = ((r & 0xe000) >> 8) | 683 ((g & 0xe000) >> 11) | 684 ((b & 0xc000) >> 14); 685 } 686 latch |= pixel << off; 687 off += 8; 688 /* write in 32bit chunks */ 689 if ((i & 3) == 3) { 690 chipsfb_write32(sc, 691 CT_OFF_DATA - CT_OFF_BITBLT, latch); 692 latch = 0; 693 off = 0; 694 } 695 data8++; 696 } 697 /* if we have pixels left in latch write them out */ 698 if ((i & 3) != 0) { 699 chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, latch); 700 } 701 /* this chip needs scanlines 64bit aligned */ 702 if (pad) chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, 0); 703 } 704 705 if (rv == GC_ADD) { 706 glyphcache_add(&sc->sc_gc, c, x, y); 707 } 708} 709 710static void 711chipsfb_putchar(void *cookie, int row, int col, u_int c, long attr) 712{ 713 struct rasops_info *ri = cookie; 714 struct wsdisplay_font *font = PICK_FONT(ri, c); 715 struct vcons_screen *scr = ri->ri_hw; 716 struct chipsfb_softc *sc = scr->scr_cookie; 717 718 if (__predict_false((unsigned int)row > ri->ri_rows || 719 (unsigned int)col > ri->ri_cols)) 720 return; 721 722 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 723 uint8_t *data; 724 int fg, bg, uc; 725 int x, y, wi, he; 726 727 wi = font->fontwidth; 728 he = font->fontheight; 729 730 if (!CHAR_IN_FONT(c, font)) 731 return; 732 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf]; 733 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf]; 734 x = ri->ri_xorigin + col * wi; 735 y = ri->ri_yorigin + row * he; 736 if (c == 0x20) { 737 chipsfb_rectfill(sc, x, y, wi, he, bg); 738 } else { 739 uc = c - font->firstchar; 740 data = (uint8_t *)font->data + uc * 741 ri->ri_fontscale; 742 chipsfb_setup_mono(sc, x, y, wi, he, fg, bg); 743 chipsfb_feed(sc, font->stride * he, data); 744 } 745 } 746} 747 748static void 749chipsfb_setup_mono(struct chipsfb_softc *sc, int xd, int yd, int width, 750 int height, uint32_t fg, uint32_t bg) 751{ 752 uint32_t dst, cmd, stride, size; 753 754 cmd = BLT_PAT_IS_SOLID | BLT_SRC_IS_CPU | BLT_SRC_IS_MONO | ROP_COPY; 755 756 /* we assume 8 bit for now */ 757 dst = xd + yd * sc->sc_linebytes; 758 759 stride = (sc->sc_linebytes << 16); 760 size = (height << 16) | width; 761 762 chipsfb_wait_idle(sc); 763 chipsfb_write32(sc, CT_BLT_STRIDE, stride); 764 chipsfb_write32(sc, CT_BLT_DSTADDR, dst); 765 chipsfb_write32(sc, CT_BLT_SRCADDR, 0); 766 chipsfb_write32(sc, CT_BLT_CONTROL, cmd); 767 chipsfb_write32(sc, CT_BLT_BG, bg); 768 chipsfb_write32(sc, CT_BLT_FG, fg); 769 chipsfb_write32(sc, CT_BLT_SIZE, size); 770} 771 772static void 773chipsfb_feed(struct chipsfb_softc *sc, int count, uint8_t *data) 774{ 775 int i; 776 uint32_t latch = 0, bork; 777 int shift = 0; 778 779 for (i = 0; i < count; i++) { 780 bork = data[i]; 781 latch |= (bork << shift); 782 if (shift == 24) { 783 chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, latch); 784 latch = 0; 785 shift = 0; 786 } else 787 shift += 8; 788 } 789 790 if (shift != 0) { 791 chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, latch); 792 } 793 794 /* apparently the chip wants 64bit-aligned data or it won't go idle */ 795 if ((count + 3) & 0x04) { 796 chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, 0); 797 } 798#ifdef CHIPSFB_WAIT 799 chipsfb_wait_idle(sc); 800#endif 801} 802 803#if 0 804static void 805chipsfb_showpal(struct chipsfb_softc *sc) 806{ 807 int i, x = 0; 808 809 for (i = 0; i < 16; i++) { 810 chipsfb_rectfill(sc, x, 0, 64, 64, i); 811 x += 64; 812 } 813} 814#endif 815 816#if 0 817static int 818chipsfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 819{ 820 821 return 0; 822} 823#endif 824 825static void 826chipsfb_restore_palette(struct chipsfb_softc *sc) 827{ 828 int i; 829 830 for (i = 0; i < 256; i++) { 831 chipsfb_putpalreg(sc, 832 i, 833 sc->sc_cmap_red[i], 834 sc->sc_cmap_green[i], 835 sc->sc_cmap_blue[i]); 836 } 837} 838 839/* 840 * wsdisplay_accessops 841 */ 842 843static int 844chipsfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 845 struct lwp *l) 846{ 847 struct vcons_data *vd = v; 848 struct chipsfb_softc *sc = vd->cookie; 849 struct wsdisplay_fbinfo *wdf; 850 struct vcons_screen *ms = vd->active; 851 852 switch (cmd) { 853 case WSDISPLAYIO_GTYPE: 854 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 855 return 0; 856 857 case WSDISPLAYIO_GINFO: 858 wdf = (void *)data; 859 wdf->height = ms->scr_ri.ri_height; 860 wdf->width = ms->scr_ri.ri_width; 861 wdf->depth = ms->scr_ri.ri_depth; 862 wdf->cmsize = 256; 863 return 0; 864 865 case WSDISPLAYIO_GETCMAP: 866 return chipsfb_getcmap(sc, 867 (struct wsdisplay_cmap *)data); 868 869 case WSDISPLAYIO_PUTCMAP: 870 return chipsfb_putcmap(sc, 871 (struct wsdisplay_cmap *)data); 872 873 874 case WSDISPLAYIO_SMODE: { 875 int new_mode = *(int*)data; 876 if (new_mode != sc->sc_mode) { 877 sc->sc_mode = new_mode; 878 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 879 chipsfb_init(sc); 880 chipsfb_restore_palette(sc); 881 glyphcache_wipe(&sc->sc_gc); 882 vcons_redraw_screen(ms); 883 } 884 } 885 } 886 return 0; 887 888 case WSDISPLAYIO_GET_FBINFO: { 889 struct wsdisplayio_fbinfo *fbi = data; 890 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 891 } 892 893 default: 894 if (sc->sc_ioctl != NULL) 895 return sc->sc_ioctl(v, vs, cmd, data, flag, l); 896 } 897 return EPASSTHROUGH; 898} 899 900static paddr_t 901chipsfb_mmap(void *v, void *vs, off_t offset, int prot) 902{ 903 struct vcons_data *vd = v; 904 struct chipsfb_softc *sc = vd->cookie; 905 paddr_t pa; 906 907 if (sc->sc_mmap != NULL) { 908 pa = sc->sc_mmap(v, vs, offset, prot); 909 if (pa != -1) return pa; 910 } 911 912 /* 'regular' framebuffer mmap()ing */ 913 if (offset < sc->memsize) { 914 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb, offset, prot, 915 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 916 return pa; 917 } 918 919 /* 920 * restrict all other mappings to processes with superuser privileges 921 * or the kernel itself 922 */ 923 if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM, 924 NULL, NULL, NULL, NULL) != 0) { 925 aprint_normal_dev(sc->sc_dev, "mmap() rejected.\n"); 926 return -1; 927 } 928 929 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 930 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 931 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 932 return pa; 933 } 934 935#ifdef PCI_MAGIC_IO_RANGE 936 /* allow mapping of IO space */ 937 if ((offset >= PCI_MAGIC_IO_RANGE) && 938 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) { 939 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE, 940 0, prot, BUS_SPACE_MAP_LINEAR); 941 return pa; 942 } 943#endif 944 945 return -1; 946} 947 948static void 949chipsfb_init_screen(void *cookie, struct vcons_screen *scr, 950 int existing, long *defattr) 951{ 952 struct chipsfb_softc *sc = cookie; 953 struct rasops_info *ri = &scr->scr_ri; 954 955 ri->ri_depth = sc->sc_bits_per_pixel; 956 ri->ri_width = sc->sc_width; 957 ri->ri_height = sc->sc_height; 958 ri->ri_stride = sc->sc_width; 959 ri->ri_flg = RI_CENTER | RI_FULLCLEAR | 960 RI_8BIT_IS_RGB | RI_ENABLE_ALPHA; 961 962 ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_fbh); 963 964#ifdef CHIPSFB_DEBUG 965 aprint_debug("addr: %08lx\n", (ulong)ri->ri_bits); 966#endif 967 if (existing) { 968 ri->ri_flg |= RI_CLEAR; 969 } 970 971 rasops_init(ri, 0, 0); 972 ri->ri_caps = WSSCREEN_WSCOLORS; 973 974 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 975 sc->sc_width / ri->ri_font->fontwidth); 976 977 ri->ri_hw = scr; 978 ri->ri_ops.copyrows = chipsfb_copyrows; 979 ri->ri_ops.copycols = chipsfb_copycols; 980 ri->ri_ops.eraserows = chipsfb_eraserows; 981 ri->ri_ops.erasecols = chipsfb_erasecols; 982 ri->ri_ops.cursor = chipsfb_cursor; 983 if (FONT_IS_ALPHA(ri->ri_font)) { 984 ri->ri_ops.putchar = chipsfb_putchar_aa; 985 } else 986 ri->ri_ops.putchar = chipsfb_putchar; 987} 988 989#if 0 990int 991chipsfb_load_font(void *v, void *cookie, struct wsdisplay_font *data) 992{ 993 994 return 0; 995} 996#endif 997 998static void 999chipsfb_init(struct chipsfb_softc *sc) 1000{ 1001 uint8_t reg; 1002 1003 chipsfb_wait_idle(sc); 1004 1005 /* setup the blitter */ 1006 chipsfb_write32(sc, CT_BLT_EXPCTL, MONO_SRC_ALIGN_BYTE); 1007 1008 /* put DAC into 8bit mode */ 1009 reg = chipsfb_read_indexed(sc, CT_CONF_INDEX, XR_PIXEL_PIPELINE_CTL_0); 1010 reg |= ENABLE_8BIT_DAC; 1011 chipsfb_write_indexed(sc, CT_CONF_INDEX, XR_PIXEL_PIPELINE_CTL_0, reg); 1012} 1013 1014uint32_t 1015chipsfb_probe_vram(struct chipsfb_softc *sc) 1016{ 1017 uint32_t ofs = 0x00080000; /* 512kB */ 1018 1019 /* 1020 * advance in 0.5MB steps, see if we can read back what we wrote and 1021 * if what we wrote to 0 is left untouched. Max. fb size is 4MB so 1022 * we voluntarily stop there. 1023 */ 1024 bus_space_write_4(sc->sc_memt, sc->sc_fbh, 0, 0xf0f0f0f0); 1025 bus_space_write_4(sc->sc_memt, sc->sc_fbh, ofs, 0x0f0f0f0f); 1026 while ((bus_space_read_4(sc->sc_memt, sc->sc_fbh, 0) == 0xf0f0f0f0) && 1027 (bus_space_read_4(sc->sc_memt, sc->sc_fbh, ofs) == 0x0f0f0f0f) && 1028 (ofs < 0x00400000)) { 1029 1030 ofs += 0x00080000; 1031 bus_space_write_4(sc->sc_memt, sc->sc_fbh, ofs, 0x0f0f0f0f); 1032 } 1033 1034 return ofs; 1035} 1036