xref: /netbsd-src/sys/dev/ic/sti.c (revision b5c47949a45ac972130c38cf13dfd8afb1f09285)
1 /*	$NetBSD: sti.c,v 1.29 2021/03/14 08:13:58 skrll 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.29 2021/03/14 08:13:58 skrll 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 	}
771 #endif
772 }
773 
774 u_int
775 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh)
776 {
777 	int devtype;
778 	u_int romend;
779 
780 	devtype = bus_space_read_1(memt, romh, 3);
781 	if (devtype == STI_DEVTYPE4) {
782 		bus_space_read_region_stream_4(memt, romh, STI_DEV4_DD_ROMEND,
783 		    (uint32_t *)&romend, 1);
784 	} else {
785 		romend = parseword(STI_DEV1_DD_ROMEND);
786 	}
787 
788 	DPRINTF(("%s: %08x (%08x)\n", __func__, romend, round_page(romend)));
789 
790 	return round_page(romend);
791 }
792 
793 int
794 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *cfg,
795     uint32_t baseaddr, u_int fontindex)
796 {
797 	struct sti_rom *rom = scr->scr_rom;
798 	bus_space_tag_t memt = rom->memt;
799 	bus_space_handle_t romh = rom->romh;
800 	struct sti_font *fp = &scr->scr_curfont;
801 	uint32_t addr;
802 	int size;
803 #ifdef notyet
804 	int uc;
805 	struct {
806 		struct sti_unpmvflags flags;
807 		struct sti_unpmvin in;
808 		struct sti_unpmvout out;
809 	} a;
810 #endif
811 
812 	/*
813 	 * Get the first PROM font in memory
814 	 */
815 
816 	STI_ENABLE_ROM(rom->rom_softc);
817 
818 rescan:
819 	addr = baseaddr;
820 	do {
821 		if (rom->rom_devtype == STI_DEVTYPE1) {
822 			fp->first  = parseshort(addr + 0x00);
823 			fp->last   = parseshort(addr + 0x08);
824 			fp->width  = bus_space_read_1(memt, romh, addr + 0x13);
825 			fp->height = bus_space_read_1(memt, romh, addr + 0x17);
826 			fp->type   = bus_space_read_1(memt, romh, addr + 0x1b);
827 			fp->bpc    = bus_space_read_1(memt, romh, addr + 0x1f);
828 			fp->next   = parseword(addr + 0x20);
829 			fp->uheight= bus_space_read_1(memt, romh, addr + 0x33);
830 			fp->uoffset= bus_space_read_1(memt, romh, addr + 0x37);
831 		} else {	/* STI_DEVTYPE4 */
832 			bus_space_read_region_stream_4(memt, romh, addr,
833 			    (uint32_t *)fp, sizeof(struct sti_font) / 4);
834 		}
835 
836 #ifdef STIDEBUG
837 		STI_DISABLE_ROM(rom->rom_softc);
838 		DPRINTF(("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
839 		    device_xname(scr->scr_rom->rom_softc->sc_dev), fp->width,
840 		    fp->height, fp->type, fp->bpc, fp->first, fp->last));
841 		STI_ENABLE_ROM(rom->rom_softc);
842 #endif
843 
844 		if (fontindex == 0) {
845 			size = sizeof(struct sti_font) +
846 			    (fp->last - fp->first + 1) * fp->bpc;
847 			if (rom->rom_devtype == STI_DEVTYPE1)
848 				size *= 4;
849 			scr->scr_romfont = malloc(size, M_DEVBUF, M_WAITOK);
850 
851 			bus_space_read_region_stream_4(memt, romh, addr,
852 			    (uint32_t *)scr->scr_romfont, size / 4);
853 			break;
854 		}
855 
856 		addr = baseaddr + fp->next;
857 		fontindex--;
858 	} while (fp->next != 0);
859 
860 	/*
861 	 * If our font index was bogus, we did not find the expected font.
862 	 * In this case, pick the first one and be done with it.
863 	 */
864 	if (fp->next == 0 && scr->scr_romfont == NULL) {
865 		fontindex = 0;
866 		goto rescan;
867 	}
868 
869 	STI_DISABLE_ROM(rom->rom_softc);
870 
871 #ifdef notyet
872 	/*
873 	 * If there is enough room in the off-screen framebuffer memory,
874 	 * display all the characters there in order to display them
875 	 * faster with blkmv operations rather than unpmv later on.
876 	 */
877 	if (size <= cfg->fbheight *
878 	    (cfg->fbwidth - cfg->width - cfg->owidth)) {
879 		memset(&a, 0, sizeof(a));
880 		a.flags.flags = STI_UNPMVF_WAIT;
881 		a.in.fg_colour = STI_COLOUR_WHITE;
882 		a.in.bg_colour = STI_COLOUR_BLACK;
883 		a.in.font_addr = scr->scr_romfont;
884 
885 		scr->scr_fontmaxcol = cfg->fbheight / fp->height;
886 		scr->scr_fontbase = cfg->width + cfg->owidth;
887 		for (uc = fp->first; uc <= fp->last; uc++) {
888 			a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) *
889 			    fp->width + scr->scr_fontbase;
890 			a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) *
891 			    fp->height;
892 			a.in.index = uc;
893 
894 			(*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
895 			if (a.out.errno) {
896 				aprint_error_dev(sc->sc_dev, "unpmv %d "
897 				    "returned %d\n", uc, a.out.errno);
898 				return 0;
899 			}
900 		}
901 
902 		free(scr->scr_romfont, M_DEVBUF);
903 		scr->scr_romfont = NULL;
904 	}
905 #endif
906 
907 	return 0;
908 }
909 
910 /*
911  * Wrappers around STI code pointers
912  */
913 
914 int
915 sti_init(struct sti_screen *scr, int mode)
916 {
917 	struct sti_rom *rom = scr->scr_rom;
918 	struct {
919 		struct sti_initflags flags;
920 		struct sti_initin in;
921 		struct sti_einitin ein;
922 		struct sti_initout out;
923 	} a;
924 
925 	KASSERT(rom != NULL);
926 	memset(&a, 0, sizeof(a));
927 
928 	a.flags.flags = STI_INITF_WAIT | STI_INITF_EBET;
929 	if ((mode & STI_TEXTMODE) != 0) {
930 		a.flags.flags |= STI_INITF_TEXT | STI_INITF_CMB |
931 		    STI_INITF_PBET | STI_INITF_PBETI | STI_INITF_ICMT;
932 	} else {
933 		a.flags.flags |= STI_INITF_NTEXT;
934 	}
935 	if ((mode & STI_CLEARSCR) != 0)
936 		a.flags.flags |= STI_INITF_CLEAR;
937 
938 	a.in.text_planes = 1;
939 	a.in.ext_in = &a.ein;
940 
941 	DPRINTF(("%s: init,%p(%x, %p, %p, %p)\n",
942 	    device_xname(rom->rom_softc->sc_dev), rom->init, a.flags.flags,
943 	    &a.in, &a.out, &scr->scr_cfg));
944 
945 	(*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
946 
947 	if (a.out.text_planes != a.in.text_planes)
948 		return -1;	/* not colliding with sti errno values */
949 	return a.out.errno;
950 }
951 
952 int
953 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out)
954 {
955 	struct sti_rom *rom = scr->scr_rom;
956 	struct {
957 		struct sti_inqconfflags flags;
958 		struct sti_inqconfin in;
959 	} a;
960 
961 	memset(&a, 0, sizeof(a));
962 
963 	a.flags.flags = STI_INQCONFF_WAIT;
964 	(*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg);
965 
966 	return out->errno;
967 }
968 
969 void
970 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w,
971     enum sti_bmove_funcs f)
972 {
973 	struct sti_rom *rom = scr->scr_rom;
974 	struct {
975 		struct sti_blkmvflags flags;
976 		struct sti_blkmvin in;
977 		struct sti_blkmvout out;
978 	} a;
979 
980 	memset(&a, 0, sizeof(a));
981 
982 	a.flags.flags = STI_BLKMVF_WAIT;
983 	switch (f) {
984 	case bmf_clear:
985 		a.flags.flags |= STI_BLKMVF_CLR;
986 		a.in.bg_colour = STI_COLOUR_BLACK;
987 		break;
988 	case bmf_underline:
989 	case bmf_copy:
990 		a.in.fg_colour = STI_COLOUR_WHITE;
991 		a.in.bg_colour = STI_COLOUR_BLACK;
992 		break;
993 	case bmf_invert:
994 		a.flags.flags |= STI_BLKMVF_COLR;
995 		a.in.fg_colour = STI_COLOUR_BLACK;
996 		a.in.bg_colour = STI_COLOUR_WHITE;
997 		break;
998 	}
999 	a.in.srcx = x1;
1000 	a.in.srcy = y1;
1001 	a.in.dstx = x2;
1002 	a.in.dsty = y2;
1003 	a.in.height = h;
1004 	a.in.width = w;
1005 
1006 	(*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1007 #ifdef STIDEBUG
1008 	if (a.out.errno)
1009 		printf("%s: blkmv returned %d\n",
1010 		    device_xname(rom->rom_softc->sc_dev), a.out.errno);
1011 #endif
1012 }
1013 
1014 int
1015 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b)
1016 {
1017 	struct sti_rom *rom = scr->scr_rom;
1018 	struct {
1019 		struct sti_scmentflags flags;
1020 		struct sti_scmentin in;
1021 		struct sti_scmentout out;
1022 	} a;
1023 
1024 	memset(&a, 0, sizeof(a));
1025 
1026 	a.flags.flags = STI_SCMENTF_WAIT;
1027 	a.in.entry = i;
1028 	a.in.value = (r << 16) | (g << 8) | b;
1029 
1030 	(*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1031 
1032 	return a.out.errno;
1033 }
1034 
1035 /*
1036  * wsdisplay accessops
1037  */
1038 int
1039 sti_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
1040 {
1041 	struct sti_screen *scr = (struct sti_screen *)v;
1042 	struct wsdisplay_fbinfo *wdf;
1043 	struct wsdisplay_cmap *cmapp;
1044 	u_int mode, idx, count;
1045 	int ret;
1046 
1047 	ret = 0;
1048 	switch (cmd) {
1049 	case WSDISPLAYIO_GMODE:
1050 		*(u_int *)data = scr->scr_wsmode;
1051 		break;
1052 
1053 	case WSDISPLAYIO_SMODE:
1054 		mode = *(u_int *)data;
1055 		switch (mode) {
1056 		case WSDISPLAYIO_MODE_EMUL:
1057 			if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL)
1058 				ret = sti_init(scr, STI_TEXTMODE);
1059 			break;
1060 		case WSDISPLAYIO_MODE_DUMBFB:
1061 			if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) {
1062 				sti_init(scr, 0);
1063 				if (scr->setupfb != NULL)
1064 					scr->setupfb(scr);
1065 				else
1066 #if 0
1067 					ret = sti_init(scr, STI_FBMODE);
1068 #else
1069 					ret = EINVAL;
1070 #endif
1071 			}
1072 			break;
1073 		case WSDISPLAYIO_MODE_MAPPED:
1074 		default:
1075 			ret = EINVAL;
1076 			break;
1077 		}
1078 		if (ret == 0)
1079 			scr->scr_wsmode = mode;
1080 		break;
1081 
1082 	case WSDISPLAYIO_GTYPE:
1083 		*(u_int *)data = WSDISPLAY_TYPE_STI;
1084 		break;
1085 
1086 	case WSDISPLAYIO_GINFO:
1087 		wdf = (struct wsdisplay_fbinfo *)data;
1088 		wdf->height = scr->scr_cfg.scr_height;
1089 		wdf->width  = scr->scr_cfg.scr_width;
1090 		wdf->depth  = scr->scr_bpp;
1091 		if (scr->putcmap == NULL || scr->scr_bpp > 8)
1092 			wdf->cmsize = 0;
1093 		else
1094 			wdf->cmsize = STI_NCMAP;
1095 		break;
1096 
1097 	case WSDISPLAYIO_LINEBYTES:
1098 		if (scr->scr_bpp > 8)
1099 			*(u_int *)data = scr->scr_cfg.fb_width * 4;
1100 		else
1101 			*(u_int *)data = scr->scr_cfg.fb_width;
1102 		break;
1103 
1104 	case WSDISPLAYIO_GETCMAP:
1105 		if (scr->putcmap == NULL || scr->scr_bpp > 8)
1106 			return ENODEV;
1107 		cmapp = (struct wsdisplay_cmap *)data;
1108 		idx = cmapp->index;
1109 		count = cmapp->count;
1110 		if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1111 			return EINVAL;
1112 		if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
1113 			break;
1114 		if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
1115 			break;
1116 		if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
1117 			break;
1118 		break;
1119 
1120 	case WSDISPLAYIO_PUTCMAP:
1121 		if (scr->putcmap == NULL || scr->scr_bpp > 8)
1122 			return ENODEV;
1123 		if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL) {
1124 			/*
1125 			 * The hardware palette settings are handled by
1126 			 * the STI ROM in STI_TEXTMODE and changing cmap
1127 			 * could cause mangled text colors at least on CRX.
1128 			 * Updating CMAP in EMUL mode isn't expected anyway
1129 			 * so just ignore it.
1130 			 */
1131 			return 0;
1132 		}
1133 		cmapp = (struct wsdisplay_cmap *)data;
1134 		idx = cmapp->index;
1135 		count = cmapp->count;
1136 		if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1137 			return EINVAL;
1138 		if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
1139 			break;
1140 		if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
1141 			break;
1142 		if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
1143 			break;
1144 		ret = scr->putcmap(scr, idx, count);
1145 		break;
1146 
1147 	case WSDISPLAYIO_SVIDEO:
1148 	case WSDISPLAYIO_GVIDEO:
1149 	case WSDISPLAYIO_GCURPOS:
1150 	case WSDISPLAYIO_SCURPOS:
1151 	case WSDISPLAYIO_GCURMAX:
1152 	case WSDISPLAYIO_GCURSOR:
1153 	case WSDISPLAYIO_SCURSOR:
1154 	default:
1155 		return ENOTTY;	/* not supported yet */
1156 	}
1157 
1158 	return ret;
1159 }
1160 
1161 paddr_t
1162 sti_mmap(void *v, void *vs, off_t offset, int prot)
1163 {
1164 	struct sti_screen *scr = (struct sti_screen *)v;
1165 	struct sti_rom *rom = scr->scr_rom;
1166 	paddr_t pa;
1167 
1168 	if ((offset & PAGE_MASK) != 0)
1169 		return -1;
1170 
1171 	if (offset < 0 || offset >= scr->fblen)
1172 		return -1;
1173 
1174 	if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB)
1175 		return -1;
1176 
1177 	pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot,
1178 	    BUS_SPACE_MAP_LINEAR);
1179 
1180 	if (pa == -1)
1181 		pa = scr->fbaddr + offset;
1182 
1183 	return pa;
1184 }
1185 
1186 int
1187 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1188     int *cxp, int *cyp, long *defattr)
1189 {
1190 	struct sti_screen *scr = (struct sti_screen *)v;
1191 
1192 	if (scr->scr_nscreens > 0)
1193 		return ENOMEM;
1194 
1195 	*cookiep = scr;
1196 	*cxp = 0;
1197 	*cyp = 0;
1198 	sti_alloc_attr(scr, 0, 0, 0, defattr);
1199 	scr->scr_nscreens++;
1200 	return 0;
1201 }
1202 
1203 void
1204 sti_free_screen(void *v, void *cookie)
1205 {
1206 	struct sti_screen *scr = (struct sti_screen *)v;
1207 
1208 	scr->scr_nscreens--;
1209 }
1210 
1211 int
1212 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
1213     void *cbarg)
1214 {
1215 #if 0
1216 	struct sti_screen *scr = (struct sti_screen *)v;
1217 #endif
1218 
1219 	return 0;
1220 }
1221 
1222 int
1223 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font)
1224 {
1225 #if 0
1226 	struct sti_screen *scr = (struct sti_screen *)v;
1227 #endif
1228 
1229 	return -1;
1230 }
1231 
1232 /*
1233  * wsdisplay emulops
1234  */
1235 void
1236 sti_cursor(void *v, int on, int row, int col)
1237 {
1238 	struct sti_screen *scr = (struct sti_screen *)v;
1239 	struct sti_font *fp = &scr->scr_curfont;
1240 
1241 	sti_bmove(scr,
1242 	    col * fp->width, row * fp->height,
1243 	    col * fp->width, row * fp->height,
1244 	    fp->height, fp->width, bmf_invert);
1245 }
1246 
1247 /*
1248  * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
1249  */
1250 static const uint8_t
1251 sti_unitoroman[0x100 - 0xa0] = {
1252 	0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc,    0, 0xbd,
1253 	0xab,    0, 0xf9, 0xfb,    0, 0xf6,    0, 0xb0,
1254 
1255 	0xb3, 0xfe,    0,    0, 0xa8, 0xf3, 0xf4, 0xf2,
1256 	   0,    0, 0xfa, 0xfd, 0xf7, 0xf8,    0, 0xb9,
1257 
1258 	0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
1259 	0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
1260 
1261 	0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda,    0,
1262 	0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
1263 
1264 	0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
1265 	0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
1266 
1267 	0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce,    0,
1268 	0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
1269 };
1270 
1271 int
1272 sti_mapchar(void *v, int uni, u_int *index)
1273 {
1274 	struct sti_screen *scr = (struct sti_screen *)v;
1275 	struct sti_font *fp = &scr->scr_curfont;
1276 	int c;
1277 
1278 	switch (fp->type) {
1279 	case STI_FONT_HPROMAN8:
1280 		if (uni >= 0x80 && uni < 0xa0)
1281 			c = -1;
1282 		else if (uni >= 0xa0 && uni < 0x100) {
1283 			c = (int)sti_unitoroman[uni - 0xa0];
1284 			if (c == 0)
1285 				c = -1;
1286 		} else
1287 			c = uni;
1288 		break;
1289 	default:
1290 		c = uni;
1291 		break;
1292 	}
1293 
1294 	if (c == -1 || c < fp->first || c > fp->last) {
1295 		*index = ' ';
1296 		return 0;
1297 	}
1298 
1299 	*index = c;
1300 	return 5;
1301 }
1302 
1303 void
1304 sti_putchar(void *v, int row, int col, u_int uc, long attr)
1305 {
1306 	struct sti_screen *scr = (struct sti_screen *)v;
1307 	struct sti_rom *rom = scr->scr_rom;
1308 	struct sti_font *fp = &scr->scr_curfont;
1309 	int bg, fg;
1310 
1311 	fg = WSATTR_UNPACK_FG(attr);
1312 	bg = WSATTR_UNPACK_BG(attr);
1313 
1314 	if (scr->scr_romfont != NULL) {
1315 		/*
1316 		 * Font is in memory, use unpmv
1317 		 */
1318 		struct {
1319 			struct sti_unpmvflags flags;
1320 			struct sti_unpmvin in;
1321 			struct sti_unpmvout out;
1322 		} a;
1323 
1324 		memset(&a, 0, sizeof(a));
1325 
1326 		a.flags.flags = STI_UNPMVF_WAIT;
1327 		a.in.fg_colour = fg;
1328 		a.in.bg_colour = bg;
1329 		a.in.x = col * fp->width;
1330 		a.in.y = row * fp->height;
1331 		a.in.font_addr = scr->scr_romfont;
1332 		a.in.index = uc;
1333 
1334 		(*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1335 	} else {
1336 		/*
1337 		 * Font is in frame buffer, use blkmv
1338 		 */
1339 		struct {
1340 			struct sti_blkmvflags flags;
1341 			struct sti_blkmvin in;
1342 			struct sti_blkmvout out;
1343 		} a;
1344 
1345 		memset(&a, 0, sizeof(a));
1346 
1347 		a.flags.flags = STI_BLKMVF_WAIT;
1348 		a.in.fg_colour = fg;
1349 		a.in.bg_colour = bg;
1350 
1351 		a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
1352 		    fp->width + scr->scr_fontbase;
1353 		a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
1354 		    fp->height;
1355 		a.in.dstx = col * fp->width;
1356 		a.in.dsty = row * fp->height;
1357 		a.in.height = fp->height;
1358 		a.in.width = fp->width;
1359 
1360 		(*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1361 	}
1362 }
1363 
1364 void
1365 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
1366 {
1367 	struct sti_screen *scr = (struct sti_screen *)v;
1368 	struct sti_font *fp = &scr->scr_curfont;
1369 
1370 	sti_bmove(scr,
1371 	    srccol * fp->width, row * fp->height,
1372 	    dstcol * fp->width, row * fp->height,
1373 	    fp->height, ncols * fp->width, bmf_copy);
1374 }
1375 
1376 void
1377 sti_erasecols(void *v, int row, int startcol, int ncols, long attr)
1378 {
1379 	struct sti_screen *scr = (struct sti_screen *)v;
1380 	struct sti_font *fp = &scr->scr_curfont;
1381 
1382 	sti_bmove(scr,
1383 	    startcol * fp->width, row * fp->height,
1384 	    startcol * fp->width, row * fp->height,
1385 	    fp->height, ncols * fp->width, bmf_clear);
1386 }
1387 
1388 void
1389 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
1390 {
1391 	struct sti_screen *scr = (struct sti_screen *)v;
1392 	struct sti_font *fp = &scr->scr_curfont;
1393 
1394 	sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
1395 	    nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
1396 }
1397 
1398 void
1399 sti_eraserows(void *v, int srcrow, int nrows, long attr)
1400 {
1401 	struct sti_screen *scr = (struct sti_screen *)v;
1402 	struct sti_font *fp = &scr->scr_curfont;
1403 
1404 	sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
1405 	    nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
1406 }
1407 
1408 int
1409 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr)
1410 {
1411 #if 0
1412 	struct sti_screen *scr = (struct sti_screen *)v;
1413 #endif
1414 
1415 	if ((flags & (WSATTR_HILIT | WSATTR_BLINK |
1416 	    WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0)
1417 		return EINVAL;
1418 	if ((flags & WSATTR_REVERSE) != 0) {
1419 		fg = STI_COLOUR_BLACK;
1420 		bg = STI_COLOUR_WHITE;
1421 	} else {
1422 		fg = STI_COLOUR_WHITE;
1423 		bg = STI_COLOUR_BLACK;
1424 	}
1425 
1426 	*pattr = WSATTR_PACK(fg, bg, flags);
1427 	return 0;
1428 }
1429 
1430 /*
1431  * Early console support.  Only used on hp300, currently
1432  */
1433 int
1434 sti_cnattach(struct sti_rom *rom, struct sti_screen *scr, bus_space_tag_t memt,
1435     bus_addr_t *bases, u_int codebase)
1436 {
1437 	bus_space_handle_t romh;
1438 	u_int romend;
1439 	int error;
1440 	long defattr;
1441 
1442 	if ((error = bus_space_map(memt, bases[0], PAGE_SIZE, 0, &romh)) != 0)
1443 		return error;
1444 
1445 	/*
1446 	 * Compute real PROM size
1447 	 */
1448 	romend = sti_rom_size(memt, romh);
1449 
1450 	bus_space_unmap(memt, romh, PAGE_SIZE);
1451 
1452 	if ((error = bus_space_map(memt, bases[0], romend, 0, &romh)) != 0)
1453 		return error;
1454 
1455 	bases[0] = romh;
1456 	if (sti_rom_setup(rom, memt, memt, romh, bases, codebase) != 0)
1457 		return -1;
1458 	scr->scr_rom = rom;
1459 	if (sti_screen_setup(scr, STI_CLEARSCR) != 0)
1460 		return -1;
1461 
1462 	sti_alloc_attr(scr, 0, 0, 0, &defattr);
1463 	wsdisplay_cnattach(&scr->scr_wsd, scr, 0, 0, defattr);
1464 
1465 	return 0;
1466 }
1467 
1468 int
1469 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1470 {
1471 	int i, ret;
1472 
1473 	for (i = idx + count - 1; i >= (int)idx; i--)
1474 		if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
1475 		    scr->scr_gcmap[i], scr->scr_bcmap[i])))
1476 			return EINVAL;
1477 
1478 	return 0;
1479 }
1480 
1481 #ifndef SMALL_KERNEL
1482 
1483 void	ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
1484 void	ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
1485 void	ngle_setup_attr_planes(struct sti_screen *scr);
1486 void	ngle_setup_bt458(struct sti_screen *scr);
1487 
1488 #define	ngle_bt458_write(memt, memh, r, v) \
1489 	bus_space_write_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
1490 
1491 void
1492 ngle_artist_setupfb(struct sti_screen *scr)
1493 {
1494 	struct sti_rom *rom = scr->scr_rom;
1495 	bus_space_tag_t memt = rom->memt;
1496 	bus_space_handle_t memh = rom->regh[2];
1497 
1498 	ngle_setup_bt458(scr);
1499 
1500 	ngle_setup_hw(memt, memh);
1501 	ngle_setup_fb(memt, memh, scr->reg10_value);
1502 
1503 	ngle_setup_attr_planes(scr);
1504 
1505 	ngle_setup_hw(memt, memh);
1506 	bus_space_write_4(memt, memh, NGLE_REG_21,
1507 	    bus_space_read_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1508 	bus_space_write_4(memt, memh, NGLE_REG_27,
1509 	    bus_space_read_4(memt, memh, NGLE_REG_27) | 0x00800000);
1510 }
1511 
1512 void
1513 ngle_elk_setupfb(struct sti_screen *scr)
1514 {
1515 	struct sti_rom *rom = scr->scr_rom;
1516 	bus_space_tag_t memt = rom->memt;
1517 	bus_space_handle_t memh = rom->regh[2];
1518 
1519 	ngle_setup_bt458(scr);
1520 
1521 	ngle_setup_hw(memt, memh);
1522 	ngle_setup_fb(memt, memh, scr->reg10_value);
1523 
1524 	ngle_setup_attr_planes(scr);
1525 
1526 	ngle_setup_hw(memt, memh);
1527 	/* enable overlay planes in Bt458 command register */
1528 	ngle_bt458_write(memt, memh, 0x0c, 0x06);
1529 	ngle_bt458_write(memt, memh, 0x0e, 0x43);
1530 }
1531 
1532 void
1533 ngle_timber_setupfb(struct sti_screen *scr)
1534 {
1535 	struct sti_rom *rom = scr->scr_rom;
1536 	bus_space_tag_t memt = rom->memt;
1537 	bus_space_handle_t memh = rom->regh[2];
1538 
1539 	ngle_setup_bt458(scr);
1540 
1541 	ngle_setup_hw(memt, memh);
1542 	/* enable overlay planes in Bt458 command register */
1543 	ngle_bt458_write(memt, memh, 0x0c, 0x06);
1544 	ngle_bt458_write(memt, memh, 0x0e, 0x43);
1545 }
1546 
1547 void
1548 ngle_setup_bt458(struct sti_screen *scr)
1549 {
1550 	struct sti_rom *rom = scr->scr_rom;
1551 	bus_space_tag_t memt = rom->memt;
1552 	bus_space_handle_t memh = rom->regh[2];
1553 
1554 	ngle_setup_hw(memt, memh);
1555 	/* set Bt458 read mask register to all planes */
1556 	ngle_bt458_write(memt, memh, 0x08, 0x04);
1557 	ngle_bt458_write(memt, memh, 0x0a, 0xff);
1558 }
1559 
1560 void
1561 ngle_setup_attr_planes(struct sti_screen *scr)
1562 {
1563 	struct sti_rom *rom = scr->scr_rom;
1564 	bus_space_tag_t memt = rom->memt;
1565 	bus_space_handle_t memh = rom->regh[2];
1566 
1567 	ngle_setup_hw(memt, memh);
1568 	bus_space_write_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
1569 	bus_space_write_4(memt, memh, NGLE_REG_14, 0x23000302);
1570 	bus_space_write_4(memt, memh, NGLE_REG_12, scr->reg12_value);
1571 	bus_space_write_4(memt, memh, NGLE_REG_8, 0xffffffff);
1572 
1573 	bus_space_write_4(memt, memh, NGLE_REG_6, 0x00000000);
1574 	bus_space_write_4(memt, memh, NGLE_REG_9,
1575 	    (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height);
1576 	bus_space_write_4(memt, memh, NGLE_REG_6, 0x05000000);
1577 	bus_space_write_4(memt, memh, NGLE_REG_9, 0x00040001);
1578 
1579 	ngle_setup_hw(memt, memh);
1580 	bus_space_write_4(memt, memh, NGLE_REG_12, 0x00000000);
1581 
1582 	ngle_setup_fb(memt, memh, scr->reg10_value);
1583 }
1584 
1585 int
1586 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1587 {
1588 	struct sti_rom *rom = scr->scr_rom;
1589 	bus_space_tag_t memt = rom->memt;
1590 	bus_space_handle_t memh = rom->regh[2];
1591 	uint8_t *r, *g, *b;
1592 	uint32_t cmap_finish;
1593 
1594 	if (scr->scr_bpp > 8)
1595 		cmap_finish = 0x83000100;
1596 	else
1597 		cmap_finish = 0x80000100;
1598 
1599 	r = scr->scr_rcmap + idx;
1600 	g = scr->scr_gcmap + idx;
1601 	b = scr->scr_bcmap + idx;
1602 
1603 	ngle_setup_hw(memt, memh);
1604 	bus_space_write_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1605 	bus_space_write_4(memt, memh, NGLE_REG_14, 0x03000300);
1606 	bus_space_write_4(memt, memh, NGLE_REG_13, 0xffffffff);
1607 
1608 	while (count-- != 0) {
1609 		ngle_setup_hw(memt, memh);
1610 		bus_space_write_4(memt, memh, NGLE_REG_3, 0x400 | (idx << 2));
1611 		bus_space_write_4(memt, memh, NGLE_REG_4,
1612 		    (*r << 16) | (*g << 8) | *b);
1613 
1614 		idx++;
1615 		r++, g++, b++;
1616 	}
1617 
1618 	bus_space_write_4(memt, memh, NGLE_REG_2, 0x400);
1619 	bus_space_write_4(memt, memh, scr->cmap_finish_register, cmap_finish);
1620 	ngle_setup_fb(memt, memh, scr->reg10_value);
1621 
1622 
1623 	return 0;
1624 }
1625 
1626 void
1627 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh)
1628 {
1629 	uint8_t stat;
1630 
1631 	do {
1632 		stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1633 		if (stat == 0)
1634 			stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1635 	} while (stat != 0);
1636 }
1637 
1638 void
1639 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10)
1640 {
1641 
1642 	ngle_setup_hw(memt, memh);
1643 	bus_space_write_4(memt, memh, NGLE_REG_10, reg10);
1644 	bus_space_write_4(memt, memh, NGLE_REG_14, 0x83000300);
1645 	ngle_setup_hw(memt, memh);
1646 	bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
1647 }
1648 #endif	/* SMALL_KERNEL */
1649