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