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