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