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