sti.c revision 1.77
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
52struct cfdriver sti_cd = {
53	NULL, "sti", DV_DULL
54};
55
56int	sti_alloc_attr(void *, int, int, int, long *);
57int	sti_copycols(void *, int, int, int, int);
58int	sti_copyrows(void *, int, int, int);
59int	sti_cursor(void *, int, int, int);
60int	sti_erasecols(void *, int, int, int, long);
61int	sti_eraserows(void *, int, int, long);
62int	sti_mapchar(void *, int, u_int *);
63int	sti_putchar(void *, int, int, u_int, long);
64void	sti_unpack_attr(void *, long, int *, int *, int *);
65
66struct 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
78int	sti_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
79	    int *, long *);
80void	sti_free_screen(void *, void *);
81int	sti_ioctl(void *, u_long, caddr_t, int, struct proc *);
82paddr_t sti_mmap(void *, off_t, int);
83int	sti_show_screen(void *, void *, int, void (*)(void *, int, int),
84	    void *);
85
86const 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
94enum sti_bmove_funcs {
95	bmf_clear, bmf_copy, bmf_invert, bmf_underline
96};
97
98void	sti_bmove(struct sti_screen *, int, int, int, int, int, int,
99	    enum sti_bmove_funcs);
100int	sti_init(struct sti_screen *, int);
101#define	STI_TEXTMODE	0x01
102#define	STI_CLEARSCR	0x02
103#define	STI_FBMODE	0x04
104int	sti_inqcfg(struct sti_screen *, struct sti_inqconfout *);
105int	sti_setcment(struct sti_screen *, u_int, u_char, u_char, u_char);
106
107struct sti_screen *
108	sti_attach_screen(struct sti_softc *, int);
109void	sti_describe_screen(struct sti_softc *, struct sti_screen *);
110void	sti_end_attach_screen(struct sti_softc *, struct sti_screen *, int);
111int	sti_fetchfonts(struct sti_screen *, struct sti_inqconfout *, u_int32_t,
112	    u_int);
113void	sti_region_setup(struct sti_screen *);
114int	sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
115	    bus_space_handle_t, bus_addr_t *, u_int);
116int	sti_screen_setup(struct sti_screen *, int);
117
118int	ngle_default_putcmap(struct sti_screen *, u_int, u_int);
119
120void	ngle_artist_setupfb(struct sti_screen *);
121void	ngle_elk_setupfb(struct sti_screen *);
122void	ngle_timber_setupfb(struct sti_screen *);
123int	ngle_putcmap(struct sti_screen *, u_int, u_int);
124
125#if NSTI_PCI > 0
126#define	STI_ENABLE_ROM(sc) \
127do { \
128	if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \
129		(*(sc)->sc_enable_rom)(sc); \
130} while (0)
131#define	STI_DISABLE_ROM(sc) \
132do { \
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
151int
152sti_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
184struct sti_screen *
185sti_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
209int
210sti_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 */
393void
394sti_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
495int
496sti_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
705fail:
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
715void
716sti_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
729void
730sti_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 */
748void
749sti_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
758void
759sti_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
784u_int
785sti_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
801int
802sti_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
826rescan:
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
933int
934sti_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
968int
969sti_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
985void
986sti_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
1029int
1030sti_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
1059int
1060sti_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
1171paddr_t
1172sti_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
1196int
1197sti_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
1213void
1214sti_free_screen(void *v, void *cookie)
1215{
1216	struct sti_screen *scr = (struct sti_screen *)v;
1217
1218	scr->scr_nscreens--;
1219}
1220
1221int
1222sti_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
1236int
1237sti_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 */
1253static const u_int8_t
1254sti_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
1274int
1275sti_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
1306int
1307sti_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
1369int
1370sti_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
1383int
1384sti_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
1397int
1398sti_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
1409int
1410sti_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
1421int
1422sti_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
1432void
1433sti_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
1450int
1451ngle_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
1465void	ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
1466void	ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
1467void	ngle_setup_attr_planes(struct sti_screen *scr);
1468void	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
1473void
1474ngle_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
1494void
1495ngle_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
1514void
1515ngle_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
1529void
1530ngle_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
1542void
1543ngle_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
1567int
1568ngle_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
1608void
1609ngle_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
1620void
1621ngle_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