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