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