1/*	$NetBSD: gftfb.c,v 1.14 2024/04/18 04:52:43 macallan Exp $	*/
2
3/*	$OpenBSD: sti_pci.c,v 1.7 2009/02/06 22:51:04 miod Exp $	*/
4
5/*
6 * Copyright (c) 2006, 2007 Miodrag Vallat.
7 ^                     2024 Michael Lorenz
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice, this permission notice, and the disclaimer below
12 * appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23/*
24 * a native driver for HP Visualize EG PCI graphics cards
25 * STI portions are from Miodrag Vallat's sti_pci.c
26 */
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/kmem.h>
31#include <sys/device.h>
32#include <sys/mutex.h>
33
34#include <dev/pci/pcivar.h>
35#include <dev/pci/pcireg.h>
36#include <dev/pci/pcidevs.h>
37#include <dev/pci/pciio.h>
38
39#include <dev/wscons/wsdisplayvar.h>
40#include <dev/wscons/wsconsio.h>
41#include <dev/wsfont/wsfont.h>
42#include <dev/rasops/rasops.h>
43#include <dev/wscons/wsdisplay_vconsvar.h>
44#include <dev/pci/wsdisplay_pci.h>
45#include <dev/wscons/wsdisplay_glyphcachevar.h>
46
47#include <dev/ic/stireg.h>
48#include <dev/ic/stivar.h>
49
50#ifdef STIDEBUG
51#define	DPRINTF(s)	do {	\
52	if (stidebug)		\
53		printf s;	\
54} while(0)
55
56extern int stidebug;
57#else
58#define	DPRINTF(s)	/* */
59#endif
60
61int	gftfb_match(device_t, cfdata_t, void *);
62void	gftfb_attach(device_t, device_t, void *);
63
64struct	gftfb_softc {
65	device_t		sc_dev;
66	pci_chipset_tag_t	sc_pc;
67	pcitag_t		sc_tag;
68
69	/* stuff we need in order to use the STI ROM */
70	struct sti_softc	sc_base;
71	struct sti_screen 	sc_scr;
72	bus_space_handle_t	sc_romh;
73
74	int sc_width, sc_height;
75	int sc_locked;
76	struct vcons_screen sc_console_screen;
77	struct wsscreen_descr sc_defaultscreen_descr;
78	const struct wsscreen_descr *sc_screens[1];
79	struct wsscreen_list sc_screenlist;
80	struct vcons_data vd;
81	int sc_mode;
82	void (*sc_putchar)(void *, int, int, u_int, long);
83	u_char sc_cmap_red[256];
84	u_char sc_cmap_green[256];
85	u_char sc_cmap_blue[256];
86	kmutex_t sc_hwlock;
87	uint32_t sc_hwmode;
88#define HW_FB	0
89#define HW_FILL	1
90#define HW_BLIT	2
91	uint32_t sc_rect_colour, sc_rect_height;
92	/* cursor stuff */
93	int sc_cursor_x, sc_cursor_y;
94	int sc_hot_x, sc_hot_y, sc_enabled;
95	int sc_video_on;
96	glyphcache sc_gc;
97};
98
99CFATTACH_DECL_NEW(gftfb, sizeof(struct gftfb_softc),
100    gftfb_match, gftfb_attach, NULL, NULL);
101
102int	gftfb_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int);
103int	gftfb_check_rom(struct gftfb_softc *, struct pci_attach_args *);
104void	gftfb_enable_rom(struct sti_softc *);
105void	gftfb_disable_rom(struct sti_softc *);
106void	gftfb_enable_rom_internal(struct gftfb_softc *);
107void	gftfb_disable_rom_internal(struct gftfb_softc *);
108
109void 	gftfb_setup(struct gftfb_softc *);
110
111#define	ngle_bt458_write(memt, memh, r, v) \
112	bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
113
114
115/* XXX these really need to go into their own header */
116int	sti_pci_is_console(struct pci_attach_args *, bus_addr_t *);
117int	sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
118	    bus_space_handle_t, bus_addr_t *, u_int);
119int	sti_screen_setup(struct sti_screen *, int);
120void	sti_describe_screen(struct sti_softc *, struct sti_screen *);
121
122#define PCI_ROM_SIZE(mr)                                                \
123            (PCI_MAPREG_ROM_ADDR(mr) & -PCI_MAPREG_ROM_ADDR(mr))
124
125/* wsdisplay stuff */
126static int	gftfb_ioctl(void *, void *, u_long, void *, int,
127			     struct lwp *);
128static paddr_t	gftfb_mmap(void *, void *, off_t, int);
129static void	gftfb_init_screen(void *, struct vcons_screen *, int, long *);
130
131static int	gftfb_putcmap(struct gftfb_softc *, struct wsdisplay_cmap *);
132static int 	gftfb_getcmap(struct gftfb_softc *, struct wsdisplay_cmap *);
133static void	gftfb_restore_palette(struct gftfb_softc *);
134static int 	gftfb_putpalreg(struct gftfb_softc *, uint8_t, uint8_t,
135			    uint8_t, uint8_t);
136
137static void	gftfb_rectfill(struct gftfb_softc *, int, int, int, int,
138			    uint32_t);
139static void	gftfb_bitblt(void *, int, int, int, int, int,
140			    int, int);
141
142static void	gftfb_cursor(void *, int, int, int);
143static void	gftfb_putchar(void *, int, int, u_int, long);
144static void	gftfb_copycols(void *, int, int, int, int);
145static void	gftfb_erasecols(void *, int, int, int, long);
146static void	gftfb_copyrows(void *, int, int, int);
147static void	gftfb_eraserows(void *, int, int, long);
148
149static void	gftfb_move_cursor(struct gftfb_softc *, int, int);
150static int	gftfb_do_cursor(struct gftfb_softc *, struct wsdisplay_cursor *);
151
152static void	gftfb_set_video(struct gftfb_softc *, int);
153
154struct wsdisplay_accessops gftfb_accessops = {
155	gftfb_ioctl,
156	gftfb_mmap,
157	NULL,	/* alloc_screen */
158	NULL,	/* free_screen */
159	NULL,	/* show_screen */
160	NULL, 	/* load_font */
161	NULL,	/* pollc */
162	NULL	/* scroll */
163};
164
165#define BA(F,C,S,A,J,B,I)						\
166	(((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
167
168#define IBOvals(R,M,X,S,D,L,B,F)					\
169	(((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
170
171#define	    IndexedDcd	0	/* Pixel data is indexed (pseudo) color */
172#define	    Otc04	2	/* Pixels in each longword transfer (4) */
173#define	    Otc32	5	/* Pixels in each longword transfer (32) */
174#define	    Ots08	3	/* Each pixel is size (8)d transfer (1) */
175#define	    OtsIndirect	6	/* Each bit goes through FG/BG color(8) */
176#define	    AddrLong	5	/* FB address is Long aligned (pixel) */
177#define	    BINovly	0x2	/* 8 bit overlay */
178#define	    BINapp0I	0x0	/* Application Buffer 0, Indexed */
179#define	    BINapp1I	0x1	/* Application Buffer 1, Indexed */
180#define	    BINapp0F8	0xa	/* Application Buffer 0, Fractional 8-8-8 */
181#define	    BINattr	0xd	/* Attribute Bitmap */
182#define	    RopSrc 	0x3
183#define	    RopInv 	0xc
184#define	    BitmapExtent08  3	/* Each write hits ( 8) bits in depth */
185#define	    BitmapExtent32  5	/* Each write hits (32) bits in depth */
186#define	    DataDynamic	    0	/* Data register reloaded by direct access */
187#define	    MaskDynamic	    1	/* Mask register reloaded by direct access */
188#define	    MaskOtc	    0	/* Mask contains Object Count valid bits */
189
190static inline void gftfb_wait_fifo(struct gftfb_softc *, uint32_t);
191
192int
193gftfb_match(device_t parent, cfdata_t cf, void *aux)
194{
195	struct pci_attach_args *paa = aux;
196
197	if (PCI_VENDOR(paa->pa_id) != PCI_VENDOR_HP)
198		return 0;
199
200	if (PCI_PRODUCT(paa->pa_id) == PCI_PRODUCT_HP_VISUALIZE_EG)
201		return 10;	/* beat out sti at pci */
202
203	return 0;
204}
205
206void
207gftfb_attach(device_t parent, device_t self, void *aux)
208{
209	struct gftfb_softc *sc = device_private(self);
210	struct pci_attach_args *paa = aux;
211	struct sti_rom *rom;
212	struct rasops_info *ri;
213	struct wsemuldisplaydev_attach_args aa;
214	unsigned long defattr = 0;
215	int ret, is_console = 0;
216
217	sc->sc_dev = self;
218
219	sc->sc_pc = paa->pa_pc;
220	sc->sc_tag = paa->pa_tag;
221	sc->sc_base.sc_dev = self;
222	sc->sc_base.sc_enable_rom = gftfb_enable_rom;
223	sc->sc_base.sc_disable_rom = gftfb_disable_rom;
224
225	/* we can *not* be interrupted when doing colour map accesses */
226	mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH);
227
228	aprint_normal("\n");
229
230	if (gftfb_check_rom(sc, paa) != 0)
231		return;
232
233	ret = sti_pci_is_console(paa, sc->sc_base. bases);
234	if (ret != 0) {
235		sc->sc_base.sc_flags |= STI_CONSOLE;
236		is_console = 1;
237	}
238	rom = (struct sti_rom *)kmem_zalloc(sizeof(*rom), KM_SLEEP);
239	rom->rom_softc = &sc->sc_base;
240	ret = sti_rom_setup(rom, paa->pa_iot, paa->pa_memt, sc->sc_romh,
241	    sc->sc_base.bases, STI_CODEBASE_MAIN);
242	if (ret != 0) {
243		kmem_free(rom, sizeof(*rom));
244		return;
245	}
246
247	sc->sc_base.sc_rom = rom;
248
249	sc->sc_scr.scr_rom = sc->sc_base.sc_rom;
250	ret = sti_screen_setup(&sc->sc_scr, STI_FBMODE);
251
252	sc->sc_width = sc->sc_scr.scr_cfg.scr_width;
253	sc->sc_height = sc->sc_scr.scr_cfg.scr_height;
254	sc->sc_rect_colour = 0xf0000000;
255	sc->sc_rect_height = 0;
256
257	aprint_normal_dev(sc->sc_dev, "%s at %dx%d\n", sc->sc_scr.name,
258	    sc->sc_width, sc->sc_height);
259	gftfb_setup(sc);
260
261	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
262		"default",
263		0, 0,
264		NULL,
265		8, 16,
266		WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
267		      WSSCREEN_RESIZE,
268		NULL
269	};
270
271	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
272	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
273	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
274	sc->sc_locked = 0;
275
276	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
277	    &gftfb_accessops);
278	sc->vd.init_screen = gftfb_init_screen;
279	sc->vd.show_screen_cookie = &sc->sc_gc;
280	sc->vd.show_screen_cb = glyphcache_adapt;
281
282	ri = &sc->sc_console_screen.scr_ri;
283
284	sc->sc_gc.gc_bitblt = gftfb_bitblt;
285	sc->sc_gc.gc_blitcookie = sc;
286	sc->sc_gc.gc_rop = RopSrc;
287
288	if (is_console) {
289		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
290		    &defattr);
291		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
292
293		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
294		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
295		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
296		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
297
298		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
299				sc->sc_scr.fbheight - sc->sc_height - 5,
300				sc->sc_scr.fbwidth,
301				ri->ri_font->fontwidth,
302				ri->ri_font->fontheight,
303				defattr);
304
305		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
306		    defattr);
307
308		gftfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
309		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
310
311		vcons_replay_msgbuf(&sc->sc_console_screen);
312	} else {
313		/*
314		 * since we're not the console we can postpone the rest
315		 * until someone actually allocates a screen for us
316		 */
317		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
318			/* do some minimal setup to avoid weirdnesses later */
319			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
320			    &defattr);
321		} else
322			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
323
324		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
325				sc->sc_scr.fbheight - sc->sc_height - 5,
326				sc->sc_scr.fbwidth,
327				ri->ri_font->fontwidth,
328				ri->ri_font->fontheight,
329				defattr);
330	}
331
332	gftfb_restore_palette(sc);
333
334	/* no suspend/resume support yet */
335	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
336		aprint_error_dev(sc->sc_dev,
337		    "couldn't establish power handler\n");
338
339	aa.console = is_console;
340	aa.scrdata = &sc->sc_screenlist;
341	aa.accessops = &gftfb_accessops;
342	aa.accesscookie = &sc->vd;
343
344	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
345}
346
347/*
348 * Grovel the STI ROM image.
349 */
350int
351gftfb_check_rom(struct gftfb_softc *spc, struct pci_attach_args *pa)
352{
353	struct sti_softc *sc = &spc->sc_base;
354	pcireg_t address, mask;
355	bus_space_handle_t romh;
356	bus_size_t romsize, subsize, stiromsize;
357	bus_addr_t selected, offs, suboffs;
358	uint32_t tmp;
359	int i;
360	int rc;
361
362	/* sort of inline sti_pci_enable_rom(sc) */
363	address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
364	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM,
365	    ~PCI_MAPREG_ROM_ENABLE);
366	mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
367	address |= PCI_MAPREG_ROM_ENABLE;
368	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, address);
369	sc->sc_flags |= STI_ROM_ENABLED;
370	/*
371	 * Map the complete ROM for now.
372	 */
373
374	romsize = PCI_ROM_SIZE(mask);
375	DPRINTF(("%s: mapping rom @ %lx for %lx\n", __func__,
376	    (long)PCI_MAPREG_ROM_ADDR(address), (long)romsize));
377
378	rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address), romsize,
379	    0, &romh);
380	if (rc != 0) {
381		aprint_error_dev(sc->sc_dev, "can't map PCI ROM (%d)\n", rc);
382		goto fail2;
383	}
384
385	gftfb_disable_rom_internal(spc);
386	/*
387	 * Iterate over the ROM images, pick the best candidate.
388	 */
389
390	selected = (bus_addr_t)-1;
391	for (offs = 0; offs < romsize; offs += subsize) {
392		gftfb_enable_rom_internal(spc);
393		/*
394		 * Check for a valid ROM header.
395		 */
396		tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
397		tmp = le32toh(tmp);
398		if (tmp != 0x55aa0000) {
399			gftfb_disable_rom_internal(spc);
400			if (offs == 0) {
401				aprint_error_dev(sc->sc_dev,
402				    "invalid PCI ROM header signature (%08x)\n",
403				     tmp);
404				rc = EINVAL;
405			}
406			break;
407		}
408
409		/*
410		 * Check ROM type.
411		 */
412		tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
413		tmp = le32toh(tmp);
414		if (tmp != 0x00000001) {	/* 1 == STI ROM */
415			gftfb_disable_rom_internal(spc);
416			if (offs == 0) {
417				aprint_error_dev(sc->sc_dev,
418				    "invalid PCI ROM type (%08x)\n", tmp);
419				rc = EINVAL;
420			}
421			break;
422		}
423
424		subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
425		    offs + 0x0c);
426		subsize <<= 9;
427
428#ifdef STIDEBUG
429		gftfb_disable_rom_internal(spc);
430		DPRINTF(("ROM offset %08x size %08x type %08x",
431		    (u_int)offs, (u_int)subsize, tmp));
432		gftfb_enable_rom_internal(spc);
433#endif
434
435		/*
436		 * Check for a valid ROM data structure.
437		 * We do not need it except to know what architecture the ROM
438		 * code is for.
439		 */
440
441		suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
442		    offs + 0x18);
443		tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
444		tmp = le32toh(tmp);
445		if (tmp != 0x50434952) {	/* PCIR */
446			gftfb_disable_rom_internal(spc);
447			if (offs == 0) {
448				aprint_error_dev(sc->sc_dev, "invalid PCI data"
449				    " signature (%08x)\n", tmp);
450				rc = EINVAL;
451			} else {
452				DPRINTF((" invalid PCI data signature %08x\n",
453				    tmp));
454				continue;
455			}
456		}
457
458		tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
459		gftfb_disable_rom_internal(spc);
460		DPRINTF((" code %02x", tmp));
461
462		switch (tmp) {
463#ifdef __hppa__
464		case 0x10:
465			if (selected == (bus_addr_t)-1)
466				selected = offs;
467			break;
468#endif
469#ifdef __i386__
470		case 0x00:
471			if (selected == (bus_addr_t)-1)
472				selected = offs;
473			break;
474#endif
475		default:
476#ifdef STIDEBUG
477			DPRINTF((" (wrong architecture)"));
478#endif
479			break;
480		}
481		DPRINTF(("%s\n", selected == offs ? " -> SELECTED" : ""));
482	}
483
484	if (selected == (bus_addr_t)-1) {
485		if (rc == 0) {
486			aprint_error_dev(sc->sc_dev, "found no ROM with "
487			    "correct microcode architecture\n");
488			rc = ENOEXEC;
489		}
490		goto fail;
491	}
492
493	/*
494	 * Read the STI region BAR assignments.
495	 */
496
497	gftfb_enable_rom_internal(spc);
498	offs = selected +
499	    (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
500	for (i = 0; i < STI_REGION_MAX; i++) {
501		rc = gftfb_readbar(sc, pa, i,
502		    bus_space_read_1(pa->pa_memt, romh, offs + i));
503		if (rc != 0)
504			goto fail;
505	}
506
507	/*
508	 * Find out where the STI ROM itself lies, and its size.
509	 */
510
511	offs = selected +
512	    (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
513	stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
514	    offs + 0x18);
515	stiromsize = le32toh(stiromsize);
516	gftfb_disable_rom_internal(spc);
517
518	/*
519	 * Replace our mapping with a smaller mapping of only the area
520	 * we are interested in.
521	 */
522
523	DPRINTF(("remapping rom @ %lx for %lx\n",
524	    (long)(PCI_MAPREG_ROM_ADDR(address) + offs), (long)stiromsize));
525	bus_space_unmap(pa->pa_memt, romh, romsize);
526	rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address) + offs,
527	    stiromsize, 0, &spc->sc_romh);
528	if (rc != 0) {
529		aprint_error_dev(sc->sc_dev, "can't map STI ROM (%d)\n",
530		    rc);
531		goto fail2;
532	}
533 	gftfb_disable_rom_internal(spc);
534	sc->sc_flags &= ~STI_ROM_ENABLED;
535
536	return 0;
537
538fail:
539	bus_space_unmap(pa->pa_memt, romh, romsize);
540fail2:
541	gftfb_disable_rom_internal(spc);
542
543	return rc;
544}
545
546/*
547 * Decode a BAR register.
548 */
549int
550gftfb_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region,
551    int bar)
552{
553	bus_addr_t addr;
554	bus_size_t size;
555	uint32_t cf;
556	int rc;
557
558	if (bar == 0) {
559		sc->bases[region] = 0;
560		return (0);
561	}
562
563#ifdef DIAGNOSTIC
564	if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) {
565		gftfb_disable_rom(sc);
566		printf("%s: unexpected bar %02x for region %d\n",
567		    device_xname(sc->sc_dev), bar, region);
568		gftfb_enable_rom(sc);
569	}
570#endif
571
572	cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
573
574	rc = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, PCI_MAPREG_TYPE(cf),
575	    &addr, &size, NULL);
576
577	if (rc != 0) {
578		gftfb_disable_rom(sc);
579		aprint_error_dev(sc->sc_dev, "invalid bar %02x for region %d\n",
580		    bar, region);
581		gftfb_enable_rom(sc);
582		return (rc);
583	}
584
585	sc->bases[region] = addr;
586	return (0);
587}
588
589/*
590 * Enable PCI ROM.
591 */
592void
593gftfb_enable_rom_internal(struct gftfb_softc *spc)
594{
595	pcireg_t address;
596
597	KASSERT(spc != NULL);
598
599	address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM);
600	address |= PCI_MAPREG_ROM_ENABLE;
601	pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address);
602}
603
604void
605gftfb_enable_rom(struct sti_softc *sc)
606{
607	struct gftfb_softc *spc = device_private(sc->sc_dev);
608
609	if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
610		gftfb_enable_rom_internal(spc);
611	}
612	SET(sc->sc_flags, STI_ROM_ENABLED);
613}
614
615/*
616 * Disable PCI ROM.
617 */
618void
619gftfb_disable_rom_internal(struct gftfb_softc *spc)
620{
621	pcireg_t address;
622
623	KASSERT(spc != NULL);
624
625	address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM);
626	address &= ~PCI_MAPREG_ROM_ENABLE;
627	pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address);
628}
629
630void
631gftfb_disable_rom(struct sti_softc *sc)
632{
633	struct gftfb_softc *spc = device_private(sc->sc_dev);
634
635	if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
636		gftfb_disable_rom_internal(spc);
637	}
638	CLR(sc->sc_flags, STI_ROM_ENABLED);
639}
640
641static inline void
642gftfb_wait(struct gftfb_softc *sc)
643{
644	struct sti_rom *rom = sc->sc_base.sc_rom;
645	bus_space_tag_t memt = rom->memt;
646	bus_space_handle_t memh = rom->regh[2];
647	uint8_t stat;
648
649	do {
650		stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
651		if (stat == 0)
652			stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
653	} while (stat != 0);
654}
655
656static inline void
657gftfb_setup_fb(struct gftfb_softc *sc)
658{
659	struct sti_rom *rom = sc->sc_base.sc_rom;
660	bus_space_tag_t memt = rom->memt;
661	bus_space_handle_t memh = rom->regh[2];
662
663	gftfb_wait(sc);
664	bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0x13601000);
665	bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300);
666	gftfb_wait(sc);
667	bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
668	sc->sc_hwmode = HW_FB;
669}
670
671void
672gftfb_setup(struct gftfb_softc *sc)
673{
674	struct sti_rom *rom = sc->sc_base.sc_rom;
675	bus_space_tag_t memt = rom->memt;
676	bus_space_handle_t memh = rom->regh[2];
677	int i;
678
679	sc->sc_hwmode = HW_FB;
680	sc->sc_hot_x = 0;
681	sc->sc_hot_y = 0;
682	sc->sc_enabled = 0;
683	sc->sc_video_on = 1;
684
685	sc->sc_rect_colour = 0xf0000000;
686	sc->sc_rect_height = 0;
687
688	/* set Bt458 read mask register to all planes */
689	gftfb_wait(sc);
690	ngle_bt458_write(memt, memh, 0x08, 0x04);
691	ngle_bt458_write(memt, memh, 0x0a, 0xff);
692
693	gftfb_setup_fb(sc);
694
695	/* attr. planes */
696	gftfb_wait(sc);
697	bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
698	bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302);
699	bus_space_write_stream_4(memt, memh, NGLE_REG_12, NGLE_ARTIST_CMAP0);
700	bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
701
702	gftfb_wait(sc);
703	bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000);
704	bus_space_write_stream_4(memt, memh, NGLE_REG_9,
705	    (sc->sc_scr.scr_cfg.scr_width << 16) | sc->sc_scr.scr_cfg.scr_height);
706	/*
707	 * blit into offscreen memory to force flush previous - apparently
708	 * some chips have a bug this works around
709	 */
710	bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000);
711	bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001);
712
713	gftfb_wait(sc);
714	bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000);
715
716	gftfb_setup_fb(sc);
717
718	/* make sure video output is enabled */
719	gftfb_wait(sc);
720	bus_space_write_stream_4(memt, memh, NGLE_REG_21,
721	    bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
722	bus_space_write_stream_4(memt, memh, NGLE_REG_27,
723	    bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
724
725	/* initialize cursor sprite */
726	gftfb_wait(sc);
727
728	/* cursor mask */
729	gftfb_wait(sc);
730	bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
731	bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
732	bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A07000);
733	bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
734	for (i = 0; i < 64; i++) {
735		bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0xffffffff);
736		bus_space_write_stream_4(memt, memh, NGLE_REG_5, 0xffffffff);
737	}
738
739	/* cursor image */
740	gftfb_wait(sc);
741	bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
742	bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
743	bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A06000);
744	bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
745	for (i = 0; i < 64; i++) {
746		bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0xff00ff00);
747		bus_space_write_stream_4(memt, memh, NGLE_REG_5, 0xff00ff00);
748	}
749
750	/* colour map */
751	gftfb_wait(sc);
752	bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xBBE0F000);
753	bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
754	bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
755	gftfb_wait(sc);
756	bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
757	bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
758	bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
759	bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0x000000ff);	/* BG */
760	bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0x00ff0000);	/* FG */
761	gftfb_wait(sc);
762	bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0);
763	bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80008004);
764	gftfb_setup_fb(sc);
765
766	gftfb_move_cursor(sc, 100, 100);
767
768}
769
770static int
771gftfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
772	struct lwp *l)
773{
774	struct vcons_data *vd = v;
775	struct gftfb_softc *sc = vd->cookie;
776	struct wsdisplay_fbinfo *wdf;
777	struct vcons_screen *ms = vd->active;
778
779	switch (cmd) {
780	case WSDISPLAYIO_GTYPE:
781		*(u_int *)data = WSDISPLAY_TYPE_STI;
782		return 0;
783
784	/* PCI config read/write passthrough. */
785	case PCI_IOC_CFGREAD:
786	case PCI_IOC_CFGWRITE:
787		return pci_devioctl(sc->sc_pc, sc->sc_tag,
788		    cmd, data, flag, l);
789
790	case WSDISPLAYIO_GET_BUSID:
791		return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
792		    sc->sc_tag, data);
793
794	case WSDISPLAYIO_GINFO:
795		if (ms == NULL)
796			return ENODEV;
797		wdf = (void *)data;
798		wdf->height = ms->scr_ri.ri_height;
799		wdf->width = ms->scr_ri.ri_width;
800		wdf->depth = ms->scr_ri.ri_depth;
801		wdf->cmsize = 256;
802		return 0;
803
804	case WSDISPLAYIO_GETCMAP:
805		return gftfb_getcmap(sc,
806		    (struct wsdisplay_cmap *)data);
807
808	case WSDISPLAYIO_PUTCMAP:
809		return gftfb_putcmap(sc,
810		    (struct wsdisplay_cmap *)data);
811
812	case WSDISPLAYIO_LINEBYTES:
813		*(u_int *)data = 2048;
814		return 0;
815
816	case WSDISPLAYIO_SMODE: {
817		int new_mode = *(int*)data;
818		if (new_mode != sc->sc_mode) {
819			sc->sc_mode = new_mode;
820			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
821				gftfb_setup(sc);
822				gftfb_restore_palette(sc);
823				glyphcache_wipe(&sc->sc_gc);
824				gftfb_rectfill(sc, 0, 0, sc->sc_width,
825				    sc->sc_height, ms->scr_ri.ri_devcmap[
826				    (ms->scr_defattr >> 16) & 0xff]);
827				vcons_redraw_screen(ms);
828				gftfb_set_video(sc, 1);
829			}
830		}
831		}
832		return 0;
833
834	case WSDISPLAYIO_GET_FBINFO:
835		{
836			struct wsdisplayio_fbinfo *fbi = data;
837			int ret;
838
839			ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
840			fbi->fbi_fbsize = sc->sc_scr.fbheight * 2048;
841			return ret;
842		}
843
844	case WSDISPLAYIO_GCURPOS:
845		{
846			struct wsdisplay_curpos *cp = (void *)data;
847
848			cp->x = sc->sc_cursor_x;
849			cp->y = sc->sc_cursor_y;
850		}
851		return 0;
852
853	case WSDISPLAYIO_SCURPOS:
854		{
855			struct wsdisplay_curpos *cp = (void *)data;
856
857			gftfb_move_cursor(sc, cp->x, cp->y);
858		}
859		return 0;
860
861	case WSDISPLAYIO_GCURMAX:
862		{
863			struct wsdisplay_curpos *cp = (void *)data;
864
865			cp->x = 64;
866			cp->y = 64;
867		}
868		return 0;
869
870	case WSDISPLAYIO_SCURSOR:
871		{
872			struct wsdisplay_cursor *cursor = (void *)data;
873
874			return gftfb_do_cursor(sc, cursor);
875		}
876
877	case WSDISPLAYIO_SVIDEO:
878		gftfb_set_video(sc, *(int *)data);
879		return 0;
880	case WSDISPLAYIO_GVIDEO:
881		return sc->sc_video_on ?
882		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
883	}
884	return EPASSTHROUGH;
885}
886
887static paddr_t
888gftfb_mmap(void *v, void *vs, off_t offset, int prot)
889{
890	struct vcons_data *vd = v;
891	struct gftfb_softc *sc = vd->cookie;
892	struct sti_rom *rom = sc->sc_base.sc_rom;
893	paddr_t pa = -1;
894
895
896	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)
897		return -1;
898
899	if (offset >= 0 || offset < sc->sc_scr.fblen) {
900		/* framebuffer */
901		pa = bus_space_mmap(rom->memt, sc->sc_scr.fbaddr, offset,
902		    prot, BUS_SPACE_MAP_LINEAR);
903	} else if (offset >= 0x80000000 && offset < 0x8040000) {
904		/* blitter registers etc. */
905		pa = bus_space_mmap(rom->memt, rom->regh[2],
906		    offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR);
907	}
908
909	return pa;
910}
911
912static void
913gftfb_init_screen(void *cookie, struct vcons_screen *scr,
914    int existing, long *defattr)
915{
916	struct gftfb_softc *sc = cookie;
917	struct rasops_info *ri = &scr->scr_ri;
918
919	ri->ri_depth = 8;
920	ri->ri_width = sc->sc_width;
921	ri->ri_height = sc->sc_height;
922	ri->ri_stride = 2048;
923	ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB |
924		     RI_ENABLE_ALPHA | RI_PREFER_ALPHA;
925
926	ri->ri_bits = (void *)sc->sc_scr.fbaddr;
927	rasops_init(ri, 0, 0);
928	ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
929		      WSSCREEN_RESIZE;
930	scr->scr_flags |= VCONS_LOADFONT;
931
932	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
933		    sc->sc_width / ri->ri_font->fontwidth);
934
935	ri->ri_hw = scr;
936	sc->sc_putchar = ri->ri_ops.putchar;
937	ri->ri_ops.copyrows = gftfb_copyrows;
938	ri->ri_ops.copycols = gftfb_copycols;
939	ri->ri_ops.eraserows = gftfb_eraserows;
940	ri->ri_ops.erasecols = gftfb_erasecols;
941	ri->ri_ops.cursor = gftfb_cursor;
942	ri->ri_ops.putchar = gftfb_putchar;
943}
944
945static int
946gftfb_putcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm)
947{
948	u_char *r, *g, *b;
949	u_int index = cm->index;
950	u_int count = cm->count;
951	int i, error;
952	u_char rbuf[256], gbuf[256], bbuf[256];
953
954	if (cm->index >= 256 || cm->count > 256 ||
955	    (cm->index + cm->count) > 256)
956		return EINVAL;
957	error = copyin(cm->red, &rbuf[index], count);
958	if (error)
959		return error;
960	error = copyin(cm->green, &gbuf[index], count);
961	if (error)
962		return error;
963	error = copyin(cm->blue, &bbuf[index], count);
964	if (error)
965		return error;
966
967	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
968	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
969	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
970
971	r = &sc->sc_cmap_red[index];
972	g = &sc->sc_cmap_green[index];
973	b = &sc->sc_cmap_blue[index];
974
975	for (i = 0; i < count; i++) {
976		gftfb_putpalreg(sc, index, *r, *g, *b);
977		index++;
978		r++, g++, b++;
979	}
980	return 0;
981}
982
983static int
984gftfb_getcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm)
985{
986	u_int index = cm->index;
987	u_int count = cm->count;
988	int error;
989
990	if (index >= 255 || count > 256 || index + count > 256)
991		return EINVAL;
992
993	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
994	if (error)
995		return error;
996	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
997	if (error)
998		return error;
999	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
1000	if (error)
1001		return error;
1002
1003	return 0;
1004}
1005
1006static void
1007gftfb_restore_palette(struct gftfb_softc *sc)
1008{
1009	uint8_t cmap[768];
1010	int i, j;
1011
1012	j = 0;
1013	rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap));
1014	for (i = 0; i < 256; i++) {
1015		sc->sc_cmap_red[i] = cmap[j];
1016		sc->sc_cmap_green[i] = cmap[j + 1];
1017		sc->sc_cmap_blue[i] = cmap[j + 2];
1018		gftfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
1019		j += 3;
1020	}
1021}
1022
1023static int
1024gftfb_putpalreg(struct gftfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
1025    uint8_t b)
1026{
1027	struct sti_rom *rom = sc->sc_base.sc_rom;
1028	bus_space_tag_t memt = rom->memt;
1029	bus_space_handle_t memh = rom->regh[2];
1030
1031	mutex_enter(&sc->sc_hwlock);
1032	gftfb_wait(sc);
1033	bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1034	bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1035	bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1036
1037	gftfb_wait(sc);
1038	bus_space_write_stream_4(memt, memh, NGLE_REG_3,
1039	    0x400 | (idx << 2));
1040	bus_space_write_stream_4(memt, memh, NGLE_REG_4,
1041	    (r << 16) | (g << 8) | b);
1042
1043	bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400);
1044	bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80000100);
1045	gftfb_setup_fb(sc);
1046	mutex_exit(&sc->sc_hwlock);
1047	return 0;
1048}
1049
1050static inline void
1051gftfb_wait_fifo(struct gftfb_softc *sc, uint32_t slots)
1052{
1053	struct sti_rom *rom = sc->sc_base.sc_rom;
1054	bus_space_tag_t memt = rom->memt;
1055	bus_space_handle_t memh = rom->regh[2];
1056	uint32_t reg;
1057
1058	do {
1059		reg = bus_space_read_stream_4(memt, memh, NGLE_REG_34);
1060	} while (reg < slots);
1061}
1062
1063static void
1064gftfb_real_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he,
1065		      uint32_t bg)
1066{
1067	struct sti_rom *rom = sc->sc_base.sc_rom;
1068	bus_space_tag_t memt = rom->memt;
1069	bus_space_handle_t memh = rom->regh[2];
1070
1071	if (sc->sc_hwmode != HW_FILL) {
1072		gftfb_wait_fifo(sc, 4);
1073		/* transfer data */
1074		bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
1075		/* plane mask */
1076		bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xff);
1077		/* bitmap op */
1078		bus_space_write_stream_4(memt, memh, NGLE_REG_14,
1079		    IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0));
1080		/* dst bitmap access */
1081		bus_space_write_stream_4(memt, memh, NGLE_REG_11,
1082		    BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0));
1083		sc->sc_hwmode = HW_FILL;
1084	}
1085	gftfb_wait_fifo(sc, 3);
1086	bus_space_write_stream_4(memt, memh, NGLE_REG_35, bg);
1087	/* dst XY */
1088	bus_space_write_stream_4(memt, memh, NGLE_REG_6, (x << 16) | y);
1089	/* len XY start */
1090	bus_space_write_stream_4(memt, memh, NGLE_REG_9, (wi << 16) | he);
1091
1092}
1093
1094static void
1095gftfb_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he,
1096		      uint32_t bg)
1097{
1098	/*
1099	 * For some reason my 4MB VisEG always draws rectangles at least 32
1100	 * pixels wide - no idea why, the bitblt command doesn't have this
1101	 * problem.
1102	 * So, as a workaround, we draw a 50xFontHeight rectangle to the right
1103	 * of the visible fb, keep track of the colour so we don't need to
1104	 * redraw every time, and bitblt the portion we need
1105	 */
1106	if (wi < 50) {
1107		if ((bg != sc->sc_rect_colour) ||
1108		    (he > sc->sc_rect_height)) {
1109			gftfb_real_rectfill(sc, sc->sc_width + 10, 0, 50,
1110			    he, bg);
1111			sc->sc_rect_colour = bg;
1112			sc->sc_rect_height = he;
1113		}
1114		gftfb_bitblt(sc, sc->sc_width + 10, 0, x, y, wi, he, RopSrc);
1115	} else
1116		gftfb_real_rectfill(sc, x, y, wi, he, bg);
1117}
1118
1119static void
1120gftfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi,
1121			    int he, int rop)
1122{
1123	struct gftfb_softc *sc = cookie;
1124	struct sti_rom *rom = sc->sc_base.sc_rom;
1125	bus_space_tag_t memt = rom->memt;
1126	bus_space_handle_t memh = rom->regh[2];
1127
1128	if (sc->sc_hwmode != HW_BLIT) {
1129		gftfb_wait(sc);
1130		bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0x13a01000);
1131		sc->sc_hwmode = HW_BLIT;
1132	}
1133	gftfb_wait_fifo(sc, 5);
1134	bus_space_write_stream_4(memt, memh, NGLE_REG_14, ((rop << 8) & 0xf00) | 0x23000000);
1135	bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xff);
1136	bus_space_write_stream_4(memt, memh, NGLE_REG_24, (xs << 16) | ys);
1137	bus_space_write_stream_4(memt, memh, NGLE_REG_7, (wi << 16) | he);
1138	bus_space_write_stream_4(memt, memh, NGLE_REG_25, (xd << 16) | yd);
1139}
1140
1141static void
1142gftfb_nuke_cursor(struct rasops_info *ri)
1143{
1144	struct vcons_screen *scr = ri->ri_hw;
1145	struct gftfb_softc *sc = scr->scr_cookie;
1146	int wi, he, x, y;
1147
1148	if (ri->ri_flg & RI_CURSOR) {
1149		wi = ri->ri_font->fontwidth;
1150		he = ri->ri_font->fontheight;
1151		x = ri->ri_ccol * wi + ri->ri_xorigin;
1152		y = ri->ri_crow * he + ri->ri_yorigin;
1153		gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
1154		ri->ri_flg &= ~RI_CURSOR;
1155	}
1156}
1157
1158static void
1159gftfb_cursor(void *cookie, int on, int row, int col)
1160{
1161	struct rasops_info *ri = cookie;
1162	struct vcons_screen *scr = ri->ri_hw;
1163	struct gftfb_softc *sc = scr->scr_cookie;
1164	int x, y, wi, he;
1165
1166	wi = ri->ri_font->fontwidth;
1167	he = ri->ri_font->fontheight;
1168
1169	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1170		if (on) {
1171			if (ri->ri_flg & RI_CURSOR) {
1172				gftfb_nuke_cursor(ri);
1173			}
1174			x = col * wi + ri->ri_xorigin;
1175			y = row * he + ri->ri_yorigin;
1176			gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
1177			ri->ri_flg |= RI_CURSOR;
1178		}
1179		ri->ri_crow = row;
1180		ri->ri_ccol = col;
1181	} else
1182	{
1183		ri->ri_crow = row;
1184		ri->ri_ccol = col;
1185		ri->ri_flg &= ~RI_CURSOR;
1186	}
1187
1188}
1189
1190static void
1191gftfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1192{
1193	struct rasops_info *ri = cookie;
1194	struct wsdisplay_font *font = PICK_FONT(ri, c);
1195	struct vcons_screen *scr = ri->ri_hw;
1196	struct gftfb_softc *sc = scr->scr_cookie;
1197	int x, y, wi, he, rv = GC_NOPE;
1198	uint32_t bg;
1199
1200	if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1201		return;
1202
1203	if (!CHAR_IN_FONT(c, font))
1204		return;
1205
1206	if (row == ri->ri_crow && col == ri->ri_ccol) {
1207		ri->ri_flg &= ~RI_CURSOR;
1208	}
1209
1210	wi = font->fontwidth;
1211	he = font->fontheight;
1212
1213	x = ri->ri_xorigin + col * wi;
1214	y = ri->ri_yorigin + row * he;
1215
1216	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1217
1218	if (c == 0x20) {
1219		gftfb_rectfill(sc, x, y, wi, he, bg);
1220		return;
1221	}
1222
1223	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1224	if (rv == GC_OK)
1225		return;
1226
1227	if (sc->sc_hwmode != HW_FB) gftfb_setup_fb(sc);
1228	sc->sc_putchar(cookie, row, col, c, attr);
1229
1230	if (rv == GC_ADD)
1231		glyphcache_add(&sc->sc_gc, c, x, y);
1232}
1233
1234static void
1235gftfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1236{
1237	struct rasops_info *ri = cookie;
1238	struct vcons_screen *scr = ri->ri_hw;
1239	struct gftfb_softc *sc = scr->scr_cookie;
1240	int32_t xs, xd, y, width, height;
1241
1242	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1243		if (ri->ri_crow == row &&
1244		   (ri->ri_ccol >= srccol && ri->ri_ccol < (srccol + ncols)) &&
1245		   (ri->ri_flg & RI_CURSOR)) {
1246			gftfb_nuke_cursor(ri);
1247		}
1248
1249		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1250		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1251		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1252		width = ri->ri_font->fontwidth * ncols;
1253		height = ri->ri_font->fontheight;
1254		gftfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc);
1255		if (ri->ri_crow == row &&
1256		   (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols)))
1257			ri->ri_flg &= ~RI_CURSOR;
1258	}
1259}
1260
1261static void
1262gftfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1263{
1264	struct rasops_info *ri = cookie;
1265	struct vcons_screen *scr = ri->ri_hw;
1266	struct gftfb_softc *sc = scr->scr_cookie;
1267	int32_t x, y, width, height, fg, bg, ul;
1268
1269	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1270		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1271		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1272		width = ri->ri_font->fontwidth * ncols;
1273		height = ri->ri_font->fontheight;
1274		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1275
1276		gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1277		if (ri->ri_crow == row &&
1278		   (ri->ri_ccol >= startcol && ri->ri_ccol < (startcol + ncols)))
1279			ri->ri_flg &= ~RI_CURSOR;
1280	}
1281}
1282
1283static void
1284gftfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1285{
1286	struct rasops_info *ri = cookie;
1287	struct vcons_screen *scr = ri->ri_hw;
1288	struct gftfb_softc *sc = scr->scr_cookie;
1289	int32_t x, ys, yd, width, height;
1290
1291	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1292		if ((ri->ri_crow >= srcrow && ri->ri_crow < (srcrow + nrows)) &&
1293		   (ri->ri_flg & RI_CURSOR)) {
1294			gftfb_nuke_cursor(ri);
1295		}
1296		x = ri->ri_xorigin;
1297		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1298		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1299		width = ri->ri_emuwidth;
1300		height = ri->ri_font->fontheight * nrows;
1301		gftfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc);
1302		if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows))
1303			ri->ri_flg &= ~RI_CURSOR;
1304	}
1305}
1306
1307static void
1308gftfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1309{
1310	struct rasops_info *ri = cookie;
1311	struct vcons_screen *scr = ri->ri_hw;
1312	struct gftfb_softc *sc = scr->scr_cookie;
1313	int32_t x, y, width, height, fg, bg, ul;
1314
1315	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1316		x = ri->ri_xorigin;
1317		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1318		width = ri->ri_emuwidth;
1319		height = ri->ri_font->fontheight * nrows;
1320		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1321
1322		gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1323
1324		if (ri->ri_crow >= row && ri->ri_crow < (row + nrows))
1325			ri->ri_flg &= ~RI_CURSOR;
1326	}
1327}
1328
1329/*
1330 * cursor sprite handling
1331 * like most hw info, xf86 3.3 -> nglehdw.h was used as documentation
1332 * problem is, the PCI EG doesn't quite behave like an S9000_ID_ARTIST
1333 * the cursor position register bahaves like the one on HCRX while using
1334 * the same address as Artist, incuding the enable bit and weird handling
1335 * of negative coordinates. The rest of it, colour map, sprite image etc.,
1336 * behave like Artist.
1337 */
1338
1339static void
1340gftfb_move_cursor(struct gftfb_softc *sc, int x, int y)
1341{
1342	struct sti_rom *rom = sc->sc_base.sc_rom;
1343	bus_space_tag_t memt = rom->memt;
1344	bus_space_handle_t memh = rom->regh[2];
1345	uint32_t pos;
1346
1347	sc->sc_cursor_x = x;
1348	x -= sc->sc_hot_x;
1349	sc->sc_cursor_y = y;
1350	y -= sc->sc_hot_y;
1351
1352	if (x < 0) x = 0x1000 - x;
1353	if (y < 0) y = 0x1000 - y;
1354	pos = (x << 16) | y;
1355	if (sc->sc_enabled) pos |= 0x80000000;
1356	gftfb_wait(sc);
1357	bus_space_write_stream_4(memt, memh, NGLE_REG_17, pos);
1358	bus_space_write_stream_4(memt, memh, NGLE_REG_18, 0x80);
1359}
1360
1361static int
1362gftfb_do_cursor(struct gftfb_softc *sc, struct wsdisplay_cursor *cur)
1363{
1364	struct sti_rom *rom = sc->sc_base.sc_rom;
1365	bus_space_tag_t memt = rom->memt;
1366	bus_space_handle_t memh = rom->regh[2];
1367
1368	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1369
1370		sc->sc_enabled = cur->enable;
1371		cur->which |= WSDISPLAY_CURSOR_DOPOS;
1372	}
1373	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1374
1375		sc->sc_hot_x = cur->hot.x;
1376		sc->sc_hot_y = cur->hot.y;
1377		cur->which |= WSDISPLAY_CURSOR_DOPOS;
1378	}
1379	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1380
1381		gftfb_move_cursor(sc, cur->pos.x, cur->pos.y);
1382	}
1383	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1384		uint32_t rgb;
1385		uint8_t r[2], g[2], b[2];
1386
1387		copyin(cur->cmap.blue, b, 2);
1388		copyin(cur->cmap.green, g, 2);
1389		copyin(cur->cmap.red, r, 2);
1390		mutex_enter(&sc->sc_hwlock);
1391		gftfb_wait(sc);
1392		bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xBBE0F000);
1393		bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1394		bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1395		gftfb_wait(sc);
1396		bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
1397		bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
1398		bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
1399		rgb = (r[0] << 16) | (g[0] << 8) | b[0];
1400		bus_space_write_stream_4(memt, memh, NGLE_REG_4, rgb);	/* BG */
1401		rgb = (r[1] << 16) | (g[1] << 8) | b[1];
1402		bus_space_write_stream_4(memt, memh, NGLE_REG_4, rgb);	/* FG */
1403		bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0);
1404		bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80008004);
1405		gftfb_setup_fb(sc);
1406		mutex_exit(&sc->sc_hwlock);
1407
1408	}
1409	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1410		uint32_t buffer[128], latch, tmp;
1411		int i;
1412
1413		copyin(cur->mask, buffer, 512);
1414		gftfb_wait(sc);
1415		bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
1416		bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1417		bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A07000);
1418		bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
1419		for (i = 0; i < 128; i += 2) {
1420			latch = 0;
1421			tmp = buffer[i] & 0x80808080;
1422			latch |= tmp >> 7;
1423			tmp = buffer[i] & 0x40404040;
1424			latch |= tmp >> 5;
1425			tmp = buffer[i] & 0x20202020;
1426			latch |= tmp >> 3;
1427			tmp = buffer[i] & 0x10101010;
1428			latch |= tmp >> 1;
1429			tmp = buffer[i] & 0x08080808;
1430			latch |= tmp << 1;
1431			tmp = buffer[i] & 0x04040404;
1432			latch |= tmp << 3;
1433			tmp = buffer[i] & 0x02020202;
1434			latch |= tmp << 5;
1435			tmp = buffer[i] & 0x01010101;
1436			latch |= tmp << 7;
1437			bus_space_write_stream_4(memt, memh, NGLE_REG_4, latch);
1438			latch = 0;
1439			tmp = buffer[i + 1] & 0x80808080;
1440			latch |= tmp >> 7;
1441			tmp = buffer[i + 1] & 0x40404040;
1442			latch |= tmp >> 5;
1443			tmp = buffer[i + 1] & 0x20202020;
1444			latch |= tmp >> 3;
1445			tmp = buffer[i + 1] & 0x10101010;
1446			latch |= tmp >> 1;
1447			tmp = buffer[i + 1] & 0x08080808;
1448			latch |= tmp << 1;
1449			tmp = buffer[i + 1] & 0x04040404;
1450			latch |= tmp << 3;
1451			tmp = buffer[i + 1] & 0x02020202;
1452			latch |= tmp << 5;
1453			tmp = buffer[i + 1] & 0x01010101;
1454			latch |= tmp << 7;
1455			bus_space_write_stream_4(memt, memh, NGLE_REG_5, latch);
1456		}
1457
1458		copyin(cur->image, buffer, 512);
1459		gftfb_wait(sc);
1460		bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
1461		bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1462		bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A06000);
1463		bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
1464		for (i = 0; i < 128; i += 2) {
1465			latch = 0;
1466			tmp = buffer[i] & 0x80808080;
1467			latch |= tmp >> 7;
1468			tmp = buffer[i] & 0x40404040;
1469			latch |= tmp >> 5;
1470			tmp = buffer[i] & 0x20202020;
1471			latch |= tmp >> 3;
1472			tmp = buffer[i] & 0x10101010;
1473			latch |= tmp >> 1;
1474			tmp = buffer[i] & 0x08080808;
1475			latch |= tmp << 1;
1476			tmp = buffer[i] & 0x04040404;
1477			latch |= tmp << 3;
1478			tmp = buffer[i] & 0x02020202;
1479			latch |= tmp << 5;
1480			tmp = buffer[i] & 0x01010101;
1481			latch |= tmp << 7;
1482			bus_space_write_stream_4(memt, memh, NGLE_REG_4, latch);
1483			latch = 0;
1484			tmp = buffer[i + 1] & 0x80808080;
1485			latch |= tmp >> 7;
1486			tmp = buffer[i + 1] & 0x40404040;
1487			latch |= tmp >> 5;
1488			tmp = buffer[i + 1] & 0x20202020;
1489			latch |= tmp >> 3;
1490			tmp = buffer[i + 1] & 0x10101010;
1491			latch |= tmp >> 1;
1492			tmp = buffer[i + 1] & 0x08080808;
1493			latch |= tmp << 1;
1494			tmp = buffer[i + 1] & 0x04040404;
1495			latch |= tmp << 3;
1496			tmp = buffer[i + 1] & 0x02020202;
1497			latch |= tmp << 5;
1498			tmp = buffer[i + 1] & 0x01010101;
1499			latch |= tmp << 7;
1500			bus_space_write_stream_4(memt, memh, NGLE_REG_5, latch);
1501		}
1502		gftfb_setup_fb(sc);
1503	}
1504
1505	return 0;
1506}
1507
1508static void
1509gftfb_set_video(struct gftfb_softc *sc, int on)
1510{
1511	struct sti_rom *rom = sc->sc_base.sc_rom;
1512	bus_space_tag_t memt = rom->memt;
1513	bus_space_handle_t memh = rom->regh[2];
1514
1515	if (sc->sc_video_on == on)
1516		return;
1517
1518	sc->sc_video_on = on;
1519
1520	gftfb_wait(sc);
1521	if (on) {
1522		bus_space_write_stream_4(memt, memh, NGLE_REG_21,
1523		    bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1524		bus_space_write_stream_4(memt, memh, NGLE_REG_27,
1525		    bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
1526	} else {
1527		bus_space_write_stream_4(memt, memh, NGLE_REG_21,
1528		    bus_space_read_stream_4(memt, memh, NGLE_REG_21) &  ~0x0a000000);
1529		bus_space_write_stream_4(memt, memh, NGLE_REG_27,
1530		    bus_space_read_stream_4(memt, memh, NGLE_REG_27) & ~0x00800000);
1531	}
1532}
1533