1 /* $NetBSD: hyperfb.c,v 1.1 2024/07/12 08:43:08 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2024 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 OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * a native driver for HCRX / hyperdrive cards 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: hyperfb.c,v 1.1 2024/07/12 08:43:08 macallan Exp $"); 35 36 #include "opt_cputype.h" 37 #include "opt_hyperfb.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 43 #include <sys/bus.h> 44 #include <machine/cpu.h> 45 #include <machine/iomod.h> 46 #include <machine/autoconf.h> 47 48 #include <dev/wscons/wsdisplayvar.h> 49 #include <dev/wscons/wsconsio.h> 50 #include <dev/wsfont/wsfont.h> 51 #include <dev/rasops/rasops.h> 52 #include <dev/wscons/wsdisplay_vconsvar.h> 53 #include <dev/wscons/wsdisplay_glyphcachevar.h> 54 55 #include <dev/ic/stireg.h> 56 #include <dev/ic/stivar.h> 57 58 #include <hppa/dev/cpudevs.h> 59 #include <hppa/hppa/machdep.h> 60 61 #ifdef HYPERFB_DEBUG 62 #define DPRINTF printf 63 #else 64 #define DPRINTF if (0) printf 65 #endif 66 67 #define STI_ROMSIZE (sizeof(struct sti_dd) * 4) 68 69 #define HCRX_FBOFFSET 0x01000000 70 #define HCRX_FBLEN 0x01000000 71 #define HCRX_REGOFFSET 0x00100000 72 #define HCRX_REGLEN 0x00280000 73 74 #define HCRX_CONFIG_24BIT 0x100 75 76 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4 77 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8 78 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10 79 #define HYPERBOWL_MODE2_8_24 15 80 81 int hyperfb_match(device_t, cfdata_t, void *); 82 void hyperfb_attach(device_t, device_t, void *); 83 84 struct hyperfb_softc { 85 device_t sc_dev; 86 bus_space_tag_t sc_iot; 87 bus_addr_t sc_base; 88 bus_space_handle_t sc_hfb, sc_hreg; 89 void *sc_fb; 90 91 int sc_width, sc_height; 92 int sc_locked, sc_is_console, sc_24bit; 93 struct vcons_screen sc_console_screen; 94 struct wsscreen_descr sc_defaultscreen_descr; 95 const struct wsscreen_descr *sc_screens[1]; 96 struct wsscreen_list sc_screenlist; 97 struct vcons_data vd; 98 int sc_mode; 99 void (*sc_putchar)(void *, int, int, u_int, long); 100 u_char sc_cmap_red[256]; 101 u_char sc_cmap_green[256]; 102 u_char sc_cmap_blue[256]; 103 kmutex_t sc_hwlock; 104 uint32_t sc_hwmode; 105 #define HW_FB 0 106 #define HW_FILL 1 107 #define HW_BLIT 2 108 uint32_t sc_rect_colour, sc_rect_height; 109 /* cursor stuff */ 110 int sc_cursor_x, sc_cursor_y; 111 int sc_hot_x, sc_hot_y, sc_enabled; 112 int sc_video_on; 113 glyphcache sc_gc; 114 }; 115 116 extern struct cfdriver hyperfb_cd; 117 118 CFATTACH_DECL_NEW(hyperfb, sizeof(struct hyperfb_softc), hyperfb_match, 119 hyperfb_attach, NULL, NULL); 120 121 void hyperfb_setup_fb(struct hyperfb_softc *); 122 static void hyperfb_init_screen(void *, struct vcons_screen *, 123 int, long *); 124 static int hyperfb_ioctl(void *, void *, u_long, void *, int, 125 struct lwp *); 126 static paddr_t hyperfb_mmap(void *, void *, off_t, int); 127 128 static int hyperfb_putcmap(struct hyperfb_softc *, struct wsdisplay_cmap *); 129 static int hyperfb_getcmap(struct hyperfb_softc *, struct wsdisplay_cmap *); 130 static void hyperfb_restore_palette(struct hyperfb_softc *); 131 static int hyperfb_putpalreg(struct hyperfb_softc *, uint8_t, uint8_t, 132 uint8_t, uint8_t); 133 void hyperfb_setup(struct hyperfb_softc *); 134 static void hyperfb_set_video(struct hyperfb_softc *, int); 135 136 #define ngle_bt458_write(sc, r, v) \ 137 hyperfb_write4(sc, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24) 138 139 struct wsdisplay_accessops hyperfb_accessops = { 140 hyperfb_ioctl, 141 hyperfb_mmap, 142 NULL, /* alloc_screen */ 143 NULL, /* free_screen */ 144 NULL, /* show_screen */ 145 NULL, /* load_font */ 146 NULL, /* pollc */ 147 NULL /* scroll */ 148 }; 149 150 static inline uint32_t 151 hyperfb_read4(struct hyperfb_softc *sc, uint32_t offset) 152 { 153 return bus_space_read_4(sc->sc_iot, sc->sc_hreg, offset); 154 } 155 156 static inline uint8_t 157 hyperfb_read1(struct hyperfb_softc *sc, uint32_t offset) 158 { 159 return bus_space_read_1(sc->sc_iot, sc->sc_hreg, offset); 160 } 161 162 static inline void 163 hyperfb_write4(struct hyperfb_softc *sc, uint32_t offset, uint32_t val) 164 { 165 bus_space_write_4(sc->sc_iot, sc->sc_hreg, offset, val); 166 } 167 168 static inline void 169 hyperfb_write1(struct hyperfb_softc *sc, uint32_t offset, uint8_t val) 170 { 171 bus_space_write_1(sc->sc_iot, sc->sc_hreg, offset, val); 172 } 173 174 static inline void 175 hyperfb_wait(struct hyperfb_softc *sc) 176 { 177 uint8_t stat; 178 179 do { 180 stat = hyperfb_read1(sc, NGLE_REG_15b0); 181 if (stat == 0) 182 stat = hyperfb_read1(sc, NGLE_REG_15b0); 183 } while (stat != 0); 184 } 185 186 void 187 hyperfb_setup_fb(struct hyperfb_softc *sc) 188 { 189 190 hyperfb_wait(sc); 191 hyperfb_write4(sc, NGLE_REG_10, 0x13602000); /* 8bit */ 192 hyperfb_write4(sc, NGLE_REG_14, 0x83000300); 193 hyperfb_wait(sc); 194 hyperfb_write1(sc, NGLE_REG_16b1, 1); 195 sc->sc_hwmode = HW_FB; 196 } 197 198 int 199 hyperfb_match(device_t parent, cfdata_t cf, void *aux) 200 { 201 struct confargs *ca = aux; 202 bus_space_handle_t romh; 203 paddr_t rom; 204 uint32_t id = 0; 205 u_char devtype; 206 int rv = 0, romunmapped = 0; 207 208 if (ca->ca_type.iodc_type != HPPA_TYPE_FIO) 209 return 0; 210 211 /* these need further checking for the graphics id */ 212 if (ca->ca_type.iodc_sv_model != HPPA_FIO_GSGC && 213 ca->ca_type.iodc_sv_model != HPPA_FIO_SGC) 214 return 0; 215 216 if (ca->ca_naddrs > 0) 217 rom = ca->ca_addrs[0].addr; 218 else 219 rom = ca->ca_hpa; 220 221 DPRINTF("%s: hpa=%x, rom=%x\n", __func__, (uint)ca->ca_hpa, 222 (uint)rom); 223 224 /* if it does not map, probably part of the lasi space */ 225 if (bus_space_map(ca->ca_iot, rom, STI_ROMSIZE, 0, &romh)) { 226 DPRINTF("%s: can't map rom space (%d)\n", __func__, rv); 227 228 if ((rom & HPPA_IOBEGIN) == HPPA_IOBEGIN) { 229 romh = rom; 230 romunmapped++; 231 } else { 232 /* in this case nobody has no freaking idea */ 233 return 0; 234 } 235 } 236 237 devtype = bus_space_read_1(ca->ca_iot, romh, 3); 238 DPRINTF("%s: devtype=%d\n", __func__, devtype); 239 rv = 1; 240 switch (devtype) { 241 case STI_DEVTYPE4: 242 id = bus_space_read_4(ca->ca_iot, romh, STI_DEV4_DD_GRID); 243 break; 244 case STI_DEVTYPE1: 245 id = (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 246 + 3) << 24) | 247 (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 248 + 7) << 16) | 249 (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 250 + 11) << 8) | 251 (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID 252 + 15)); 253 break; 254 default: 255 DPRINTF("%s: unknown type (%x)\n", __func__, devtype); 256 rv = 0; 257 } 258 259 if (id == STI_DD_HCRX) 260 rv = 100; /* beat out sti */ 261 262 ca->ca_addrs[ca->ca_naddrs].addr = rom; 263 ca->ca_addrs[ca->ca_naddrs].size = sti_rom_size(ca->ca_iot, romh); 264 ca->ca_naddrs++; 265 266 if (!romunmapped) 267 bus_space_unmap(ca->ca_iot, romh, STI_ROMSIZE); 268 return rv; 269 } 270 271 void 272 hyperfb_attach(device_t parent, device_t self, void *aux) 273 { 274 struct hyperfb_softc *sc = device_private(self); 275 struct confargs *ca = aux; 276 struct rasops_info *ri; 277 struct wsemuldisplaydev_attach_args aa; 278 bus_space_handle_t hrom; 279 hppa_hpa_t consaddr; 280 long defattr; 281 int pagezero_cookie; 282 paddr_t rom; 283 uint32_t config; 284 285 pagezero_cookie = hppa_pagezero_map(); 286 consaddr = (hppa_hpa_t)PAGE0->mem_cons.pz_hpa; 287 hppa_pagezero_unmap(pagezero_cookie); 288 289 sc->sc_dev = self; 290 sc->sc_base = ca->ca_hpa; 291 sc->sc_iot = ca->ca_iot; 292 sc->sc_is_console =(ca->ca_hpa == consaddr); 293 sc->sc_width = 1280; 294 sc->sc_height = 1024; 295 296 /* we can *not* be interrupted when doing colour map accesses */ 297 mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH); 298 299 /* we stashed rom addr/len into the last slot during probe */ 300 rom = ca->ca_addrs[ca->ca_naddrs - 1].addr; 301 302 if (bus_space_map(sc->sc_iot, 303 sc->sc_base + HCRX_FBOFFSET, HCRX_FBLEN, 304 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, 305 &sc->sc_hfb)) { 306 aprint_error_dev(sc->sc_dev, "failed to map the framebuffer\n"); 307 return; 308 } 309 sc->sc_fb = bus_space_vaddr(sc->sc_iot, sc->sc_hfb); 310 311 if (bus_space_map(sc->sc_iot, 312 sc->sc_base + HCRX_REGOFFSET, HCRX_REGLEN, 0, &sc->sc_hreg)) { 313 aprint_error_dev(sc->sc_dev, "failed to map registers\n"); 314 return; 315 } 316 317 /* 318 * we really only need the first word so we can grab the config bits 319 * between the bytes 320 */ 321 if (bus_space_map(sc->sc_iot, 322 rom, 4, 0, &hrom)) { 323 aprint_error_dev(sc->sc_dev, "failed to map ROM, assuming 8bit\n"); 324 config = 0; 325 } else { 326 /* alright, we got the ROM. now do the idle dance. */ 327 volatile uint32_t r = hyperfb_read4(sc, NGLE_REG_15); 328 __USE(r); 329 hyperfb_wait(sc); 330 config = bus_space_read_4(sc->sc_iot, hrom, 0); 331 bus_space_unmap(sc->sc_iot, hrom, 4); 332 } 333 sc->sc_24bit = ((config & HCRX_CONFIG_24BIT) != 0); 334 335 printf(" %s\n", sc->sc_24bit ? "HCRX24" : "HCRX"); 336 #ifdef HP7300LC_CPU 337 /* 338 * PCXL2: enable accel I/O for this space, see PCX-L2 ERS "ACCEL_IO". 339 * "pcxl2_ers.{ps,pdf}", (section / chapter . rel. page / abs. page) 340 * 8.7.4 / 8-12 / 92, 11.3.14 / 11-14 / 122 and 14.8 / 14-5 / 203. 341 */ 342 if (hppa_cpu_info->hci_cputype == hpcxl2 343 && ca->ca_hpa >= PCXL2_ACCEL_IO_START 344 && ca->ca_hpa <= PCXL2_ACCEL_IO_END) 345 eaio_l2(PCXL2_ACCEL_IO_ADDR2MASK(ca->ca_hpa)); 346 #endif /* HP7300LC_CPU */ 347 348 hyperfb_setup(sc); 349 hyperfb_setup_fb(sc); 350 351 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 352 "default", 353 0, 0, 354 NULL, 355 8, 16, 356 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 357 WSSCREEN_RESIZE, 358 NULL 359 }; 360 361 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 362 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 363 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 364 sc->sc_locked = 0; 365 366 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 367 &hyperfb_accessops); 368 sc->vd.init_screen = hyperfb_init_screen; 369 sc->vd.show_screen_cookie = &sc->sc_gc; 370 sc->vd.show_screen_cb = glyphcache_adapt; 371 372 ri = &sc->sc_console_screen.scr_ri; 373 374 //sc->sc_gc.gc_bitblt = hyperfb_bitblt; 375 //sc->sc_gc.gc_blitcookie = sc; 376 //sc->sc_gc.gc_rop = RopSrc; 377 378 if (sc->sc_is_console) { 379 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 380 &defattr); 381 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 382 383 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 384 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 385 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 386 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 387 388 #if 0 389 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 390 sc->sc_scr.fbheight - sc->sc_height - 5, 391 sc->sc_scr.fbwidth, 392 ri->ri_font->fontwidth, 393 ri->ri_font->fontheight, 394 defattr); 395 #endif 396 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 397 defattr); 398 #if 0 399 hyperfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 400 ri->ri_devcmap[(defattr >> 16) & 0xff]); 401 #endif 402 vcons_replay_msgbuf(&sc->sc_console_screen); 403 } else { 404 /* 405 * since we're not the console we can postpone the rest 406 * until someone actually allocates a screen for us 407 */ 408 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 409 /* do some minimal setup to avoid weirdnesses later */ 410 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 411 &defattr); 412 } else 413 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 414 415 #if 0 416 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 417 sc->sc_scr.fbheight - sc->sc_height - 5, 418 sc->sc_scr.fbwidth, 419 ri->ri_font->fontwidth, 420 ri->ri_font->fontheight, 421 defattr); 422 #endif 423 } 424 425 hyperfb_restore_palette(sc); 426 427 /* no suspend/resume support yet */ 428 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 429 aprint_error_dev(sc->sc_dev, 430 "couldn't establish power handler\n"); 431 432 aa.console = sc->sc_is_console; 433 aa.scrdata = &sc->sc_screenlist; 434 aa.accessops = &hyperfb_accessops; 435 aa.accesscookie = &sc->vd; 436 437 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE); 438 439 } 440 441 static void 442 hyperfb_init_screen(void *cookie, struct vcons_screen *scr, 443 int existing, long *defattr) 444 { 445 struct hyperfb_softc *sc = cookie; 446 struct rasops_info *ri = &scr->scr_ri; 447 448 ri->ri_depth = 8; 449 ri->ri_width = 1280; 450 ri->ri_height = 1024; 451 ri->ri_stride = 2048; 452 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB /*| 453 RI_ENABLE_ALPHA | RI_PREFER_ALPHA*/; 454 455 ri->ri_bits = (void *)sc->sc_fb; 456 rasops_init(ri, 0, 0); 457 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 458 WSSCREEN_RESIZE; 459 scr->scr_flags |= VCONS_LOADFONT | VCONS_DONT_READ; 460 461 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 462 sc->sc_width / ri->ri_font->fontwidth); 463 464 ri->ri_hw = scr; 465 #if 0 466 sc->sc_putchar = ri->ri_ops.putchar; 467 ri->ri_ops.copyrows = gftfb_copyrows; 468 ri->ri_ops.copycols = gftfb_copycols; 469 ri->ri_ops.eraserows = gftfb_eraserows; 470 ri->ri_ops.erasecols = gftfb_erasecols; 471 ri->ri_ops.cursor = gftfb_cursor; 472 ri->ri_ops.putchar = gftfb_putchar; 473 #endif 474 } 475 476 static int 477 hyperfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 478 struct lwp *l) 479 { 480 struct vcons_data *vd = v; 481 struct hyperfb_softc *sc = vd->cookie; 482 struct wsdisplay_fbinfo *wdf; 483 struct vcons_screen *ms = vd->active; 484 485 switch (cmd) { 486 case WSDISPLAYIO_GTYPE: 487 *(u_int *)data = WSDISPLAY_TYPE_STI; 488 return 0; 489 490 case WSDISPLAYIO_GINFO: 491 if (ms == NULL) 492 return ENODEV; 493 wdf = (void *)data; 494 wdf->height = ms->scr_ri.ri_height; 495 wdf->width = ms->scr_ri.ri_width; 496 wdf->depth = ms->scr_ri.ri_depth; 497 wdf->cmsize = 256; 498 return 0; 499 500 case WSDISPLAYIO_GETCMAP: 501 return hyperfb_getcmap(sc, 502 (struct wsdisplay_cmap *)data); 503 504 case WSDISPLAYIO_PUTCMAP: 505 return hyperfb_putcmap(sc, 506 (struct wsdisplay_cmap *)data); 507 case WSDISPLAYIO_LINEBYTES: 508 *(u_int *)data = 2048; 509 return 0; 510 511 case WSDISPLAYIO_SMODE: { 512 int new_mode = *(int*)data; 513 if (new_mode != sc->sc_mode) { 514 sc->sc_mode = new_mode; 515 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 516 hyperfb_setup(sc); 517 hyperfb_restore_palette(sc); 518 #if 0 519 glyphcache_wipe(&sc->sc_gc); 520 hyperfb_rectfill(sc, 0, 0, sc->sc_width, 521 sc->sc_height, ms->scr_ri.ri_devcmap[ 522 (ms->scr_defattr >> 16) & 0xff]); 523 #endif 524 vcons_redraw_screen(ms); 525 hyperfb_set_video(sc, 1); 526 } 527 } 528 } 529 return 0; 530 531 case WSDISPLAYIO_GET_FBINFO: 532 { 533 struct wsdisplayio_fbinfo *fbi = data; 534 int ret; 535 536 ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 537 fbi->fbi_fbsize = sc->sc_height * 2048; 538 return ret; 539 } 540 541 #if 0 542 case WSDISPLAYIO_GCURPOS: 543 { 544 struct wsdisplay_curpos *cp = (void *)data; 545 546 cp->x = sc->sc_cursor_x; 547 cp->y = sc->sc_cursor_y; 548 } 549 return 0; 550 551 case WSDISPLAYIO_SCURPOS: 552 { 553 struct wsdisplay_curpos *cp = (void *)data; 554 555 gftfb_move_cursor(sc, cp->x, cp->y); 556 } 557 return 0; 558 559 case WSDISPLAYIO_GCURMAX: 560 { 561 struct wsdisplay_curpos *cp = (void *)data; 562 563 cp->x = 64; 564 cp->y = 64; 565 } 566 return 0; 567 568 case WSDISPLAYIO_SCURSOR: 569 { 570 struct wsdisplay_cursor *cursor = (void *)data; 571 572 return gftfb_do_cursor(sc, cursor); 573 } 574 #endif 575 576 case WSDISPLAYIO_SVIDEO: 577 hyperfb_set_video(sc, *(int *)data); 578 return 0; 579 case WSDISPLAYIO_GVIDEO: 580 return sc->sc_video_on ? 581 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 582 } 583 return EPASSTHROUGH; 584 } 585 586 static paddr_t 587 hyperfb_mmap(void *v, void *vs, off_t offset, int prot) 588 { 589 struct vcons_data *vd = v; 590 struct hyperfb_softc *sc = vd->cookie; 591 paddr_t pa = -1; 592 593 594 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) 595 return -1; 596 597 if (offset >= 0 || offset < 2048 * 1024) { 598 /* framebuffer */ 599 pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_FBOFFSET, offset, 600 prot, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 601 } else if (offset >= 0x80000000 && offset < 0x8040000) { 602 /* blitter registers etc. */ 603 pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_REGOFFSET, 604 offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR); 605 } 606 607 return pa; 608 } 609 610 static int 611 hyperfb_putcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm) 612 { 613 u_char *r, *g, *b; 614 u_int index = cm->index; 615 u_int count = cm->count; 616 int i, error; 617 u_char rbuf[256], gbuf[256], bbuf[256]; 618 619 if (cm->index >= 256 || cm->count > 256 || 620 (cm->index + cm->count) > 256) 621 return EINVAL; 622 error = copyin(cm->red, &rbuf[index], count); 623 if (error) 624 return error; 625 error = copyin(cm->green, &gbuf[index], count); 626 if (error) 627 return error; 628 error = copyin(cm->blue, &bbuf[index], count); 629 if (error) 630 return error; 631 632 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 633 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 634 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 635 636 r = &sc->sc_cmap_red[index]; 637 g = &sc->sc_cmap_green[index]; 638 b = &sc->sc_cmap_blue[index]; 639 640 for (i = 0; i < count; i++) { 641 hyperfb_putpalreg(sc, index, *r, *g, *b); 642 index++; 643 r++, g++, b++; 644 } 645 return 0; 646 } 647 648 static int 649 hyperfb_getcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm) 650 { 651 u_int index = cm->index; 652 u_int count = cm->count; 653 int error; 654 655 if (index >= 255 || count > 256 || index + count > 256) 656 return EINVAL; 657 658 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 659 if (error) 660 return error; 661 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 662 if (error) 663 return error; 664 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 665 if (error) 666 return error; 667 668 return 0; 669 } 670 671 static void 672 hyperfb_restore_palette(struct hyperfb_softc *sc) 673 { 674 uint8_t cmap[768]; 675 int i, j; 676 677 j = 0; 678 rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap)); 679 for (i = 0; i < 256; i++) { 680 sc->sc_cmap_red[i] = cmap[j]; 681 sc->sc_cmap_green[i] = cmap[j + 1]; 682 sc->sc_cmap_blue[i] = cmap[j + 2]; 683 hyperfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 684 j += 3; 685 } 686 } 687 688 static int 689 hyperfb_putpalreg(struct hyperfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 690 uint8_t b) 691 { 692 693 mutex_enter(&sc->sc_hwlock); 694 hyperfb_wait(sc); 695 hyperfb_write4(sc, NGLE_REG_10, 0xbbe0f000); 696 hyperfb_write4(sc, NGLE_REG_14, 0x03000300); 697 hyperfb_write4(sc, NGLE_REG_13, 0xffffffff); 698 699 hyperfb_wait(sc); 700 hyperfb_write4(sc, NGLE_REG_3, 0x400 | (idx << 2)); 701 hyperfb_write4(sc, NGLE_REG_4, (r << 16) | (g << 8) | b); 702 703 hyperfb_write4(sc, NGLE_REG_2, 0x400); 704 hyperfb_write4(sc, NGLE_REG_38, 0x82000100); 705 hyperfb_setup_fb(sc); 706 mutex_exit(&sc->sc_hwlock); 707 return 0; 708 } 709 710 void 711 hyperfb_setup(struct hyperfb_softc *sc) 712 { 713 int i; 714 uint32_t reg; 715 716 sc->sc_hwmode = HW_FB; 717 sc->sc_hot_x = 0; 718 sc->sc_hot_y = 0; 719 sc->sc_enabled = 0; 720 sc->sc_video_on = 1; 721 722 #if 0 723 sc->sc_rect_colour = 0xf0000000; 724 sc->sc_rect_height = 0; 725 #endif 726 727 /* set Bt458 read mask register to all planes */ 728 /* XXX I'm not sure HCRX even has one of these */ 729 hyperfb_wait(sc); 730 ngle_bt458_write(sc, 0x08, 0x04); 731 ngle_bt458_write(sc, 0x0a, 0xff); 732 733 reg = hyperfb_read4(sc, NGLE_REG_32); 734 DPRINTF("planereg %08x\n", reg); 735 hyperfb_write4(sc, NGLE_REG_32, 0xffff0000); 736 737 hyperfb_setup_fb(sc); 738 739 /* attr. planes */ 740 hyperfb_wait(sc); 741 hyperfb_write4(sc, NGLE_REG_11, 0x2ea0d000); 742 hyperfb_write4(sc, NGLE_REG_14, 0x23000302); 743 hyperfb_write4(sc, NGLE_REG_12, NGLE_BUFF1_CMAP0); 744 hyperfb_write4(sc, NGLE_REG_8, 0xffffffff); 745 746 hyperfb_wait(sc); 747 hyperfb_write4(sc, NGLE_REG_6, 0x00000000); 748 hyperfb_write4(sc, NGLE_REG_9, 749 (sc->sc_width << 16) | sc->sc_height); 750 /* 751 * blit into offscreen memory to force flush previous - apparently 752 * some chips have a bug this works around 753 */ 754 hyperfb_write4(sc, NGLE_REG_6, 0x05000000); 755 hyperfb_write4(sc, NGLE_REG_9, 0x00040001); 756 757 hyperfb_wait(sc); 758 hyperfb_write4(sc, NGLE_REG_12, 0x00000000); 759 760 hyperfb_setup_fb(sc); 761 762 /* make sure video output is enabled */ 763 hyperfb_wait(sc); 764 hyperfb_write4(sc, NGLE_REG_33, 765 hyperfb_read4(sc, NGLE_REG_33) | 0x0a000000); 766 767 /* hyperbowl */ 768 hyperfb_wait(sc); 769 if(sc->sc_24bit) { 770 /* write must happen twice because hw bug */ 771 hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE); 772 hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE); 773 hyperfb_write4(sc, NGLE_REG_39, HYPERBOWL_MODE2_8_24); 774 hyperfb_write4(sc, NGLE_REG_42, 0x014c0148); /* Set lut 0 to be the direct color */ 775 hyperfb_write4(sc, NGLE_REG_43, 0x404c4048); 776 hyperfb_write4(sc, NGLE_REG_44, 0x034c0348); 777 hyperfb_write4(sc, NGLE_REG_45, 0x444c4448); 778 } else { 779 hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES); 780 hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES); 781 782 hyperfb_write4(sc, NGLE_REG_42, 0); 783 hyperfb_write4(sc, NGLE_REG_43, 0); 784 hyperfb_write4(sc, NGLE_REG_44, 0); 785 hyperfb_write4(sc, NGLE_REG_45, 0); 786 } 787 /* cursor mask */ 788 hyperfb_wait(sc); 789 hyperfb_write4(sc, NGLE_REG_30, 0); 790 for (i = 0; i < 64; i++) { 791 hyperfb_write4(sc, NGLE_REG_31, 0xffffffff); 792 hyperfb_write4(sc, NGLE_REG_31, 0xffffffff); 793 } 794 795 /* cursor image */ 796 hyperfb_wait(sc); 797 hyperfb_write4(sc, NGLE_REG_30, 0x80); 798 for (i = 0; i < 64; i++) { 799 hyperfb_write4(sc, NGLE_REG_31, 0xff00ff00); 800 hyperfb_write4(sc, NGLE_REG_31, 0xff00ff00); 801 } 802 803 /* colour map - doesn't work yet*/ 804 hyperfb_wait(sc); 805 hyperfb_write4(sc, NGLE_REG_10, 0xBBE0F000); 806 hyperfb_write4(sc, NGLE_REG_14, 0x03000300); 807 hyperfb_write4(sc, NGLE_REG_13, 0xffffffff); 808 hyperfb_wait(sc); 809 hyperfb_write4(sc, NGLE_REG_3, 0); 810 hyperfb_write4(sc, NGLE_REG_4, 0); 811 hyperfb_write4(sc, NGLE_REG_4, 0); 812 hyperfb_write4(sc, NGLE_REG_4, 0x000000ff); /* BG */ 813 hyperfb_write4(sc, NGLE_REG_4, 0x00ff0000); /* FG */ 814 hyperfb_wait(sc); 815 hyperfb_write4(sc, NGLE_REG_2, 0); 816 hyperfb_write4(sc, NGLE_REG_1, 0x80008004); 817 hyperfb_setup_fb(sc); 818 819 //hyperfb_write4(sc, NGLE_REG_29, 0x80200020); 820 821 //gftfb_move_cursor(sc, 100, 100); 822 823 } 824 825 static void 826 hyperfb_set_video(struct hyperfb_softc *sc, int on) 827 { 828 uint32_t reg; 829 830 if (sc->sc_video_on == on) 831 return; 832 833 sc->sc_video_on = on; 834 835 hyperfb_wait(sc); 836 reg = hyperfb_read4(sc, NGLE_REG_33); 837 838 if (on) { 839 hyperfb_write4(sc, NGLE_REG_33, reg | 0x0a000000); 840 } else { 841 hyperfb_write4(sc, NGLE_REG_33, reg & ~0x0a000000); 842 } 843 } 844