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