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