1 /* $NetBSD: sti.c,v 1.39 2024/08/19 16:09:42 skrll Exp $ */ 2 3 /* $OpenBSD: sti.c,v 1.61 2009/09/05 14:09:35 miod Exp $ */ 4 5 /* 6 * Copyright (c) 2000-2003 Michael Shalayeff 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 /* 31 * TODO: 32 * call sti procs asynchronously; 33 * implement console scroll-back; 34 * X11 support on more models. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: sti.c,v 1.39 2024/08/19 16:09:42 skrll Exp $"); 39 40 #include "wsdisplay.h" 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <sys/bus.h> 50 51 #include <dev/wscons/wsdisplayvar.h> 52 #include <dev/wscons/wsconsio.h> 53 54 #include <dev/ic/stireg.h> 55 #include <dev/ic/stivar.h> 56 57 #ifdef STIDEBUG 58 59 #define DPRINTF(s) do { \ 60 if (stidebug) \ 61 printf s; \ 62 } while(0) 63 64 int stidebug = 1; 65 #else 66 #define DPRINTF(s) /* */ 67 #endif 68 69 void sti_cursor(void *, int, int, int); 70 int sti_mapchar(void *, int, u_int *); 71 void sti_putchar(void *, int, int, u_int, long); 72 void sti_copycols(void *, int, int, int, int); 73 void sti_erasecols(void *, int, int, int, long); 74 void sti_copyrows(void *, int, int, int); 75 void sti_eraserows(void *, int, int, long); 76 int sti_alloc_attr(void *, int, int, int, long *); 77 78 /* pseudo attribute ops for sti ROM putchar function */ 79 #define WSATTR_FG_SHIFT 24 80 #define WSATTR_BG_SHIFT 16 81 #define WSATTR_UNPACK_FG(attr) (((attr) >> WSATTR_FG_SHIFT) & 0xff) 82 #define WSATTR_UNPACK_BG(attr) (((attr) >> WSATTR_BG_SHIFT) & 0xff) 83 #define WSATTR_UNPACK_FLAG(attr) ((attr) & WSATTR_USERMASK) 84 #define WSATTR_PACK_FG(fg) ((fg) << WSATTR_FG_SHIFT) 85 #define WSATTR_PACK_BG(bg) ((bg) << WSATTR_BG_SHIFT) 86 #define WSATTR_PACK_FLAG(flag) ((flag)) 87 #define WSATTR_PACK(fg, bg, flag) \ 88 (WSATTR_PACK_FG(fg) | WSATTR_PACK_BG(bg) | WSATTR_PACK_FLAG(flag)) 89 90 struct wsdisplay_emulops sti_emulops = { 91 .cursor = sti_cursor, 92 .mapchar = sti_mapchar, 93 .putchar = sti_putchar, 94 .copycols = sti_copycols, 95 .erasecols = sti_erasecols, 96 .copyrows = sti_copyrows, 97 .eraserows = sti_eraserows, 98 .allocattr = sti_alloc_attr 99 }; 100 101 const struct wsdisplay_accessops sti_accessops = { 102 .ioctl = sti_ioctl, 103 .mmap = sti_mmap, 104 .alloc_screen = sti_alloc_screen, 105 .free_screen = sti_free_screen, 106 .show_screen = sti_show_screen, 107 .load_font = sti_load_font 108 }; 109 110 enum sti_bmove_funcs { 111 bmf_clear, bmf_copy, bmf_invert, bmf_underline 112 }; 113 114 void sti_bmove(struct sti_screen *, int, int, int, int, int, int, 115 enum sti_bmove_funcs); 116 int sti_inqcfg(struct sti_screen *, struct sti_inqconfout *); 117 int sti_setcment(struct sti_screen *, u_int, u_char, u_char, u_char); 118 119 struct sti_screen *sti_attach_screen(struct sti_softc *, int); 120 void sti_describe_screen(struct sti_softc *, struct sti_screen *); 121 122 int sti_fetchfonts(struct sti_screen *, struct sti_inqconfout *, uint32_t, 123 u_int); 124 void sti_region_setup(struct sti_screen *); 125 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t, 126 bus_space_handle_t, bus_addr_t *, u_int); 127 int sti_screen_setup(struct sti_screen *, int); 128 129 int ngle_default_putcmap(struct sti_screen *, u_int, u_int); 130 131 #ifndef SMALL_KERNEL 132 void ngle_artist_setupfb(struct sti_screen *); 133 void ngle_elk_setupfb(struct sti_screen *); 134 void ngle_timber_setupfb(struct sti_screen *); 135 int ngle_putcmap(struct sti_screen *, u_int, u_int); 136 int ngle_hcrx_putcmap(struct sti_screen *, u_int, u_int); 137 #endif 138 139 #define STI_ENABLE_ROM(sc) \ 140 do { \ 141 if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \ 142 (*(sc)->sc_enable_rom)(sc); \ 143 } while (0) 144 #define STI_DISABLE_ROM(sc) \ 145 do { \ 146 if ((sc) != NULL && (sc)->sc_disable_rom != NULL) \ 147 (*(sc)->sc_disable_rom)(sc); \ 148 } while (0) 149 150 /* Macros to read larger than 8 bit values from byte roms */ 151 #define parseshort(o) \ 152 ((bus_space_read_1(memt, romh, (o) + 3) << 8) | \ 153 (bus_space_read_1(memt, romh, (o) + 7))) 154 #define parseword(o) \ 155 ((bus_space_read_1(memt, romh, (o) + 3) << 24) | \ 156 (bus_space_read_1(memt, romh, (o) + 7) << 16) | \ 157 (bus_space_read_1(memt, romh, (o) + 11) << 8) | \ 158 (bus_space_read_1(memt, romh, (o) + 15))) 159 160 int 161 sti_attach_common(struct sti_softc *sc, bus_space_tag_t iot, 162 bus_space_tag_t memt, bus_space_handle_t romh, u_int codebase) 163 { 164 struct sti_rom *rom; 165 int rc; 166 167 rom = (struct sti_rom *)malloc(sizeof(*rom), M_DEVBUF, 168 M_WAITOK | M_ZERO); 169 rom->rom_softc = sc; 170 rc = sti_rom_setup(rom, iot, memt, romh, sc->bases, codebase); 171 if (rc != 0) { 172 free(rom, M_DEVBUF); 173 return rc; 174 } 175 176 sc->sc_rom = rom; 177 178 sti_describe(sc); 179 180 sc->sc_scr = sti_attach_screen(sc, 181 sc->sc_flags & STI_CONSOLE ? 0 : STI_CLEARSCR); 182 if (sc->sc_scr == NULL) 183 rc = ENOMEM; 184 185 return rc; 186 } 187 188 struct sti_screen * 189 sti_attach_screen(struct sti_softc *sc, int flags) 190 { 191 struct sti_screen *scr; 192 int rc; 193 194 scr = (struct sti_screen *)malloc(sizeof(*scr), M_DEVBUF, 195 M_WAITOK | M_ZERO); 196 scr->scr_rom = sc->sc_rom; 197 rc = sti_screen_setup(scr, flags); 198 if (rc != 0) { 199 free(scr, M_DEVBUF); 200 return NULL; 201 } 202 203 sti_describe_screen(sc, scr); 204 205 return scr; 206 } 207 208 int 209 sti_rom_setup(struct sti_rom *rom, bus_space_tag_t iot, bus_space_tag_t memt, 210 bus_space_handle_t romh, bus_addr_t *bases, u_int codebase) 211 { 212 struct sti_dd *dd; 213 int error, size, i; 214 215 KASSERT(rom != NULL); 216 STI_ENABLE_ROM(rom->rom_softc); 217 218 rom->iot = iot; 219 rom->memt = memt; 220 rom->romh = romh; 221 rom->bases = bases; 222 223 /* 224 * Get ROM header and code function pointers. 225 */ 226 227 dd = &rom->rom_dd; 228 rom->rom_devtype = bus_space_read_1(memt, romh, 3); 229 if (rom->rom_devtype == STI_DEVTYPE1) { 230 dd->dd_type = bus_space_read_1(memt, romh, 0x03); 231 dd->dd_nmon = bus_space_read_1(memt, romh, 0x07); 232 dd->dd_grrev = bus_space_read_1(memt, romh, 0x0b); 233 dd->dd_lrrev = bus_space_read_1(memt, romh, 0x0f); 234 dd->dd_grid[0] = parseword(0x10); 235 dd->dd_grid[1] = parseword(0x20); 236 dd->dd_fntaddr = parseword(0x30) & ~3; 237 dd->dd_maxst = parseword(0x40); 238 dd->dd_romend = parseword(0x50) & ~3; 239 dd->dd_reglst = parseword(0x60) & ~3; 240 dd->dd_maxreent = parseshort(0x70); 241 dd->dd_maxtimo = parseshort(0x78); 242 dd->dd_montbl = parseword(0x80) & ~3; 243 dd->dd_udaddr = parseword(0x90) & ~3; 244 dd->dd_stimemreq = parseword(0xa0); 245 dd->dd_udsize = parseword(0xb0); 246 dd->dd_pwruse = parseshort(0xc0); 247 dd->dd_bussup = bus_space_read_1(memt, romh, 0xcb); 248 dd->dd_ebussup = bus_space_read_1(memt, romh, 0xcf); 249 dd->dd_altcodet = bus_space_read_1(memt, romh, 0xd3); 250 dd->dd_eddst[0] = bus_space_read_1(memt, romh, 0xd7); 251 dd->dd_eddst[1] = bus_space_read_1(memt, romh, 0xdb); 252 dd->dd_eddst[2] = bus_space_read_1(memt, romh, 0xdf); 253 dd->dd_cfbaddr = parseword(0xe0) & ~3; 254 255 codebase <<= 2; 256 dd->dd_pacode[0x0] = parseword(codebase + 0x000) & ~3; 257 dd->dd_pacode[0x1] = parseword(codebase + 0x010) & ~3; 258 dd->dd_pacode[0x2] = parseword(codebase + 0x020) & ~3; 259 dd->dd_pacode[0x3] = parseword(codebase + 0x030) & ~3; 260 dd->dd_pacode[0x4] = parseword(codebase + 0x040) & ~3; 261 dd->dd_pacode[0x5] = parseword(codebase + 0x050) & ~3; 262 dd->dd_pacode[0x6] = parseword(codebase + 0x060) & ~3; 263 dd->dd_pacode[0x7] = parseword(codebase + 0x070) & ~3; 264 dd->dd_pacode[0x8] = parseword(codebase + 0x080) & ~3; 265 dd->dd_pacode[0x9] = parseword(codebase + 0x090) & ~3; 266 dd->dd_pacode[0xa] = parseword(codebase + 0x0a0) & ~3; 267 dd->dd_pacode[0xb] = parseword(codebase + 0x0b0) & ~3; 268 dd->dd_pacode[0xc] = parseword(codebase + 0x0c0) & ~3; 269 dd->dd_pacode[0xd] = parseword(codebase + 0x0d0) & ~3; 270 dd->dd_pacode[0xe] = parseword(codebase + 0x0e0) & ~3; 271 dd->dd_pacode[0xf] = parseword(codebase + 0x0f0) & ~3; 272 } else { /* STI_DEVTYPE4 */ 273 bus_space_read_region_stream_4(memt, romh, 0, (uint32_t *)dd, 274 sizeof(*dd) / 4); 275 /* fix pacode... */ 276 bus_space_read_region_stream_4(memt, romh, codebase, 277 (uint32_t *)dd->dd_pacode, sizeof(dd->dd_pacode) / 4); 278 } 279 280 STI_DISABLE_ROM(rom->rom_softc); 281 282 DPRINTF(("dd:\n" 283 "devtype=%x, rev=%x;%d, altt=%x, gid=%08x%08x, font=%x, mss=%x\n" 284 "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n" 285 "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n" 286 "code=", 287 dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet, 288 dd->dd_grid[0], dd->dd_grid[1], dd->dd_fntaddr, dd->dd_maxst, 289 dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo, 290 dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq, 291 dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr)); 292 DPRINTF(("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", 293 dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2], 294 dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5], 295 dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8], 296 dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb], 297 dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe], 298 dd->dd_pacode[0xf])); 299 300 /* 301 * Figure out how many bytes we need for the STI code. 302 * Note there could be fewer than STI_END pointer entries 303 * populated, especially on older devices. 304 */ 305 for (i = STI_END; dd->dd_pacode[i] == 0; i--) 306 ; 307 308 size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN]; 309 310 if (rom->rom_devtype == STI_DEVTYPE1) 311 size = (size + 3) / 4; 312 if (size == 0) { 313 aprint_error(": no code for the requested platform\n"); 314 return EINVAL; 315 } 316 317 if (!(rom->rom_code = uvm_km_alloc(kernel_map, round_page(size), 0, 318 UVM_KMF_WIRED))) { 319 aprint_error(": cannot allocate %u bytes for code\n", size); 320 return ENOMEM; 321 } 322 DPRINTF(("code=0x%lx[%x]\n", rom->rom_code, size)); 323 324 /* 325 * Copy code into memory and make it executable. 326 */ 327 328 STI_ENABLE_ROM(rom->rom_softc); 329 330 if (rom->rom_devtype == STI_DEVTYPE1) { 331 uint8_t *p; 332 uint32_t addr, eaddr; 333 334 p = (uint8_t *)rom->rom_code; 335 336 for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4; 337 addr < eaddr; addr += 4 ) { 338 *p++ = bus_space_read_4(memt, romh, addr) & 0xff; 339 } 340 } else { /* STI_DEVTYPE4 */ 341 bus_space_read_region_stream_4(memt, romh, 342 dd->dd_pacode[STI_BEGIN], (uint32_t *)rom->rom_code, 343 size / 4); 344 } 345 346 STI_DISABLE_ROM(rom->rom_softc); 347 348 if ((error = uvm_map_protect(kernel_map, rom->rom_code, 349 rom->rom_code + round_page(size), UVM_PROT_RX, FALSE))) { 350 aprint_error(": uvm_map_protect failed (%d)\n", error); 351 uvm_km_free(kernel_map, rom->rom_code, round_page(size), 352 UVM_KMF_WIRED); 353 return error; 354 } 355 356 /* 357 * Setup code function pointers. 358 */ 359 360 #define O(i) \ 361 (dd->dd_pacode[(i)] == 0 ? 0 : \ 362 (rom->rom_code + (dd->dd_pacode[(i)] - dd->dd_pacode[0]) / \ 363 (rom->rom_devtype == STI_DEVTYPE1 ? 4 : 1))) 364 365 rom->init = (sti_init_t)O(STI_INIT_GRAPH); 366 rom->mgmt = (sti_mgmt_t)O(STI_STATE_MGMT); 367 rom->unpmv = (sti_unpmv_t)O(STI_FONT_UNPMV); 368 rom->blkmv = (sti_blkmv_t)O(STI_BLOCK_MOVE); 369 rom->test = (sti_test_t)O(STI_SELF_TEST); 370 rom->exhdl = (sti_exhdl_t)O(STI_EXCEP_HDLR); 371 rom->inqconf = (sti_inqconf_t)O(STI_INQ_CONF); 372 rom->scment = (sti_scment_t)O(STI_SCM_ENT); 373 rom->dmac = (sti_dmac_t)O(STI_DMA_CTRL); 374 rom->flowc = (sti_flowc_t)O(STI_FLOW_CTRL); 375 rom->utiming = (sti_utiming_t)O(STI_UTIMING); 376 rom->pmgr = (sti_pmgr_t)O(STI_PROC_MGR); 377 rom->util = (sti_util_t)O(STI_UTIL); 378 379 #undef O 380 381 /* 382 * Set colormap entry is not implemented until 8.04, so force 383 * a NULL pointer here. 384 */ 385 if (dd->dd_grrev < STI_REVISION(8, 4)) { 386 rom->scment = NULL; 387 } 388 389 return 0; 390 } 391 392 /* 393 * Map all regions. 394 */ 395 void 396 sti_region_setup(struct sti_screen *scr) 397 { 398 struct sti_rom *rom = scr->scr_rom; 399 bus_space_tag_t memt = rom->memt; 400 bus_space_handle_t romh = rom->romh; 401 bus_addr_t *bases = rom->bases; 402 struct sti_dd *dd = &rom->rom_dd; 403 struct sti_cfg *cc = &scr->scr_cfg; 404 struct sti_region regions[STI_REGION_MAX], *r; 405 u_int regno, regcnt; 406 bus_addr_t addr; 407 408 DPRINTF(("stiregions @ %x:\n", dd->dd_reglst)); 409 410 /* 411 * Read the region information. 412 */ 413 414 STI_ENABLE_ROM(rom->rom_softc); 415 416 if (rom->rom_devtype == STI_DEVTYPE1) { 417 for (regno = 0; regno < STI_REGION_MAX; regno++) 418 *(u_int *)(regions + regno) = 419 parseword(dd->dd_reglst + regno * 0x10); 420 } else { 421 bus_space_read_region_stream_4(memt, romh, dd->dd_reglst, 422 (uint32_t *)regions, sizeof(regions) / 4); 423 } 424 425 STI_DISABLE_ROM(rom->rom_softc); 426 427 /* 428 * Count them. 429 */ 430 431 for (regcnt = 0, r = regions; regcnt < STI_REGION_MAX; regcnt++, r++) 432 if (r->last) 433 break; 434 regcnt++; 435 436 /* 437 * Map them. 438 */ 439 440 for (regno = 0, r = regions; regno < regcnt; regno++, r++) { 441 if (r->length == 0) 442 continue; 443 444 /* 445 * Assume an existing mapping exists. 446 */ 447 addr = bases[regno] + (r->offset << PGSHIFT); 448 DPRINTF(("%08x @ 0x%08x%s%s%s%s", 449 r->length << PGSHIFT, (int)addr, r->sys_only ? " sys" : "", 450 r->cache ? " cache" : "", r->btlb ? " btlb" : "", 451 r->last ? " last" : "")); 452 453 /* 454 * Region #0 is always the rom, and it should have been 455 * mapped already. 456 * XXX This expects a 1:1 mapping... 457 */ 458 if (regno == 0 && romh == bases[0]) { 459 cc->regions[0] = addr; 460 DPRINTF(("\n")); 461 continue; 462 } 463 464 if (bus_space_map(memt, addr, r->length << PGSHIFT, 465 BUS_SPACE_MAP_LINEAR | (r->cache ? 466 BUS_SPACE_MAP_CACHEABLE : 0), &rom->regh[regno]) != 0) { 467 rom->regh[regno] = romh; /* XXX */ 468 DPRINTF((" - already mapped region\n")); 469 } else { 470 addr = (bus_addr_t) 471 bus_space_vaddr(memt, rom->regh[regno]); 472 if (regno == 1) { 473 DPRINTF((" - fb")); 474 scr->fbaddr = addr; 475 scr->fblen = r->length << PGSHIFT; 476 } 477 DPRINTF(("\n")); 478 } 479 480 cc->regions[regno] = addr; 481 } 482 483 #ifdef STIDEBUG 484 /* 485 * Make sure we'll trap accessing unmapped regions 486 */ 487 for (regno = 0; regno < STI_REGION_MAX; regno++) 488 if (cc->regions[regno] == 0) 489 cc->regions[regno] = 0x81234567; 490 #endif 491 } 492 493 int 494 sti_screen_setup(struct sti_screen *scr, int flags) 495 { 496 struct sti_rom *rom = scr->scr_rom; 497 bus_space_tag_t memt = rom->memt; 498 bus_space_handle_t romh = rom->romh; 499 struct sti_dd *dd = &rom->rom_dd; 500 struct sti_cfg *cc = &scr->scr_cfg; 501 struct sti_inqconfout cfg; 502 struct sti_einqconfout ecfg; 503 #ifdef STIDEBUG 504 char buf[256]; 505 #endif 506 int error, i; 507 int geometry_kluge = 0; 508 u_int fontindex = 0; 509 510 KASSERT(scr != NULL); 511 memset(cc, 0, sizeof(*cc)); 512 cc->ext_cfg = &scr->scr_ecfg; 513 memset(cc->ext_cfg, 0, sizeof(*cc->ext_cfg)); 514 515 if (dd->dd_stimemreq) { 516 scr->scr_ecfg.addr = 517 malloc(dd->dd_stimemreq, M_DEVBUF, M_WAITOK); 518 } 519 520 sti_region_setup(scr); 521 522 if ((error = sti_init(scr, 0))) { 523 aprint_error(": cannot initialize (%d)\n", error); 524 goto fail; 525 } 526 527 memset(&cfg, 0, sizeof(cfg)); 528 memset(&ecfg, 0, sizeof(ecfg)); 529 cfg.ext = &ecfg; 530 if ((error = sti_inqcfg(scr, &cfg))) { 531 aprint_error(": error %d inquiring config\n", error); 532 goto fail; 533 } 534 535 /* 536 * Older (rev 8.02) boards report wrong offset values, 537 * similar to the displayable area size, at least in m68k mode. 538 * Attempt to detect this and adjust here. 539 */ 540 if (cfg.owidth == cfg.width && 541 cfg.oheight == cfg.height) 542 geometry_kluge = 1; 543 544 if (geometry_kluge) { 545 scr->scr_cfg.oscr_width = cfg.owidth = 546 cfg.fbwidth - cfg.width; 547 scr->scr_cfg.oscr_height = cfg.oheight = 548 cfg.fbheight - cfg.height; 549 } 550 551 /* 552 * Save a few fields for sti_describe_screen() later 553 */ 554 scr->fbheight = cfg.fbheight; 555 scr->fbwidth = cfg.fbwidth; 556 scr->oheight = cfg.oheight; 557 scr->owidth = cfg.owidth; 558 memcpy(scr->name, cfg.name, sizeof(scr->name)); 559 560 if (flags & STI_FBMODE) { 561 /* we're done here */ 562 sti_init(scr, STI_FBMODE); 563 return 0; 564 } 565 566 if ((error = sti_init(scr, STI_TEXTMODE | flags))) { 567 aprint_error(": cannot initialize (%d)\n", error); 568 goto fail; 569 } 570 #ifdef STIDEBUG 571 snprintb(buf, sizeof(buf), STI_INQCONF_BITS, cfg.attributes); 572 DPRINTF(("conf: bpp=%d planes=%d attr=%s\n" 573 "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", cfg.bpp, 574 cfg.planes, buf, 575 ecfg.crt_config[0], ecfg.crt_config[1], ecfg.crt_config[2], 576 ecfg.crt_hw[0], ecfg.crt_hw[1], ecfg.crt_hw[2])); 577 #endif 578 scr->scr_bpp = cfg.bppu; 579 580 /* 581 * Although scr->scr_ecfg.current_monitor is not filled by 582 * sti_init() as expected, we can nevertheless walk the monitor 583 * list, if there is any, and if we find a mode matching our 584 * resolution, pick its font index. 585 */ 586 if (dd->dd_montbl != 0) { 587 STI_ENABLE_ROM(rom->rom_softc); 588 589 for (i = 0; i < dd->dd_nmon; i++) { 590 u_int offs = dd->dd_montbl + 8 * i; 591 uint32_t m[2]; 592 sti_mon_t mon = (void *)m; 593 if (rom->rom_devtype == STI_DEVTYPE1) { 594 m[0] = parseword(4 * offs); 595 m[1] = parseword(4 * (offs + 4)); 596 } else { 597 bus_space_read_region_stream_4(memt, romh, offs, 598 (uint32_t *)mon, sizeof(*mon) / 4); 599 } 600 601 if (mon->width == scr->scr_cfg.scr_width && 602 mon->height == scr->scr_cfg.scr_height) { 603 fontindex = mon->font; 604 break; 605 } 606 } 607 608 STI_DISABLE_ROM(rom->rom_softc); 609 610 DPRINTF(("font index: %d\n", fontindex)); 611 } 612 613 if ((error = sti_fetchfonts(scr, &cfg, dd->dd_fntaddr, fontindex))) { 614 aprint_error(": cannot fetch fonts (%d)\n", error); 615 goto fail; 616 } 617 618 /* 619 * setup screen descriptions: 620 * figure number of fonts supported; 621 * allocate wscons structures; 622 * calculate dimensions. 623 */ 624 625 scr->scr_wsd.name = "std"; 626 scr->scr_wsd.ncols = cfg.width / scr->scr_curfont.width; 627 scr->scr_wsd.nrows = cfg.height / scr->scr_curfont.height; 628 scr->scr_wsd.textops = &sti_emulops; 629 scr->scr_wsd.fontwidth = scr->scr_curfont.width; 630 scr->scr_wsd.fontheight = scr->scr_curfont.height; 631 scr->scr_wsd.capabilities = WSSCREEN_REVERSE; 632 633 scr->scr_scrlist[0] = &scr->scr_wsd; 634 scr->scr_screenlist.nscreens = 1; 635 scr->scr_screenlist.screens = scr->scr_scrlist; 636 637 #ifndef SMALL_KERNEL 638 /* 639 * Decide which board-specific routines to use. 640 */ 641 642 switch (dd->dd_grid[0]) { 643 case STI_DD_CRX: 644 scr->setupfb = ngle_elk_setupfb; 645 scr->putcmap = ngle_putcmap; 646 647 scr->reg10_value = 0x13601000; 648 if (scr->scr_bpp > 8) 649 scr->reg12_value = NGLE_BUFF1_CMAP3; 650 else 651 scr->reg12_value = NGLE_BUFF1_CMAP0; 652 scr->cmap_finish_register = NGLE_REG_1; 653 break; 654 655 case STI_DD_TIMBER: 656 scr->setupfb = ngle_timber_setupfb; 657 scr->putcmap = ngle_putcmap; 658 659 scr->reg10_value = 0x13602000; 660 scr->reg12_value = NGLE_BUFF1_CMAP0; 661 scr->cmap_finish_register = NGLE_REG_1; 662 break; 663 664 case STI_DD_ARTIST: 665 scr->setupfb = ngle_artist_setupfb; 666 scr->putcmap = ngle_putcmap; 667 668 scr->reg10_value = 0x13601000; 669 scr->reg12_value = NGLE_ARTIST_CMAP0; 670 scr->cmap_finish_register = NGLE_REG_26; 671 break; 672 673 case STI_DD_EG: 674 scr->setupfb = ngle_artist_setupfb; 675 scr->putcmap = ngle_putcmap; 676 677 scr->reg10_value = 0x13601000; 678 if (scr->scr_bpp > 8) { 679 scr->reg12_value = NGLE_BUFF1_CMAP3; 680 scr->cmap_finish_register = NGLE_REG_1; 681 } else { 682 scr->reg12_value = NGLE_ARTIST_CMAP0; 683 scr->cmap_finish_register = NGLE_REG_26; 684 } 685 break; 686 687 case STI_DD_HCRX: 688 scr->setupfb = ngle_elk_setupfb; 689 scr->putcmap = ngle_hcrx_putcmap; 690 691 if (scr->scr_bpp > 8) { 692 scr->reg12_value = NGLE_BUFF1_CMAP3; 693 scr->reg10_value = 0xBBA0A000; 694 } else { 695 scr->reg12_value = NGLE_BUFF1_CMAP0; 696 scr->reg10_value = 0x13602000; 697 } 698 scr->cmap_finish_register = NGLE_REG_38; 699 break; 700 701 case STI_DD_GRX: 702 case STI_DD_CRX24: 703 case STI_DD_EVRX: 704 case STI_DD_3X2V: 705 case STI_DD_DUAL_CRX: 706 case STI_DD_LEGO: 707 case STI_DD_SUMMIT: 708 case STI_DD_PINNACLE: 709 default: 710 scr->setupfb = NULL; 711 scr->putcmap = 712 rom->scment == NULL ? NULL : ngle_default_putcmap; 713 break; 714 } 715 #endif 716 717 return 0; 718 719 fail: 720 /* XXX free resources */ 721 if (scr->scr_ecfg.addr != NULL) { 722 free(scr->scr_ecfg.addr, M_DEVBUF); 723 scr->scr_ecfg.addr = NULL; 724 } 725 726 return ENXIO; 727 } 728 729 void 730 sti_describe_screen(struct sti_softc *sc, struct sti_screen *scr) 731 { 732 struct sti_font *fp = &scr->scr_curfont; 733 734 aprint_normal("%s: %s, %dx%d frame buffer, %dx%dx%d display\n", 735 device_xname(sc->sc_dev), scr->name, scr->fbwidth, scr->fbheight, 736 scr->scr_cfg.scr_width, scr->scr_cfg.scr_height, scr->scr_bpp); 737 738 aprint_normal("%s: %dx%d font type %d, %d bpc, charset %d-%d\n", 739 device_xname(sc->sc_dev), fp->width, fp->height, 740 fp->type, fp->bpc, fp->first, fp->last); 741 } 742 743 void 744 sti_describe(struct sti_softc *sc) 745 { 746 struct sti_rom *rom = sc->sc_rom; 747 struct sti_dd *dd = &rom->rom_dd; 748 749 aprint_normal(": rev %d.%02d;%d, ID 0x%08X%08X\n", 750 dd->dd_grrev >> 4, dd->dd_grrev & 0xf, 751 dd->dd_lrrev, dd->dd_grid[0], dd->dd_grid[1]); 752 753 if (sc->sc_scr != NULL) 754 sti_describe_screen(sc, sc->sc_scr); 755 } 756 757 /* 758 * Final part of attachment. On hppa where we use the PDC console 759 * during autoconf, this has to be postponed until autoconf has 760 * completed. 761 */ 762 void 763 sti_end_attach(struct sti_softc *sc) 764 { 765 struct sti_screen *scr = sc->sc_scr; 766 767 if (scr == NULL) 768 return; 769 #if NWSDISPLAY > 0 770 else { 771 struct wsemuldisplaydev_attach_args waa; 772 scr->scr_wsmode = WSDISPLAYIO_MODE_EMUL; 773 774 waa.console = sc->sc_flags & STI_CONSOLE ? 1 : 0; 775 waa.scrdata = &scr->scr_screenlist; 776 waa.accessops = &sti_accessops; 777 waa.accesscookie = scr; 778 779 /* attach as console if required */ 780 if (waa.console && !ISSET(sc->sc_flags, STI_ATTACHED)) { 781 long defattr; 782 783 sti_alloc_attr(scr, 0, 0, 0, &defattr); 784 wsdisplay_cnattach(&scr->scr_wsd, scr, 785 0, scr->scr_wsd.nrows - 1, defattr); 786 sc->sc_flags |= STI_ATTACHED; 787 } 788 789 config_found(sc->sc_dev, &waa, wsemuldisplaydevprint, 790 CFARGS_NONE); 791 } 792 #endif 793 } 794 795 u_int 796 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh) 797 { 798 int devtype; 799 u_int romend; 800 801 devtype = bus_space_read_1(memt, romh, 3); 802 if (devtype == STI_DEVTYPE4) { 803 bus_space_read_region_stream_4(memt, romh, STI_DEV4_DD_ROMEND, 804 (uint32_t *)&romend, 1); 805 } else { 806 romend = parseword(STI_DEV1_DD_ROMEND); 807 } 808 809 DPRINTF(("%s: %08x (%08x)\n", __func__, romend, round_page(romend))); 810 811 return round_page(romend); 812 } 813 814 int 815 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *cfg, 816 uint32_t baseaddr, u_int fontindex) 817 { 818 struct sti_rom *rom = scr->scr_rom; 819 bus_space_tag_t memt = rom->memt; 820 bus_space_handle_t romh = rom->romh; 821 struct sti_font *fp = &scr->scr_curfont; 822 uint32_t addr; 823 int size; 824 #ifdef notyet 825 int uc; 826 struct { 827 struct sti_unpmvflags flags; 828 struct sti_unpmvin in; 829 struct sti_unpmvout out; 830 } a; 831 #endif 832 833 /* 834 * Get the first PROM font in memory 835 */ 836 837 STI_ENABLE_ROM(rom->rom_softc); 838 839 rescan: 840 addr = baseaddr; 841 do { 842 if (rom->rom_devtype == STI_DEVTYPE1) { 843 fp->first = parseshort(addr + 0x00); 844 fp->last = parseshort(addr + 0x08); 845 fp->width = bus_space_read_1(memt, romh, addr + 0x13); 846 fp->height = bus_space_read_1(memt, romh, addr + 0x17); 847 fp->type = bus_space_read_1(memt, romh, addr + 0x1b); 848 fp->bpc = bus_space_read_1(memt, romh, addr + 0x1f); 849 fp->next = parseword(addr + 0x20); 850 fp->uheight= bus_space_read_1(memt, romh, addr + 0x33); 851 fp->uoffset= bus_space_read_1(memt, romh, addr + 0x37); 852 } else { /* STI_DEVTYPE4 */ 853 bus_space_read_region_stream_4(memt, romh, addr, 854 (uint32_t *)fp, sizeof(struct sti_font) / 4); 855 } 856 857 #ifdef STIDEBUG 858 STI_DISABLE_ROM(rom->rom_softc); 859 DPRINTF(("%s: %dx%d font type %d, %d bpc, charset %d-%d\n", 860 device_xname(scr->scr_rom->rom_softc->sc_dev), fp->width, 861 fp->height, fp->type, fp->bpc, fp->first, fp->last)); 862 STI_ENABLE_ROM(rom->rom_softc); 863 #endif 864 865 if (fontindex == 0) { 866 size = sizeof(struct sti_font) + 867 (fp->last - fp->first + 1) * fp->bpc; 868 if (rom->rom_devtype == STI_DEVTYPE1) 869 size *= 4; 870 scr->scr_romfont = malloc(size, M_DEVBUF, M_WAITOK); 871 872 bus_space_read_region_stream_4(memt, romh, addr, 873 (uint32_t *)scr->scr_romfont, size / 4); 874 break; 875 } 876 877 addr = baseaddr + fp->next; 878 fontindex--; 879 } while (fp->next != 0); 880 881 /* 882 * If our font index was bogus, we did not find the expected font. 883 * In this case, pick the first one and be done with it. 884 */ 885 if (fp->next == 0 && scr->scr_romfont == NULL) { 886 fontindex = 0; 887 goto rescan; 888 } 889 890 STI_DISABLE_ROM(rom->rom_softc); 891 892 #ifdef notyet 893 /* 894 * If there is enough room in the off-screen framebuffer memory, 895 * display all the characters there in order to display them 896 * faster with blkmv operations rather than unpmv later on. 897 */ 898 if (size <= cfg->fbheight * 899 (cfg->fbwidth - cfg->width - cfg->owidth)) { 900 memset(&a, 0, sizeof(a)); 901 a.flags.flags = STI_UNPMVF_WAIT; 902 a.in.fg_colour = STI_COLOUR_WHITE; 903 a.in.bg_colour = STI_COLOUR_BLACK; 904 a.in.font_addr = scr->scr_romfont; 905 906 scr->scr_fontmaxcol = cfg->fbheight / fp->height; 907 scr->scr_fontbase = cfg->width + cfg->owidth; 908 for (uc = fp->first; uc <= fp->last; uc++) { 909 a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) * 910 fp->width + scr->scr_fontbase; 911 a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) * 912 fp->height; 913 a.in.index = uc; 914 915 (*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 916 if (a.out.errno) { 917 aprint_error_dev(sc->sc_dev, "unpmv %d " 918 "returned %d\n", uc, a.out.errno); 919 return 0; 920 } 921 } 922 923 free(scr->scr_romfont, M_DEVBUF); 924 scr->scr_romfont = NULL; 925 } 926 #endif 927 928 return 0; 929 } 930 931 /* 932 * Wrappers around STI code pointers 933 */ 934 935 int 936 sti_init(struct sti_screen *scr, int mode) 937 { 938 struct sti_rom *rom = scr->scr_rom; 939 struct { 940 struct sti_initflags flags; 941 struct sti_initin in; 942 struct sti_einitin ein; 943 struct sti_initout out; 944 } a; 945 946 KASSERT(rom != NULL); 947 memset(&a, 0, sizeof(a)); 948 949 a.flags.flags = STI_INITF_WAIT | STI_INITF_PBET | STI_INITF_PBETI; 950 if ((mode & STI_TEXTMODE) != 0) { 951 a.flags.flags |= STI_INITF_TEXT | STI_INITF_CMB | 952 STI_INITF_PBET | STI_INITF_PBETI | STI_INITF_ICMT; 953 a.in.text_planes = 1; 954 } else { 955 a.flags.flags |= STI_INITF_TEXT | STI_INITF_NTEXT; 956 /* 957 * Request as many text planes as STI will allow. 958 * The reason to do this - when switching to framebuffer mode 959 * for X we need access to all planes. In theory STI should do 960 * just that when we request access to both text and non-text 961 * planes as above. 962 * In reality though, at least on my PCI Visualize EG, some 963 * planes and/or colour registers remain inaccessible if we 964 * request only one text plane. 965 * Clearly we're missing a register write or two here, but so 966 * far I haven't found it. 967 */ 968 a.in.text_planes = 3; 969 } 970 if ((mode & STI_CLEARSCR) != 0) 971 a.flags.flags |= STI_INITF_CLEAR; 972 973 a.in.ext_in = &a.ein; 974 975 DPRINTF(("%s: init,%p(%x, %p, %p, %p)\n", 976 device_xname(rom->rom_softc->sc_dev), rom->init, a.flags.flags, 977 &a.in, &a.out, &scr->scr_cfg)); 978 979 (*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 980 981 if (a.out.text_planes != a.in.text_planes) 982 return -1; /* not colliding with sti errno values */ 983 return a.out.errno; 984 } 985 986 int 987 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out) 988 { 989 struct sti_rom *rom = scr->scr_rom; 990 struct { 991 struct sti_inqconfflags flags; 992 struct sti_inqconfin in; 993 } a; 994 995 memset(&a, 0, sizeof(a)); 996 997 a.flags.flags = STI_INQCONFF_WAIT; 998 (*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg); 999 1000 return out->errno; 1001 } 1002 1003 void 1004 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w, 1005 enum sti_bmove_funcs f) 1006 { 1007 struct sti_rom *rom = scr->scr_rom; 1008 struct { 1009 struct sti_blkmvflags flags; 1010 struct sti_blkmvin in; 1011 struct sti_blkmvout out; 1012 } a; 1013 1014 memset(&a, 0, sizeof(a)); 1015 1016 a.flags.flags = STI_BLKMVF_WAIT; 1017 switch (f) { 1018 case bmf_clear: 1019 a.flags.flags |= STI_BLKMVF_CLR; 1020 a.in.bg_colour = STI_COLOUR_BLACK; 1021 break; 1022 case bmf_underline: 1023 case bmf_copy: 1024 a.in.fg_colour = STI_COLOUR_WHITE; 1025 a.in.bg_colour = STI_COLOUR_BLACK; 1026 break; 1027 case bmf_invert: 1028 a.flags.flags |= STI_BLKMVF_COLR; 1029 a.in.fg_colour = STI_COLOUR_BLACK; 1030 a.in.bg_colour = STI_COLOUR_WHITE; 1031 break; 1032 } 1033 a.in.srcx = x1; 1034 a.in.srcy = y1; 1035 a.in.dstx = x2; 1036 a.in.dsty = y2; 1037 a.in.height = h; 1038 a.in.width = w; 1039 1040 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 1041 #ifdef STIDEBUG 1042 if (a.out.errno) 1043 printf("%s: blkmv returned %d\n", 1044 device_xname(rom->rom_softc->sc_dev), a.out.errno); 1045 #endif 1046 } 1047 1048 int 1049 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b) 1050 { 1051 struct sti_rom *rom = scr->scr_rom; 1052 struct { 1053 struct sti_scmentflags flags; 1054 struct sti_scmentin in; 1055 struct sti_scmentout out; 1056 } a; 1057 1058 memset(&a, 0, sizeof(a)); 1059 1060 a.flags.flags = STI_SCMENTF_WAIT; 1061 a.in.entry = i; 1062 a.in.value = (r << 16) | (g << 8) | b; 1063 1064 (*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 1065 1066 return a.out.errno; 1067 } 1068 1069 /* 1070 * wsdisplay accessops 1071 */ 1072 int 1073 sti_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 1074 { 1075 struct sti_screen *scr = (struct sti_screen *)v; 1076 struct sti_rom *rom = scr->scr_rom; 1077 struct wsdisplay_fbinfo *wdf; 1078 struct wsdisplay_cmap *cmapp; 1079 u_int mode, idx, count; 1080 int ret; 1081 1082 ret = 0; 1083 switch (cmd) { 1084 case GCID: 1085 *(u_int *)data = rom->rom_dd.dd_grid[0]; 1086 break; 1087 1088 case WSDISPLAYIO_GMODE: 1089 *(u_int *)data = scr->scr_wsmode; 1090 break; 1091 1092 case WSDISPLAYIO_SMODE: 1093 mode = *(u_int *)data; 1094 switch (mode) { 1095 case WSDISPLAYIO_MODE_EMUL: 1096 if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL) 1097 ret = sti_init(scr, STI_TEXTMODE); 1098 break; 1099 case WSDISPLAYIO_MODE_DUMBFB: 1100 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) { 1101 ret = sti_init(scr, 0); 1102 if (scr->setupfb != NULL) 1103 scr->setupfb(scr); 1104 else 1105 #if 0 1106 ret = sti_init(scr, STI_FBMODE); 1107 #else 1108 ret = EINVAL; 1109 #endif 1110 } 1111 break; 1112 case WSDISPLAYIO_MODE_MAPPED: 1113 default: 1114 ret = EINVAL; 1115 break; 1116 } 1117 if (ret == 0) 1118 scr->scr_wsmode = mode; 1119 break; 1120 1121 case WSDISPLAYIO_GTYPE: 1122 *(u_int *)data = WSDISPLAY_TYPE_STI; 1123 break; 1124 1125 case WSDISPLAYIO_GINFO: 1126 wdf = (struct wsdisplay_fbinfo *)data; 1127 wdf->height = scr->scr_cfg.scr_height; 1128 wdf->width = scr->scr_cfg.scr_width; 1129 wdf->depth = scr->scr_bpp; 1130 if (scr->putcmap == NULL || scr->scr_bpp > 8) 1131 wdf->cmsize = 0; 1132 else 1133 wdf->cmsize = STI_NCMAP; 1134 break; 1135 1136 case WSDISPLAYIO_LINEBYTES: 1137 if (scr->scr_bpp > 8) 1138 *(u_int *)data = scr->scr_cfg.fb_width * 4; 1139 else 1140 *(u_int *)data = scr->scr_cfg.fb_width; 1141 break; 1142 1143 case WSDISPLAYIO_GETCMAP: 1144 if (scr->putcmap == NULL || scr->scr_bpp > 8) 1145 return ENODEV; 1146 cmapp = (struct wsdisplay_cmap *)data; 1147 idx = cmapp->index; 1148 count = cmapp->count; 1149 if (idx >= STI_NCMAP || count > STI_NCMAP - idx) 1150 return EINVAL; 1151 if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count))) 1152 break; 1153 if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count))) 1154 break; 1155 if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count))) 1156 break; 1157 break; 1158 1159 case WSDISPLAYIO_PUTCMAP: 1160 if (scr->putcmap == NULL || scr->scr_bpp > 8) 1161 return ENODEV; 1162 if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL) { 1163 /* 1164 * The hardware palette settings are handled by 1165 * the STI ROM in STI_TEXTMODE and changing cmap 1166 * could cause mangled text colors at least on CRX. 1167 * Updating CMAP in EMUL mode isn't expected anyway 1168 * so just ignore it. 1169 */ 1170 return 0; 1171 } 1172 cmapp = (struct wsdisplay_cmap *)data; 1173 idx = cmapp->index; 1174 count = cmapp->count; 1175 if (idx >= STI_NCMAP || count > STI_NCMAP - idx) 1176 return EINVAL; 1177 if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count))) 1178 break; 1179 if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count))) 1180 break; 1181 if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count))) 1182 break; 1183 ret = scr->putcmap(scr, idx, count); 1184 break; 1185 1186 case WSDISPLAYIO_SVIDEO: 1187 case WSDISPLAYIO_GVIDEO: 1188 case WSDISPLAYIO_GCURPOS: 1189 case WSDISPLAYIO_SCURPOS: 1190 case WSDISPLAYIO_GCURMAX: 1191 case WSDISPLAYIO_GCURSOR: 1192 case WSDISPLAYIO_SCURSOR: 1193 default: 1194 return ENOTTY; /* not supported yet */ 1195 } 1196 1197 return ret; 1198 } 1199 1200 paddr_t 1201 sti_mmap(void *v, void *vs, off_t offset, int prot) 1202 { 1203 struct sti_screen *scr = (struct sti_screen *)v; 1204 struct sti_rom *rom = scr->scr_rom; 1205 paddr_t pa; 1206 1207 if ((offset & PAGE_MASK) != 0) 1208 return -1; 1209 1210 if (offset < 0 || offset >= scr->fblen) 1211 return -1; 1212 1213 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) 1214 return -1; 1215 1216 pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot, 1217 BUS_SPACE_MAP_LINEAR); 1218 1219 if (pa == -1) 1220 pa = scr->fbaddr + offset; 1221 1222 return pa; 1223 } 1224 1225 int 1226 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 1227 int *cxp, int *cyp, long *defattr) 1228 { 1229 struct sti_screen *scr = (struct sti_screen *)v; 1230 1231 if (scr->scr_nscreens > 0) 1232 return ENOMEM; 1233 1234 *cookiep = scr; 1235 *cxp = 0; 1236 *cyp = 0; 1237 sti_alloc_attr(scr, 0, 0, 0, defattr); 1238 scr->scr_nscreens++; 1239 return 0; 1240 } 1241 1242 void 1243 sti_free_screen(void *v, void *cookie) 1244 { 1245 struct sti_screen *scr = (struct sti_screen *)v; 1246 1247 scr->scr_nscreens--; 1248 } 1249 1250 int 1251 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 1252 void *cbarg) 1253 { 1254 #if 0 1255 struct sti_screen *scr = (struct sti_screen *)v; 1256 #endif 1257 1258 return 0; 1259 } 1260 1261 int 1262 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font) 1263 { 1264 #if 0 1265 struct sti_screen *scr = (struct sti_screen *)v; 1266 #endif 1267 1268 return -1; 1269 } 1270 1271 /* 1272 * wsdisplay emulops 1273 */ 1274 void 1275 sti_cursor(void *v, int on, int row, int col) 1276 { 1277 struct sti_screen *scr = (struct sti_screen *)v; 1278 struct sti_font *fp = &scr->scr_curfont; 1279 1280 sti_bmove(scr, 1281 col * fp->width, row * fp->height, 1282 col * fp->width, row * fp->height, 1283 fp->height, fp->width, bmf_invert); 1284 } 1285 1286 /* 1287 * ISO 8859-1 part of Unicode to HP Roman font index conversion array. 1288 */ 1289 static const uint8_t 1290 sti_unitoroman[0x100 - 0xa0] = { 1291 0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc, 0, 0xbd, 1292 0xab, 0, 0xf9, 0xfb, 0, 0xf6, 0, 0xb0, 1293 1294 0xb3, 0xfe, 0, 0, 0xa8, 0xf3, 0xf4, 0xf2, 1295 0, 0, 0xfa, 0xfd, 0xf7, 0xf8, 0, 0xb9, 1296 1297 0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4, 1298 0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7, 1299 1300 0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda, 0, 1301 0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde, 1302 1303 0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5, 1304 0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd, 1305 1306 0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce, 0, 1307 0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef 1308 }; 1309 1310 int 1311 sti_mapchar(void *v, int uni, u_int *index) 1312 { 1313 struct sti_screen *scr = (struct sti_screen *)v; 1314 struct sti_font *fp = &scr->scr_curfont; 1315 int c; 1316 1317 switch (fp->type) { 1318 case STI_FONT_HPROMAN8: 1319 if (uni >= 0x80 && uni < 0xa0) 1320 c = -1; 1321 else if (uni >= 0xa0 && uni < 0x100) { 1322 c = (int)sti_unitoroman[uni - 0xa0]; 1323 if (c == 0) 1324 c = -1; 1325 } else 1326 c = uni; 1327 break; 1328 default: 1329 c = uni; 1330 break; 1331 } 1332 1333 if (c == -1 || c < fp->first || c > fp->last) { 1334 *index = ' '; 1335 return 0; 1336 } 1337 1338 *index = c; 1339 return 5; 1340 } 1341 1342 void 1343 sti_putchar(void *v, int row, int col, u_int uc, long attr) 1344 { 1345 struct sti_screen *scr = (struct sti_screen *)v; 1346 struct sti_rom *rom = scr->scr_rom; 1347 struct sti_font *fp = &scr->scr_curfont; 1348 int bg, fg; 1349 1350 fg = WSATTR_UNPACK_FG(attr); 1351 bg = WSATTR_UNPACK_BG(attr); 1352 1353 if (scr->scr_romfont != NULL) { 1354 /* 1355 * Font is in memory, use unpmv 1356 */ 1357 struct { 1358 struct sti_unpmvflags flags; 1359 struct sti_unpmvin in; 1360 struct sti_unpmvout out; 1361 } a; 1362 1363 memset(&a, 0, sizeof(a)); 1364 1365 a.flags.flags = STI_UNPMVF_WAIT; 1366 a.in.fg_colour = fg; 1367 a.in.bg_colour = bg; 1368 a.in.x = col * fp->width; 1369 a.in.y = row * fp->height; 1370 a.in.font_addr = scr->scr_romfont; 1371 a.in.index = uc; 1372 1373 (*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 1374 } else { 1375 /* 1376 * Font is in frame buffer, use blkmv 1377 */ 1378 struct { 1379 struct sti_blkmvflags flags; 1380 struct sti_blkmvin in; 1381 struct sti_blkmvout out; 1382 } a; 1383 1384 memset(&a, 0, sizeof(a)); 1385 1386 a.flags.flags = STI_BLKMVF_WAIT; 1387 a.in.fg_colour = fg; 1388 a.in.bg_colour = bg; 1389 1390 a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) * 1391 fp->width + scr->scr_fontbase; 1392 a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) * 1393 fp->height; 1394 a.in.dstx = col * fp->width; 1395 a.in.dsty = row * fp->height; 1396 a.in.height = fp->height; 1397 a.in.width = fp->width; 1398 1399 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 1400 } 1401 } 1402 1403 void 1404 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols) 1405 { 1406 struct sti_screen *scr = (struct sti_screen *)v; 1407 struct sti_font *fp = &scr->scr_curfont; 1408 1409 sti_bmove(scr, 1410 srccol * fp->width, row * fp->height, 1411 dstcol * fp->width, row * fp->height, 1412 fp->height, ncols * fp->width, bmf_copy); 1413 } 1414 1415 void 1416 sti_erasecols(void *v, int row, int startcol, int ncols, long attr) 1417 { 1418 struct sti_screen *scr = (struct sti_screen *)v; 1419 struct sti_font *fp = &scr->scr_curfont; 1420 1421 sti_bmove(scr, 1422 startcol * fp->width, row * fp->height, 1423 startcol * fp->width, row * fp->height, 1424 fp->height, ncols * fp->width, bmf_clear); 1425 } 1426 1427 void 1428 sti_copyrows(void *v, int srcrow, int dstrow, int nrows) 1429 { 1430 struct sti_screen *scr = (struct sti_screen *)v; 1431 struct sti_font *fp = &scr->scr_curfont; 1432 1433 sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height, 1434 nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy); 1435 } 1436 1437 void 1438 sti_eraserows(void *v, int srcrow, int nrows, long attr) 1439 { 1440 struct sti_screen *scr = (struct sti_screen *)v; 1441 struct sti_font *fp = &scr->scr_curfont; 1442 1443 sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height, 1444 nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear); 1445 } 1446 1447 int 1448 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr) 1449 { 1450 #if 0 1451 struct sti_screen *scr = (struct sti_screen *)v; 1452 #endif 1453 1454 if ((flags & (WSATTR_HILIT | WSATTR_BLINK | 1455 WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0) 1456 return EINVAL; 1457 if ((flags & WSATTR_REVERSE) != 0) { 1458 fg = STI_COLOUR_BLACK; 1459 bg = STI_COLOUR_WHITE; 1460 } else { 1461 fg = STI_COLOUR_WHITE; 1462 bg = STI_COLOUR_BLACK; 1463 } 1464 1465 *pattr = WSATTR_PACK(fg, bg, flags); 1466 return 0; 1467 } 1468 1469 /* 1470 * Early console support. Only used on hp300, currently 1471 */ 1472 int 1473 sti_cnattach(struct sti_rom *rom, struct sti_screen *scr, bus_space_tag_t memt, 1474 bus_addr_t *bases, u_int codebase) 1475 { 1476 bus_space_handle_t romh; 1477 u_int romend; 1478 int error; 1479 long defattr; 1480 1481 if ((error = bus_space_map(memt, bases[0], PAGE_SIZE, 0, &romh)) != 0) 1482 return error; 1483 1484 /* 1485 * Compute real PROM size 1486 */ 1487 romend = sti_rom_size(memt, romh); 1488 1489 bus_space_unmap(memt, romh, PAGE_SIZE); 1490 1491 if ((error = bus_space_map(memt, bases[0], romend, 0, &romh)) != 0) 1492 return error; 1493 1494 bases[0] = romh; 1495 if (sti_rom_setup(rom, memt, memt, romh, bases, codebase) != 0) 1496 return -1; 1497 scr->scr_rom = rom; 1498 if (sti_screen_setup(scr, STI_CLEARSCR) != 0) 1499 return -1; 1500 1501 sti_alloc_attr(scr, 0, 0, 0, &defattr); 1502 wsdisplay_cnattach(&scr->scr_wsd, scr, 0, 0, defattr); 1503 1504 return 0; 1505 } 1506 1507 int 1508 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count) 1509 { 1510 int i, ret; 1511 1512 for (i = idx + count - 1; i >= (int)idx; i--) 1513 if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i], 1514 scr->scr_gcmap[i], scr->scr_bcmap[i]))) 1515 return EINVAL; 1516 1517 return 0; 1518 } 1519 1520 #ifndef SMALL_KERNEL 1521 1522 void ngle_setup_hw(bus_space_tag_t, bus_space_handle_t); 1523 void ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t); 1524 void ngle_setup_attr_planes(struct sti_screen *scr); 1525 void ngle_setup_bt458(struct sti_screen *scr); 1526 1527 #define ngle_bt458_write(memt, memh, r, v) \ 1528 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24) 1529 1530 void 1531 ngle_artist_setupfb(struct sti_screen *scr) 1532 { 1533 struct sti_rom *rom = scr->scr_rom; 1534 bus_space_tag_t memt = rom->memt; 1535 bus_space_handle_t memh = rom->regh[2]; 1536 1537 ngle_setup_bt458(scr); 1538 1539 ngle_setup_hw(memt, memh); 1540 ngle_setup_fb(memt, memh, scr->reg10_value); 1541 1542 ngle_setup_attr_planes(scr); 1543 1544 ngle_setup_hw(memt, memh); 1545 bus_space_write_stream_4(memt, memh, NGLE_REG_21, 1546 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000); 1547 bus_space_write_stream_4(memt, memh, NGLE_REG_27, 1548 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000); 1549 } 1550 1551 void 1552 ngle_elk_setupfb(struct sti_screen *scr) 1553 { 1554 struct sti_rom *rom = scr->scr_rom; 1555 bus_space_tag_t memt = rom->memt; 1556 bus_space_handle_t memh = rom->regh[2]; 1557 1558 ngle_setup_bt458(scr); 1559 1560 ngle_setup_hw(memt, memh); 1561 ngle_setup_fb(memt, memh, scr->reg10_value); 1562 1563 ngle_setup_attr_planes(scr); 1564 1565 ngle_setup_hw(memt, memh); 1566 /* enable overlay planes in Bt458 command register */ 1567 ngle_bt458_write(memt, memh, 0x0c, 0x06); 1568 ngle_bt458_write(memt, memh, 0x0e, 0x43); 1569 } 1570 1571 void 1572 ngle_timber_setupfb(struct sti_screen *scr) 1573 { 1574 struct sti_rom *rom = scr->scr_rom; 1575 bus_space_tag_t memt = rom->memt; 1576 bus_space_handle_t memh = rom->regh[2]; 1577 1578 ngle_setup_bt458(scr); 1579 1580 ngle_setup_hw(memt, memh); 1581 /* enable overlay planes in Bt458 command register */ 1582 ngle_bt458_write(memt, memh, 0x0c, 0x06); 1583 ngle_bt458_write(memt, memh, 0x0e, 0x43); 1584 } 1585 1586 void 1587 ngle_setup_bt458(struct sti_screen *scr) 1588 { 1589 struct sti_rom *rom = scr->scr_rom; 1590 bus_space_tag_t memt = rom->memt; 1591 bus_space_handle_t memh = rom->regh[2]; 1592 1593 ngle_setup_hw(memt, memh); 1594 /* set Bt458 read mask register to all planes */ 1595 ngle_bt458_write(memt, memh, 0x08, 0x04); 1596 ngle_bt458_write(memt, memh, 0x0a, 0xff); 1597 } 1598 1599 void 1600 ngle_setup_attr_planes(struct sti_screen *scr) 1601 { 1602 struct sti_rom *rom = scr->scr_rom; 1603 bus_space_tag_t memt = rom->memt; 1604 bus_space_handle_t memh = rom->regh[2]; 1605 1606 ngle_setup_hw(memt, memh); 1607 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000); 1608 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302); 1609 bus_space_write_stream_4(memt, memh, NGLE_REG_12, scr->reg12_value); 1610 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff); 1611 1612 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000); 1613 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 1614 (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height); 1615 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000); 1616 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001); 1617 1618 ngle_setup_hw(memt, memh); 1619 bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000); 1620 1621 ngle_setup_fb(memt, memh, scr->reg10_value); 1622 } 1623 1624 int 1625 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count) 1626 { 1627 struct sti_rom *rom = scr->scr_rom; 1628 bus_space_tag_t memt = rom->memt; 1629 bus_space_handle_t memh = rom->regh[2]; 1630 uint8_t *r, *g, *b; 1631 uint32_t cmap_finish; 1632 1633 if (scr->scr_bpp > 8) 1634 cmap_finish = 0x83000100; 1635 else 1636 cmap_finish = 0x80000100; 1637 1638 r = scr->scr_rcmap + idx; 1639 g = scr->scr_gcmap + idx; 1640 b = scr->scr_bcmap + idx; 1641 1642 ngle_setup_hw(memt, memh); 1643 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000); 1644 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300); 1645 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff); 1646 1647 while (count-- != 0) { 1648 ngle_setup_hw(memt, memh); 1649 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 1650 0x400 | (idx << 2)); 1651 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 1652 (*r << 16) | (*g << 8) | *b); 1653 1654 idx++; 1655 r++, g++, b++; 1656 } 1657 1658 1659 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400); 1660 bus_space_write_stream_4(memt, memh, scr->cmap_finish_register, 1661 cmap_finish); 1662 ngle_setup_fb(memt, memh, scr->reg10_value); 1663 1664 1665 return 0; 1666 } 1667 1668 int 1669 ngle_hcrx_putcmap(struct sti_screen *scr, u_int idx, u_int count) 1670 { 1671 struct sti_rom *rom = scr->scr_rom; 1672 bus_space_tag_t memt = rom->memt; 1673 bus_space_handle_t memh = rom->regh[2]; 1674 uint8_t *r, *g, *b; 1675 uint32_t cmap_finish; 1676 1677 if (scr->scr_bpp > 8) 1678 cmap_finish = 0x80000100; 1679 else 1680 cmap_finish = 0x82000100; 1681 1682 r = scr->scr_rcmap + idx; 1683 g = scr->scr_gcmap + idx; 1684 b = scr->scr_bcmap + idx; 1685 1686 ngle_setup_hw(memt, memh); 1687 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000); 1688 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300); 1689 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff); 1690 1691 while (count-- != 0) { 1692 ngle_setup_hw(memt, memh); 1693 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 1694 0x400 | (idx << 2)); 1695 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 1696 (*r << 16) | (*g << 8) | *b); 1697 1698 idx++; 1699 r++, g++, b++; 1700 } 1701 1702 1703 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400); 1704 bus_space_write_stream_4(memt, memh, NGLE_REG_38, cmap_finish); 1705 ngle_setup_fb(memt, memh, scr->reg10_value); 1706 1707 1708 return 0; 1709 } 1710 1711 void 1712 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh) 1713 { 1714 uint8_t stat; 1715 1716 do { 1717 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0); 1718 if (stat == 0) 1719 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0); 1720 } while (stat != 0); 1721 } 1722 1723 void 1724 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10) 1725 { 1726 1727 ngle_setup_hw(memt, memh); 1728 bus_space_write_stream_4(memt, memh, NGLE_REG_10, reg10); 1729 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300); 1730 ngle_setup_hw(memt, memh); 1731 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1); 1732 } 1733 #endif /* SMALL_KERNEL */ 1734