1 /* $NetBSD: sti.c,v 1.37 2024/07/03 13:08:36 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.37 2024/07/03 13:08:36 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 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 wsdisplay_fbinfo *wdf; 1077 struct wsdisplay_cmap *cmapp; 1078 u_int mode, idx, count; 1079 int ret; 1080 1081 ret = 0; 1082 switch (cmd) { 1083 case WSDISPLAYIO_GMODE: 1084 *(u_int *)data = scr->scr_wsmode; 1085 break; 1086 1087 case WSDISPLAYIO_SMODE: 1088 mode = *(u_int *)data; 1089 switch (mode) { 1090 case WSDISPLAYIO_MODE_EMUL: 1091 if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL) 1092 ret = sti_init(scr, STI_TEXTMODE); 1093 break; 1094 case WSDISPLAYIO_MODE_DUMBFB: 1095 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) { 1096 ret = sti_init(scr, 0); 1097 if (scr->setupfb != NULL) 1098 scr->setupfb(scr); 1099 else 1100 #if 0 1101 ret = sti_init(scr, STI_FBMODE); 1102 #else 1103 ret = EINVAL; 1104 #endif 1105 } 1106 break; 1107 case WSDISPLAYIO_MODE_MAPPED: 1108 default: 1109 ret = EINVAL; 1110 break; 1111 } 1112 if (ret == 0) 1113 scr->scr_wsmode = mode; 1114 break; 1115 1116 case WSDISPLAYIO_GTYPE: 1117 *(u_int *)data = WSDISPLAY_TYPE_STI; 1118 break; 1119 1120 case WSDISPLAYIO_GINFO: 1121 wdf = (struct wsdisplay_fbinfo *)data; 1122 wdf->height = scr->scr_cfg.scr_height; 1123 wdf->width = scr->scr_cfg.scr_width; 1124 wdf->depth = scr->scr_bpp; 1125 if (scr->putcmap == NULL || scr->scr_bpp > 8) 1126 wdf->cmsize = 0; 1127 else 1128 wdf->cmsize = STI_NCMAP; 1129 break; 1130 1131 case WSDISPLAYIO_LINEBYTES: 1132 if (scr->scr_bpp > 8) 1133 *(u_int *)data = scr->scr_cfg.fb_width * 4; 1134 else 1135 *(u_int *)data = scr->scr_cfg.fb_width; 1136 break; 1137 1138 case WSDISPLAYIO_GETCMAP: 1139 if (scr->putcmap == NULL || scr->scr_bpp > 8) 1140 return ENODEV; 1141 cmapp = (struct wsdisplay_cmap *)data; 1142 idx = cmapp->index; 1143 count = cmapp->count; 1144 if (idx >= STI_NCMAP || count > STI_NCMAP - idx) 1145 return EINVAL; 1146 if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count))) 1147 break; 1148 if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count))) 1149 break; 1150 if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count))) 1151 break; 1152 break; 1153 1154 case WSDISPLAYIO_PUTCMAP: 1155 if (scr->putcmap == NULL || scr->scr_bpp > 8) 1156 return ENODEV; 1157 if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL) { 1158 /* 1159 * The hardware palette settings are handled by 1160 * the STI ROM in STI_TEXTMODE and changing cmap 1161 * could cause mangled text colors at least on CRX. 1162 * Updating CMAP in EMUL mode isn't expected anyway 1163 * so just ignore it. 1164 */ 1165 return 0; 1166 } 1167 cmapp = (struct wsdisplay_cmap *)data; 1168 idx = cmapp->index; 1169 count = cmapp->count; 1170 if (idx >= STI_NCMAP || count > STI_NCMAP - idx) 1171 return EINVAL; 1172 if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count))) 1173 break; 1174 if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count))) 1175 break; 1176 if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count))) 1177 break; 1178 ret = scr->putcmap(scr, idx, count); 1179 break; 1180 1181 case WSDISPLAYIO_SVIDEO: 1182 case WSDISPLAYIO_GVIDEO: 1183 case WSDISPLAYIO_GCURPOS: 1184 case WSDISPLAYIO_SCURPOS: 1185 case WSDISPLAYIO_GCURMAX: 1186 case WSDISPLAYIO_GCURSOR: 1187 case WSDISPLAYIO_SCURSOR: 1188 default: 1189 return ENOTTY; /* not supported yet */ 1190 } 1191 1192 return ret; 1193 } 1194 1195 paddr_t 1196 sti_mmap(void *v, void *vs, off_t offset, int prot) 1197 { 1198 struct sti_screen *scr = (struct sti_screen *)v; 1199 struct sti_rom *rom = scr->scr_rom; 1200 paddr_t pa; 1201 1202 if ((offset & PAGE_MASK) != 0) 1203 return -1; 1204 1205 if (offset < 0 || offset >= scr->fblen) 1206 return -1; 1207 1208 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) 1209 return -1; 1210 1211 pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot, 1212 BUS_SPACE_MAP_LINEAR); 1213 1214 if (pa == -1) 1215 pa = scr->fbaddr + offset; 1216 1217 return pa; 1218 } 1219 1220 int 1221 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 1222 int *cxp, int *cyp, long *defattr) 1223 { 1224 struct sti_screen *scr = (struct sti_screen *)v; 1225 1226 if (scr->scr_nscreens > 0) 1227 return ENOMEM; 1228 1229 *cookiep = scr; 1230 *cxp = 0; 1231 *cyp = 0; 1232 sti_alloc_attr(scr, 0, 0, 0, defattr); 1233 scr->scr_nscreens++; 1234 return 0; 1235 } 1236 1237 void 1238 sti_free_screen(void *v, void *cookie) 1239 { 1240 struct sti_screen *scr = (struct sti_screen *)v; 1241 1242 scr->scr_nscreens--; 1243 } 1244 1245 int 1246 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 1247 void *cbarg) 1248 { 1249 #if 0 1250 struct sti_screen *scr = (struct sti_screen *)v; 1251 #endif 1252 1253 return 0; 1254 } 1255 1256 int 1257 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font) 1258 { 1259 #if 0 1260 struct sti_screen *scr = (struct sti_screen *)v; 1261 #endif 1262 1263 return -1; 1264 } 1265 1266 /* 1267 * wsdisplay emulops 1268 */ 1269 void 1270 sti_cursor(void *v, int on, int row, int col) 1271 { 1272 struct sti_screen *scr = (struct sti_screen *)v; 1273 struct sti_font *fp = &scr->scr_curfont; 1274 1275 sti_bmove(scr, 1276 col * fp->width, row * fp->height, 1277 col * fp->width, row * fp->height, 1278 fp->height, fp->width, bmf_invert); 1279 } 1280 1281 /* 1282 * ISO 8859-1 part of Unicode to HP Roman font index conversion array. 1283 */ 1284 static const uint8_t 1285 sti_unitoroman[0x100 - 0xa0] = { 1286 0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc, 0, 0xbd, 1287 0xab, 0, 0xf9, 0xfb, 0, 0xf6, 0, 0xb0, 1288 1289 0xb3, 0xfe, 0, 0, 0xa8, 0xf3, 0xf4, 0xf2, 1290 0, 0, 0xfa, 0xfd, 0xf7, 0xf8, 0, 0xb9, 1291 1292 0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4, 1293 0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7, 1294 1295 0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda, 0, 1296 0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde, 1297 1298 0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5, 1299 0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd, 1300 1301 0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce, 0, 1302 0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef 1303 }; 1304 1305 int 1306 sti_mapchar(void *v, int uni, u_int *index) 1307 { 1308 struct sti_screen *scr = (struct sti_screen *)v; 1309 struct sti_font *fp = &scr->scr_curfont; 1310 int c; 1311 1312 switch (fp->type) { 1313 case STI_FONT_HPROMAN8: 1314 if (uni >= 0x80 && uni < 0xa0) 1315 c = -1; 1316 else if (uni >= 0xa0 && uni < 0x100) { 1317 c = (int)sti_unitoroman[uni - 0xa0]; 1318 if (c == 0) 1319 c = -1; 1320 } else 1321 c = uni; 1322 break; 1323 default: 1324 c = uni; 1325 break; 1326 } 1327 1328 if (c == -1 || c < fp->first || c > fp->last) { 1329 *index = ' '; 1330 return 0; 1331 } 1332 1333 *index = c; 1334 return 5; 1335 } 1336 1337 void 1338 sti_putchar(void *v, int row, int col, u_int uc, long attr) 1339 { 1340 struct sti_screen *scr = (struct sti_screen *)v; 1341 struct sti_rom *rom = scr->scr_rom; 1342 struct sti_font *fp = &scr->scr_curfont; 1343 int bg, fg; 1344 1345 fg = WSATTR_UNPACK_FG(attr); 1346 bg = WSATTR_UNPACK_BG(attr); 1347 1348 if (scr->scr_romfont != NULL) { 1349 /* 1350 * Font is in memory, use unpmv 1351 */ 1352 struct { 1353 struct sti_unpmvflags flags; 1354 struct sti_unpmvin in; 1355 struct sti_unpmvout out; 1356 } a; 1357 1358 memset(&a, 0, sizeof(a)); 1359 1360 a.flags.flags = STI_UNPMVF_WAIT; 1361 a.in.fg_colour = fg; 1362 a.in.bg_colour = bg; 1363 a.in.x = col * fp->width; 1364 a.in.y = row * fp->height; 1365 a.in.font_addr = scr->scr_romfont; 1366 a.in.index = uc; 1367 1368 (*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 1369 } else { 1370 /* 1371 * Font is in frame buffer, use blkmv 1372 */ 1373 struct { 1374 struct sti_blkmvflags flags; 1375 struct sti_blkmvin in; 1376 struct sti_blkmvout out; 1377 } a; 1378 1379 memset(&a, 0, sizeof(a)); 1380 1381 a.flags.flags = STI_BLKMVF_WAIT; 1382 a.in.fg_colour = fg; 1383 a.in.bg_colour = bg; 1384 1385 a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) * 1386 fp->width + scr->scr_fontbase; 1387 a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) * 1388 fp->height; 1389 a.in.dstx = col * fp->width; 1390 a.in.dsty = row * fp->height; 1391 a.in.height = fp->height; 1392 a.in.width = fp->width; 1393 1394 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg); 1395 } 1396 } 1397 1398 void 1399 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols) 1400 { 1401 struct sti_screen *scr = (struct sti_screen *)v; 1402 struct sti_font *fp = &scr->scr_curfont; 1403 1404 sti_bmove(scr, 1405 srccol * fp->width, row * fp->height, 1406 dstcol * fp->width, row * fp->height, 1407 fp->height, ncols * fp->width, bmf_copy); 1408 } 1409 1410 void 1411 sti_erasecols(void *v, int row, int startcol, int ncols, long attr) 1412 { 1413 struct sti_screen *scr = (struct sti_screen *)v; 1414 struct sti_font *fp = &scr->scr_curfont; 1415 1416 sti_bmove(scr, 1417 startcol * fp->width, row * fp->height, 1418 startcol * fp->width, row * fp->height, 1419 fp->height, ncols * fp->width, bmf_clear); 1420 } 1421 1422 void 1423 sti_copyrows(void *v, int srcrow, int dstrow, int nrows) 1424 { 1425 struct sti_screen *scr = (struct sti_screen *)v; 1426 struct sti_font *fp = &scr->scr_curfont; 1427 1428 sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height, 1429 nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy); 1430 } 1431 1432 void 1433 sti_eraserows(void *v, int srcrow, int nrows, long attr) 1434 { 1435 struct sti_screen *scr = (struct sti_screen *)v; 1436 struct sti_font *fp = &scr->scr_curfont; 1437 1438 sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height, 1439 nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear); 1440 } 1441 1442 int 1443 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr) 1444 { 1445 #if 0 1446 struct sti_screen *scr = (struct sti_screen *)v; 1447 #endif 1448 1449 if ((flags & (WSATTR_HILIT | WSATTR_BLINK | 1450 WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0) 1451 return EINVAL; 1452 if ((flags & WSATTR_REVERSE) != 0) { 1453 fg = STI_COLOUR_BLACK; 1454 bg = STI_COLOUR_WHITE; 1455 } else { 1456 fg = STI_COLOUR_WHITE; 1457 bg = STI_COLOUR_BLACK; 1458 } 1459 1460 *pattr = WSATTR_PACK(fg, bg, flags); 1461 return 0; 1462 } 1463 1464 /* 1465 * Early console support. Only used on hp300, currently 1466 */ 1467 int 1468 sti_cnattach(struct sti_rom *rom, struct sti_screen *scr, bus_space_tag_t memt, 1469 bus_addr_t *bases, u_int codebase) 1470 { 1471 bus_space_handle_t romh; 1472 u_int romend; 1473 int error; 1474 long defattr; 1475 1476 if ((error = bus_space_map(memt, bases[0], PAGE_SIZE, 0, &romh)) != 0) 1477 return error; 1478 1479 /* 1480 * Compute real PROM size 1481 */ 1482 romend = sti_rom_size(memt, romh); 1483 1484 bus_space_unmap(memt, romh, PAGE_SIZE); 1485 1486 if ((error = bus_space_map(memt, bases[0], romend, 0, &romh)) != 0) 1487 return error; 1488 1489 bases[0] = romh; 1490 if (sti_rom_setup(rom, memt, memt, romh, bases, codebase) != 0) 1491 return -1; 1492 scr->scr_rom = rom; 1493 if (sti_screen_setup(scr, STI_CLEARSCR) != 0) 1494 return -1; 1495 1496 sti_alloc_attr(scr, 0, 0, 0, &defattr); 1497 wsdisplay_cnattach(&scr->scr_wsd, scr, 0, 0, defattr); 1498 1499 return 0; 1500 } 1501 1502 int 1503 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count) 1504 { 1505 int i, ret; 1506 1507 for (i = idx + count - 1; i >= (int)idx; i--) 1508 if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i], 1509 scr->scr_gcmap[i], scr->scr_bcmap[i]))) 1510 return EINVAL; 1511 1512 return 0; 1513 } 1514 1515 #ifndef SMALL_KERNEL 1516 1517 void ngle_setup_hw(bus_space_tag_t, bus_space_handle_t); 1518 void ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t); 1519 void ngle_setup_attr_planes(struct sti_screen *scr); 1520 void ngle_setup_bt458(struct sti_screen *scr); 1521 1522 #define ngle_bt458_write(memt, memh, r, v) \ 1523 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24) 1524 1525 void 1526 ngle_artist_setupfb(struct sti_screen *scr) 1527 { 1528 struct sti_rom *rom = scr->scr_rom; 1529 bus_space_tag_t memt = rom->memt; 1530 bus_space_handle_t memh = rom->regh[2]; 1531 1532 ngle_setup_bt458(scr); 1533 1534 ngle_setup_hw(memt, memh); 1535 ngle_setup_fb(memt, memh, scr->reg10_value); 1536 1537 ngle_setup_attr_planes(scr); 1538 1539 ngle_setup_hw(memt, memh); 1540 bus_space_write_stream_4(memt, memh, NGLE_REG_21, 1541 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000); 1542 bus_space_write_stream_4(memt, memh, NGLE_REG_27, 1543 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000); 1544 } 1545 1546 void 1547 ngle_elk_setupfb(struct sti_screen *scr) 1548 { 1549 struct sti_rom *rom = scr->scr_rom; 1550 bus_space_tag_t memt = rom->memt; 1551 bus_space_handle_t memh = rom->regh[2]; 1552 1553 ngle_setup_bt458(scr); 1554 1555 ngle_setup_hw(memt, memh); 1556 ngle_setup_fb(memt, memh, scr->reg10_value); 1557 1558 ngle_setup_attr_planes(scr); 1559 1560 ngle_setup_hw(memt, memh); 1561 /* enable overlay planes in Bt458 command register */ 1562 ngle_bt458_write(memt, memh, 0x0c, 0x06); 1563 ngle_bt458_write(memt, memh, 0x0e, 0x43); 1564 } 1565 1566 void 1567 ngle_timber_setupfb(struct sti_screen *scr) 1568 { 1569 struct sti_rom *rom = scr->scr_rom; 1570 bus_space_tag_t memt = rom->memt; 1571 bus_space_handle_t memh = rom->regh[2]; 1572 1573 ngle_setup_bt458(scr); 1574 1575 ngle_setup_hw(memt, memh); 1576 /* enable overlay planes in Bt458 command register */ 1577 ngle_bt458_write(memt, memh, 0x0c, 0x06); 1578 ngle_bt458_write(memt, memh, 0x0e, 0x43); 1579 } 1580 1581 void 1582 ngle_setup_bt458(struct sti_screen *scr) 1583 { 1584 struct sti_rom *rom = scr->scr_rom; 1585 bus_space_tag_t memt = rom->memt; 1586 bus_space_handle_t memh = rom->regh[2]; 1587 1588 ngle_setup_hw(memt, memh); 1589 /* set Bt458 read mask register to all planes */ 1590 ngle_bt458_write(memt, memh, 0x08, 0x04); 1591 ngle_bt458_write(memt, memh, 0x0a, 0xff); 1592 } 1593 1594 void 1595 ngle_setup_attr_planes(struct sti_screen *scr) 1596 { 1597 struct sti_rom *rom = scr->scr_rom; 1598 bus_space_tag_t memt = rom->memt; 1599 bus_space_handle_t memh = rom->regh[2]; 1600 1601 ngle_setup_hw(memt, memh); 1602 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000); 1603 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302); 1604 bus_space_write_stream_4(memt, memh, NGLE_REG_12, scr->reg12_value); 1605 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff); 1606 1607 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000); 1608 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 1609 (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height); 1610 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000); 1611 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001); 1612 1613 ngle_setup_hw(memt, memh); 1614 bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000); 1615 1616 ngle_setup_fb(memt, memh, scr->reg10_value); 1617 } 1618 1619 int 1620 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count) 1621 { 1622 struct sti_rom *rom = scr->scr_rom; 1623 bus_space_tag_t memt = rom->memt; 1624 bus_space_handle_t memh = rom->regh[2]; 1625 uint8_t *r, *g, *b; 1626 uint32_t cmap_finish; 1627 1628 if (scr->scr_bpp > 8) 1629 cmap_finish = 0x83000100; 1630 else 1631 cmap_finish = 0x80000100; 1632 1633 r = scr->scr_rcmap + idx; 1634 g = scr->scr_gcmap + idx; 1635 b = scr->scr_bcmap + idx; 1636 1637 ngle_setup_hw(memt, memh); 1638 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000); 1639 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300); 1640 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff); 1641 1642 while (count-- != 0) { 1643 ngle_setup_hw(memt, memh); 1644 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 1645 0x400 | (idx << 2)); 1646 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 1647 (*r << 16) | (*g << 8) | *b); 1648 1649 idx++; 1650 r++, g++, b++; 1651 } 1652 1653 1654 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400); 1655 bus_space_write_stream_4(memt, memh, scr->cmap_finish_register, 1656 cmap_finish); 1657 ngle_setup_fb(memt, memh, scr->reg10_value); 1658 1659 1660 return 0; 1661 } 1662 1663 int 1664 ngle_hcrx_putcmap(struct sti_screen *scr, u_int idx, u_int count) 1665 { 1666 struct sti_rom *rom = scr->scr_rom; 1667 bus_space_tag_t memt = rom->memt; 1668 bus_space_handle_t memh = rom->regh[2]; 1669 uint8_t *r, *g, *b; 1670 uint32_t cmap_finish; 1671 1672 if (scr->scr_bpp > 8) 1673 cmap_finish = 0x80000100; 1674 else 1675 cmap_finish = 0x82000100; 1676 1677 r = scr->scr_rcmap + idx; 1678 g = scr->scr_gcmap + idx; 1679 b = scr->scr_bcmap + idx; 1680 1681 ngle_setup_hw(memt, memh); 1682 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000); 1683 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300); 1684 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff); 1685 1686 while (count-- != 0) { 1687 ngle_setup_hw(memt, memh); 1688 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 1689 0x400 | (idx << 2)); 1690 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 1691 (*r << 16) | (*g << 8) | *b); 1692 1693 idx++; 1694 r++, g++, b++; 1695 } 1696 1697 1698 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400); 1699 bus_space_write_stream_4(memt, memh, NGLE_REG_38, cmap_finish); 1700 ngle_setup_fb(memt, memh, scr->reg10_value); 1701 1702 1703 return 0; 1704 } 1705 1706 void 1707 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh) 1708 { 1709 uint8_t stat; 1710 1711 do { 1712 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0); 1713 if (stat == 0) 1714 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0); 1715 } while (stat != 0); 1716 } 1717 1718 void 1719 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10) 1720 { 1721 1722 ngle_setup_hw(memt, memh); 1723 bus_space_write_stream_4(memt, memh, NGLE_REG_10, reg10); 1724 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300); 1725 ngle_setup_hw(memt, memh); 1726 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1); 1727 } 1728 #endif /* SMALL_KERNEL */ 1729