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