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