xref: /openbsd-src/sys/arch/sparc64/dev/gfxp.c (revision 63294167c4eaf171adac4fb2d8cc6d072a13af61)
1*63294167Skettenis /*	$OpenBSD: gfxp.c,v 1.16 2022/07/15 17:57:26 kettenis Exp $	*/
2df2aaf71Skettenis 
3df2aaf71Skettenis /*
4df2aaf71Skettenis  * Copyright (c) 2009 Mark Kettenis.
5df2aaf71Skettenis  *
6df2aaf71Skettenis  * Permission to use, copy, modify, and distribute this software for any
7df2aaf71Skettenis  * purpose with or without fee is hereby granted, provided that the above
8df2aaf71Skettenis  * copyright notice and this permission notice appear in all copies.
9df2aaf71Skettenis  *
10df2aaf71Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11df2aaf71Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12df2aaf71Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13df2aaf71Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14df2aaf71Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15df2aaf71Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16df2aaf71Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17df2aaf71Skettenis  */
18df2aaf71Skettenis 
19df2aaf71Skettenis #include <sys/param.h>
20df2aaf71Skettenis #include <sys/device.h>
21df2aaf71Skettenis #include <sys/pciio.h>
22df2aaf71Skettenis #include <sys/systm.h>
23df2aaf71Skettenis 
24df2aaf71Skettenis #include <machine/autoconf.h>
25df2aaf71Skettenis #include <machine/bus.h>
26df2aaf71Skettenis #include <machine/openfirm.h>
27df2aaf71Skettenis 
28df2aaf71Skettenis #include <dev/pci/pcireg.h>
29df2aaf71Skettenis #include <dev/pci/pcivar.h>
30df2aaf71Skettenis #include <dev/pci/pcidevs.h>
31df2aaf71Skettenis 
32df2aaf71Skettenis #include <dev/wscons/wsconsio.h>
33df2aaf71Skettenis #include <dev/wscons/wsdisplayvar.h>
34df2aaf71Skettenis 
35df2aaf71Skettenis #include <dev/rasops/rasops.h>
36df2aaf71Skettenis 
37df2aaf71Skettenis #include <machine/fbvar.h>
38df2aaf71Skettenis 
39ea4ebcbaSkettenis /*
40ea4ebcbaSkettenis  * The Permedia 2 provides two views into its 64k register file.  The
41ea4ebcbaSkettenis  * first view is little-endian, the second is big-endian and
42ea4ebcbaSkettenis  * immediately follows the little-endian view.  Since bus_space(9)
43ea4ebcbaSkettenis  * already does the byte order conversion for us, we use the
44ea4ebcbaSkettenis  * little-endian view.
45ea4ebcbaSkettenis  *
46ea4ebcbaSkettenis  * There are also little-endian and big-endian views into the
47ea4ebcbaSkettenis  * framebuffer.  These are made available through separate BARs.  We
48ea4ebcbaSkettenis  * use the big-endian view in this driver to avoid unnecessary byte
49ea4ebcbaSkettenis  * swapping in rasops(9).
50ea4ebcbaSkettenis  */
51df2aaf71Skettenis #define PM2_PCI_MMIO		0x10 	/* Registers */
52df2aaf71Skettenis #define PM2_PCI_MEM_LE		0x14 	/* Framebuffer (little-endian) */
53df2aaf71Skettenis #define PM2_PCI_MEM_BE		0x18	/* Framebuffer (big-endian) */
54df2aaf71Skettenis 
55df2aaf71Skettenis #define PM2_IN_FIFO_SPACE	0x0018
56ea4ebcbaSkettenis #define PM2_OUT_FIFO_SPACE	0x0020
57ea4ebcbaSkettenis #define PM2_DMA_COUNT		0x0030
58ea4ebcbaSkettenis 
59ea4ebcbaSkettenis #define PM2_OUT_FIFO		0x2000
60ea4ebcbaSkettenis #define  PM2_SYNC_TAG			0x00000188
61ea4ebcbaSkettenis 
62292a3d08Skettenis #define PM2_PALETTE_WRITE_ADDR	0x4000
63292a3d08Skettenis #define PM2_PALETTE_DATA	0x4008
64292a3d08Skettenis 
65fcf0d935Skettenis #define PM2V_INDEX_LOW		0x4020
66fcf0d935Skettenis #define PM2V_INDEX_HIGH		0x4028
67fcf0d935Skettenis #define PM2V_INDEX_DATA		0x4030
68fcf0d935Skettenis #define  PM2V_CURSOR_MODE		0x0005
69fcf0d935Skettenis #define  PM2V_CURSOR_PATTERN		0x0400
70fcf0d935Skettenis 
71ea4ebcbaSkettenis #define PM2_RENDER		0x8038
7210f81fd2Skettenis #define  PM2_RENDER_FASTFILL		0x00000008
7310f81fd2Skettenis #define  PM2_RENDER_RECT		0x000000c0
74ea4ebcbaSkettenis #define  PM2_INCREASE_X			0x00200000
75ea4ebcbaSkettenis #define  PM2_INCREASE_Y			0x00400000
76ea4ebcbaSkettenis #define PM2_RECT_ORIG		0x80d0
77ea4ebcbaSkettenis #define PM2_RECT_SIZE		0x80d8
78ea4ebcbaSkettenis 
7959d99acbSkettenis #define PM2_FB_READ_MODE	0x8a80
8010f81fd2Skettenis #define PM2_FB_BLOCK_COLOR	0x8ac8
818b23122bSkettenis #define PM2_FB_READ_PIXEL	0x8ad0
8210f81fd2Skettenis 
83ea4ebcbaSkettenis #define PM2_FILTER_MODE		0x8c00
84ea4ebcbaSkettenis #define  PM2_FM_PASS_SYNC_TAG		0x00000400
85ea4ebcbaSkettenis #define PM2_SYNC		0x8c40
86ea4ebcbaSkettenis 
87ea4ebcbaSkettenis #define PM2_FB_SRC_DELTA	0x8d88
88ea4ebcbaSkettenis #define PM2_CONFIG		0x8d90
89ea4ebcbaSkettenis #define  PM2_CONFIG_FB_READ_SRC_EN	0x00000001
90ea4ebcbaSkettenis #define  PM2_CONFIG_FB_WRITE_EN		0x00000008
91ea4ebcbaSkettenis 
92ea4ebcbaSkettenis #define PM2_COORDS(x, y)	((y) << 16 | (x))
93df2aaf71Skettenis 
94df2aaf71Skettenis 
95df2aaf71Skettenis #ifdef APERTURE
96df2aaf71Skettenis extern int allowaperture;
97df2aaf71Skettenis #endif
98df2aaf71Skettenis 
99df2aaf71Skettenis struct gfxp_softc {
100df2aaf71Skettenis 	struct sunfb	sc_sunfb;
101df2aaf71Skettenis 
102df2aaf71Skettenis 	bus_space_tag_t sc_memt;
103df2aaf71Skettenis 	bus_space_handle_t sc_memh;
104df2aaf71Skettenis 	bus_addr_t	sc_membase_le;
105df2aaf71Skettenis 	bus_size_t	sc_memsize_le;
106df2aaf71Skettenis 	bus_addr_t	sc_membase_be;
107df2aaf71Skettenis 	bus_size_t	sc_memsize_be;
108df2aaf71Skettenis 
109df2aaf71Skettenis 	bus_space_tag_t	sc_mmiot;
110df2aaf71Skettenis 	bus_space_handle_t sc_mmioh;
111df2aaf71Skettenis 	bus_addr_t	sc_mmiobase;
112df2aaf71Skettenis 	bus_size_t	sc_mmiosize;
113df2aaf71Skettenis 
114df2aaf71Skettenis 	pcitag_t	sc_pcitag;
115df2aaf71Skettenis 
116df2aaf71Skettenis 	int		sc_mode;
117292a3d08Skettenis 	u_int8_t	sc_cmap_red[256];
118292a3d08Skettenis 	u_int8_t	sc_cmap_green[256];
119292a3d08Skettenis 	u_int8_t	sc_cmap_blue[256];
12059d99acbSkettenis 
12159d99acbSkettenis 	/* Saved state to clean up after X11. */
12259d99acbSkettenis 	uint32_t	sc_read_mode;
1238b23122bSkettenis 	uint32_t	sc_read_pixel;
124df2aaf71Skettenis };
125df2aaf71Skettenis 
126df2aaf71Skettenis int	gfxp_ioctl(void *, u_long, caddr_t, int, struct proc *);
127df2aaf71Skettenis paddr_t	gfxp_mmap(void *, off_t, int);
128df2aaf71Skettenis 
129df2aaf71Skettenis struct wsdisplay_accessops gfxp_accessops = {
13087eec248Smiod 	.ioctl = gfxp_ioctl,
13187eec248Smiod 	.mmap = gfxp_mmap
132df2aaf71Skettenis };
133df2aaf71Skettenis 
134df2aaf71Skettenis int	gfxp_match(struct device *, void *, void *);
135df2aaf71Skettenis void	gfxp_attach(struct device *, struct device *, void *);
136df2aaf71Skettenis 
137eb7eaf8dSmpi const struct cfattach gfxp_ca = {
138df2aaf71Skettenis 	sizeof(struct gfxp_softc), gfxp_match, gfxp_attach
139df2aaf71Skettenis };
140df2aaf71Skettenis 
141df2aaf71Skettenis struct cfdriver gfxp_cd = {
142df2aaf71Skettenis 	NULL, "gfxp", DV_DULL
143df2aaf71Skettenis };
144df2aaf71Skettenis 
145df2aaf71Skettenis int	gfxp_is_console(int);
146292a3d08Skettenis int	gfxp_getcmap(struct gfxp_softc *, struct wsdisplay_cmap *);
147292a3d08Skettenis int	gfxp_putcmap(struct gfxp_softc *, struct wsdisplay_cmap *);
148292a3d08Skettenis void	gfxp_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
149df2aaf71Skettenis 
150072953e3Smiod int	gfxp_copycols(void *, int, int, int, int);
151e0c3e559Sjsg int	gfxp_erasecols(void *, int, int, int, uint32_t);
152072953e3Smiod int	gfxp_copyrows(void *, int, int, int);
153e0c3e559Sjsg int	gfxp_eraserows(void *, int, int, uint32_t);
154df2aaf71Skettenis 
15559d99acbSkettenis void	gfxp_init(struct gfxp_softc *);
15659d99acbSkettenis void	gfxp_reinit(struct gfxp_softc *);
157fcf0d935Skettenis 
158fcf0d935Skettenis void	gfxp_indexed_write(struct gfxp_softc *, bus_size_t, uint32_t);
159df2aaf71Skettenis int	gfxp_wait(struct gfxp_softc *);
160df2aaf71Skettenis int	gfxp_wait_fifo(struct gfxp_softc *, int);
161df2aaf71Skettenis void	gfxp_copyrect(struct gfxp_softc *, int, int, int, int, int, int);
162df2aaf71Skettenis void	gfxp_fillrect(struct gfxp_softc *, int, int, int, int, int);
163df2aaf71Skettenis 
164df2aaf71Skettenis int
gfxp_match(struct device * parent,void * cf,void * aux)165df2aaf71Skettenis gfxp_match(struct device *parent, void *cf, void *aux)
166df2aaf71Skettenis {
167df2aaf71Skettenis 	struct pci_attach_args *pa = aux;
168df2aaf71Skettenis 	int node;
169df2aaf71Skettenis 	char *name;
170df2aaf71Skettenis 
171df2aaf71Skettenis 	node = PCITAG_NODE(pa->pa_tag);
172df2aaf71Skettenis 	name = getpropstring(node, "name");
173df2aaf71Skettenis 	if (strcmp(name, "TECH-SOURCE,gfxp") == 0 ||
174df2aaf71Skettenis 	    strcmp(name, "TSI,gfxp") == 0)
175df2aaf71Skettenis 		return (10);
176df2aaf71Skettenis 
177df2aaf71Skettenis 	return (0);
178df2aaf71Skettenis }
179df2aaf71Skettenis 
180df2aaf71Skettenis void
gfxp_attach(struct device * parent,struct device * self,void * aux)181df2aaf71Skettenis gfxp_attach(struct device *parent, struct device *self, void *aux)
182df2aaf71Skettenis {
183df2aaf71Skettenis 	struct gfxp_softc *sc = (struct gfxp_softc *)self;
184df2aaf71Skettenis 	struct pci_attach_args *pa = aux;
185df2aaf71Skettenis 	struct rasops_info *ri;
18682ed75efSkettenis 	int node, console, flags;
187df2aaf71Skettenis 	char *model;
188df2aaf71Skettenis 
189df2aaf71Skettenis 	sc->sc_pcitag = pa->pa_tag;
190df2aaf71Skettenis 
191df2aaf71Skettenis 	node = PCITAG_NODE(pa->pa_tag);
192df2aaf71Skettenis 	console = gfxp_is_console(node);
193df2aaf71Skettenis 
194df2aaf71Skettenis 	printf("\n");
195df2aaf71Skettenis 
196df2aaf71Skettenis 	model = getpropstring(node, "model");
197df2aaf71Skettenis 	printf("%s: %s", self->dv_xname, model);
198df2aaf71Skettenis 
199df2aaf71Skettenis 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PM2_PCI_MEM_LE,
200df2aaf71Skettenis 	    PCI_MAPREG_TYPE_MEM, &sc->sc_membase_le, &sc->sc_memsize_le, NULL))
201df2aaf71Skettenis 		sc->sc_memsize_le = 0;
202df2aaf71Skettenis 
203df2aaf71Skettenis 	if (pci_mapreg_map(pa, PM2_PCI_MEM_BE, PCI_MAPREG_TYPE_MEM,
204df2aaf71Skettenis 	    BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
205df2aaf71Skettenis 	    &sc->sc_membase_be, &sc->sc_memsize_be, 0)) {
206df2aaf71Skettenis 		printf("\n%s: can't map video memory\n", self->dv_xname);
207df2aaf71Skettenis 		return;
208df2aaf71Skettenis 	}
209df2aaf71Skettenis 
210df2aaf71Skettenis 	if (pci_mapreg_map(pa, PM2_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
211df2aaf71Skettenis 	    &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase,
212df2aaf71Skettenis 	    &sc->sc_mmiosize, 0)) {
213df2aaf71Skettenis 		bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize_be);
214df2aaf71Skettenis 		printf("\n%s: can't map mmio\n", self->dv_xname);
215df2aaf71Skettenis 		return;
216df2aaf71Skettenis 	}
217df2aaf71Skettenis 
218df2aaf71Skettenis 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
219df2aaf71Skettenis 
220df2aaf71Skettenis 	printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
221df2aaf71Skettenis 
222df2aaf71Skettenis 	ri = &sc->sc_sunfb.sf_ro;
223df2aaf71Skettenis 	ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh);
224df2aaf71Skettenis 	ri->ri_hw = sc;
225df2aaf71Skettenis 
22682ed75efSkettenis 	flags = RI_BSWAP;
22782ed75efSkettenis 	if (sc->sc_sunfb.sf_depth == 32) {
228df2aaf71Skettenis 		ri->ri_rnum = 8;
229df2aaf71Skettenis 		ri->ri_rpos = 16;
230df2aaf71Skettenis 		ri->ri_gnum = 8;
231df2aaf71Skettenis 		ri->ri_gpos = 8;
232df2aaf71Skettenis 		ri->ri_bnum = 8;
233df2aaf71Skettenis 		ri->ri_bpos = 0;
23482ed75efSkettenis 		flags &= ~RI_BSWAP;
23582ed75efSkettenis 	}
236df2aaf71Skettenis 
23782ed75efSkettenis 	fbwscons_init(&sc->sc_sunfb, flags, console);
238292a3d08Skettenis 	fbwscons_setcolormap(&sc->sc_sunfb, gfxp_setcolor);
239df2aaf71Skettenis 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
240df2aaf71Skettenis 
24159d99acbSkettenis 	gfxp_init(sc);
242ea4ebcbaSkettenis 	ri->ri_ops.copyrows = gfxp_copyrows;
243ea4ebcbaSkettenis 	ri->ri_ops.copycols = gfxp_copycols;
24410f81fd2Skettenis 	ri->ri_ops.eraserows = gfxp_eraserows;
24510f81fd2Skettenis 	ri->ri_ops.erasecols = gfxp_erasecols;
246ea4ebcbaSkettenis 
247df2aaf71Skettenis 	if (console)
248df2aaf71Skettenis 		fbwscons_console_init(&sc->sc_sunfb, -1);
249df2aaf71Skettenis 	fbwscons_attach(&sc->sc_sunfb, &gfxp_accessops, console);
250df2aaf71Skettenis }
251df2aaf71Skettenis 
252df2aaf71Skettenis int
gfxp_ioctl(void * v,u_long cmd,caddr_t data,int flags,struct proc * p)253df2aaf71Skettenis gfxp_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
254df2aaf71Skettenis {
255df2aaf71Skettenis 	struct gfxp_softc *sc = v;
256df2aaf71Skettenis 	struct wsdisplay_fbinfo *wdf;
257df2aaf71Skettenis 	struct pcisel *sel;
258df2aaf71Skettenis 
259df2aaf71Skettenis 	switch (cmd) {
260df2aaf71Skettenis 	case WSDISPLAYIO_GTYPE:
261df2aaf71Skettenis 		*(u_int *)data = WSDISPLAY_TYPE_GFXP;
262df2aaf71Skettenis 		break;
263df2aaf71Skettenis 	case WSDISPLAYIO_SMODE:
264df2aaf71Skettenis 		sc->sc_mode = *(u_int *)data;
265292a3d08Skettenis 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
266292a3d08Skettenis 			fbwscons_setcolormap(&sc->sc_sunfb, gfxp_setcolor);
267292a3d08Skettenis 
268292a3d08Skettenis 			/* Clean up the mess left behind by X. */
26959d99acbSkettenis 			gfxp_reinit(sc);
270292a3d08Skettenis 		}
271df2aaf71Skettenis 		break;
272df2aaf71Skettenis 	case WSDISPLAYIO_GINFO:
273df2aaf71Skettenis 		wdf = (void *)data;
274df2aaf71Skettenis 		wdf->height = sc->sc_sunfb.sf_height;
275df2aaf71Skettenis 		wdf->width  = sc->sc_sunfb.sf_width;
276df2aaf71Skettenis 		wdf->depth  = sc->sc_sunfb.sf_depth;
277*63294167Skettenis 		wdf->stride = sc->sc_sunfb.sf_linebytes;
278*63294167Skettenis 		wdf->offset = 0;
279292a3d08Skettenis 		if (sc->sc_sunfb.sf_depth == 32)
280df2aaf71Skettenis 			wdf->cmsize = 0;
281292a3d08Skettenis 		else
282292a3d08Skettenis 			wdf->cmsize = 256;
283df2aaf71Skettenis 		break;
284df2aaf71Skettenis 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
28582ed75efSkettenis 		if (sc->sc_sunfb.sf_depth == 32)
286df2aaf71Skettenis 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
28782ed75efSkettenis 		else
28882ed75efSkettenis 			return (-1);
289df2aaf71Skettenis 		break;
290df2aaf71Skettenis 	case WSDISPLAYIO_LINEBYTES:
291df2aaf71Skettenis 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
292df2aaf71Skettenis 		break;
293df2aaf71Skettenis 
294292a3d08Skettenis 	case WSDISPLAYIO_GETCMAP:
295292a3d08Skettenis 		return gfxp_getcmap(sc, (struct wsdisplay_cmap *)data);
296292a3d08Skettenis 	case WSDISPLAYIO_PUTCMAP:
297292a3d08Skettenis 		return gfxp_putcmap(sc, (struct wsdisplay_cmap *)data);
298292a3d08Skettenis 
299df2aaf71Skettenis 	case WSDISPLAYIO_GPCIID:
300df2aaf71Skettenis 		sel = (struct pcisel *)data;
301df2aaf71Skettenis 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
302df2aaf71Skettenis 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
303df2aaf71Skettenis 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
304df2aaf71Skettenis 		break;
305df2aaf71Skettenis 
306df2aaf71Skettenis 	case WSDISPLAYIO_SVIDEO:
307df2aaf71Skettenis 	case WSDISPLAYIO_GVIDEO:
308df2aaf71Skettenis 		break;
309df2aaf71Skettenis 
310df2aaf71Skettenis 	case WSDISPLAYIO_GCURPOS:
311df2aaf71Skettenis 	case WSDISPLAYIO_SCURPOS:
312df2aaf71Skettenis 	case WSDISPLAYIO_GCURMAX:
313df2aaf71Skettenis 	case WSDISPLAYIO_GCURSOR:
314df2aaf71Skettenis 	case WSDISPLAYIO_SCURSOR:
315df2aaf71Skettenis 	default:
316df2aaf71Skettenis 		return -1; /* not supported yet */
317df2aaf71Skettenis         }
318df2aaf71Skettenis 
319df2aaf71Skettenis 	return (0);
320df2aaf71Skettenis }
321df2aaf71Skettenis 
322df2aaf71Skettenis paddr_t
gfxp_mmap(void * v,off_t off,int prot)323df2aaf71Skettenis gfxp_mmap(void *v, off_t off, int prot)
324df2aaf71Skettenis {
325df2aaf71Skettenis 	struct gfxp_softc *sc = v;
326df2aaf71Skettenis 
327df2aaf71Skettenis 	if (off & PGOFSET)
328df2aaf71Skettenis 		return (-1);
329df2aaf71Skettenis 
330df2aaf71Skettenis 	switch (sc->sc_mode) {
331df2aaf71Skettenis 	case WSDISPLAYIO_MODE_MAPPED:
332df2aaf71Skettenis #ifdef APERTURE
333df2aaf71Skettenis 		if (allowaperture == 0)
334df2aaf71Skettenis 			return (-1);
335df2aaf71Skettenis #endif
336df2aaf71Skettenis 
337df2aaf71Skettenis 		if (sc->sc_mmiosize == 0)
338df2aaf71Skettenis 			return (-1);
339df2aaf71Skettenis 
340df2aaf71Skettenis 		if (off >= sc->sc_membase_be &&
341df2aaf71Skettenis 		    off < (sc->sc_membase_be + sc->sc_memsize_be))
342df2aaf71Skettenis 			return (bus_space_mmap(sc->sc_memt,
343df2aaf71Skettenis 			    sc->sc_membase_be, off - sc->sc_membase_be,
344df2aaf71Skettenis 			    prot, BUS_SPACE_MAP_LINEAR));
345df2aaf71Skettenis 
346df2aaf71Skettenis 		if (off >= sc->sc_mmiobase &&
347df2aaf71Skettenis 		    off < (sc->sc_mmiobase + sc->sc_mmiosize))
348df2aaf71Skettenis 			return (bus_space_mmap(sc->sc_mmiot,
349df2aaf71Skettenis 			    sc->sc_mmiobase, off - sc->sc_mmiobase,
350df2aaf71Skettenis 			    prot, BUS_SPACE_MAP_LINEAR));
351df2aaf71Skettenis 		break;
352df2aaf71Skettenis 
353df2aaf71Skettenis 	case WSDISPLAYIO_MODE_DUMBFB:
354df2aaf71Skettenis 		if (off >= 0 && off < sc->sc_memsize_le)
355df2aaf71Skettenis 			return (bus_space_mmap(sc->sc_memt, sc->sc_membase_le,
356df2aaf71Skettenis 			    off, prot, BUS_SPACE_MAP_LINEAR));
357df2aaf71Skettenis 		break;
358df2aaf71Skettenis 	}
359df2aaf71Skettenis 
360df2aaf71Skettenis 	return (-1);
361df2aaf71Skettenis }
362df2aaf71Skettenis 
363df2aaf71Skettenis int
gfxp_is_console(int node)364df2aaf71Skettenis gfxp_is_console(int node)
365df2aaf71Skettenis {
366df2aaf71Skettenis 	extern int fbnode;
367df2aaf71Skettenis 
368df2aaf71Skettenis 	return (fbnode == node);
369df2aaf71Skettenis }
370df2aaf71Skettenis 
371292a3d08Skettenis int
gfxp_getcmap(struct gfxp_softc * sc,struct wsdisplay_cmap * cm)372292a3d08Skettenis gfxp_getcmap(struct gfxp_softc *sc, struct wsdisplay_cmap *cm)
373292a3d08Skettenis {
374292a3d08Skettenis 	u_int index = cm->index;
375292a3d08Skettenis 	u_int count = cm->count;
376292a3d08Skettenis 	int error;
377292a3d08Skettenis 
378292a3d08Skettenis 	if (index >= 256 || count > 256 - index)
379292a3d08Skettenis 		return (EINVAL);
380292a3d08Skettenis 
381292a3d08Skettenis 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
382292a3d08Skettenis 	if (error)
383292a3d08Skettenis 		return (error);
384292a3d08Skettenis 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
385292a3d08Skettenis 	if (error)
386292a3d08Skettenis 		return (error);
387292a3d08Skettenis 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
388292a3d08Skettenis 	if (error)
389292a3d08Skettenis 		return (error);
390292a3d08Skettenis 	return (0);
391292a3d08Skettenis }
392292a3d08Skettenis 
393292a3d08Skettenis int
gfxp_putcmap(struct gfxp_softc * sc,struct wsdisplay_cmap * cm)394292a3d08Skettenis gfxp_putcmap(struct gfxp_softc *sc, struct wsdisplay_cmap *cm)
395292a3d08Skettenis {
396292a3d08Skettenis 	u_int index = cm->index;
397292a3d08Skettenis 	u_int count = cm->count;
398292a3d08Skettenis 	u_int i;
399292a3d08Skettenis 	int error;
400292a3d08Skettenis 	u_char *r, *g, *b;
401292a3d08Skettenis 
402292a3d08Skettenis 	if (index >= 256 || count > 256 - index)
403292a3d08Skettenis 		return (EINVAL);
404292a3d08Skettenis 
405292a3d08Skettenis 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
406292a3d08Skettenis 		return (error);
407292a3d08Skettenis 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
408292a3d08Skettenis 		return (error);
409292a3d08Skettenis 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
410292a3d08Skettenis 		return (error);
411292a3d08Skettenis 
412292a3d08Skettenis 	r = &sc->sc_cmap_red[index];
413292a3d08Skettenis 	g = &sc->sc_cmap_green[index];
414292a3d08Skettenis 	b = &sc->sc_cmap_blue[index];
415292a3d08Skettenis 
416292a3d08Skettenis 	gfxp_wait_fifo(sc, 1);
417292a3d08Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
418292a3d08Skettenis 	    PM2_PALETTE_WRITE_ADDR, index);
419292a3d08Skettenis 	for (i = 0; i < count; i++) {
420292a3d08Skettenis 		gfxp_wait_fifo(sc, 3);
421292a3d08Skettenis 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
422292a3d08Skettenis 		    PM2_PALETTE_DATA, *r);
423292a3d08Skettenis 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
424292a3d08Skettenis 		    PM2_PALETTE_DATA, *g);
425292a3d08Skettenis 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
426292a3d08Skettenis 		    PM2_PALETTE_DATA, *b);
427292a3d08Skettenis 		r++, g++, b++;
428292a3d08Skettenis 	}
429292a3d08Skettenis 	return (0);
430292a3d08Skettenis }
431292a3d08Skettenis 
432292a3d08Skettenis void
gfxp_setcolor(void * v,u_int index,u_int8_t r,u_int8_t g,u_int8_t b)433292a3d08Skettenis gfxp_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
434292a3d08Skettenis {
435292a3d08Skettenis 	struct gfxp_softc *sc = v;
436292a3d08Skettenis 
437292a3d08Skettenis 	sc->sc_cmap_red[index] = r;
438292a3d08Skettenis 	sc->sc_cmap_green[index] = g;
439292a3d08Skettenis 	sc->sc_cmap_blue[index] = b;
440292a3d08Skettenis 
441292a3d08Skettenis 	gfxp_wait_fifo(sc, 4);
442292a3d08Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
443292a3d08Skettenis 	    PM2_PALETTE_WRITE_ADDR, index);
444292a3d08Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, r);
445292a3d08Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, g);
446292a3d08Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, b);
447292a3d08Skettenis }
448292a3d08Skettenis 
449ea4ebcbaSkettenis /*
450ea4ebcbaSkettenis  * Accelerated routines.
451ea4ebcbaSkettenis  */
452ea4ebcbaSkettenis 
453072953e3Smiod int
gfxp_copycols(void * cookie,int row,int src,int dst,int num)454ea4ebcbaSkettenis gfxp_copycols(void *cookie, int row, int src, int dst, int num)
455ea4ebcbaSkettenis {
456ea4ebcbaSkettenis 	struct rasops_info *ri = cookie;
457ea4ebcbaSkettenis 	struct gfxp_softc *sc = ri->ri_hw;
458ea4ebcbaSkettenis 
459ea4ebcbaSkettenis 	num *= ri->ri_font->fontwidth;
460ea4ebcbaSkettenis 	src *= ri->ri_font->fontwidth;
461ea4ebcbaSkettenis 	dst *= ri->ri_font->fontwidth;
462ea4ebcbaSkettenis 	row *= ri->ri_font->fontheight;
463ea4ebcbaSkettenis 
464ea4ebcbaSkettenis 	gfxp_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
465ea4ebcbaSkettenis 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
466ea4ebcbaSkettenis 	    num, ri->ri_font->fontheight);
467072953e3Smiod 
468072953e3Smiod 	return 0;
469ea4ebcbaSkettenis }
470ea4ebcbaSkettenis 
471072953e3Smiod int
gfxp_erasecols(void * cookie,int row,int col,int num,uint32_t attr)472e0c3e559Sjsg gfxp_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
473ea4ebcbaSkettenis {
474ea4ebcbaSkettenis 	struct rasops_info *ri = cookie;
475ea4ebcbaSkettenis 	struct gfxp_softc *sc = ri->ri_hw;
476ea4ebcbaSkettenis 	int bg, fg;
477ea4ebcbaSkettenis 
478ea4ebcbaSkettenis 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
479ea4ebcbaSkettenis 
480ea4ebcbaSkettenis 	row *= ri->ri_font->fontheight;
481ea4ebcbaSkettenis 	col *= ri->ri_font->fontwidth;
482ea4ebcbaSkettenis 	num *= ri->ri_font->fontwidth;
483ea4ebcbaSkettenis 
484ea4ebcbaSkettenis 	gfxp_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
485ea4ebcbaSkettenis 	    num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
486072953e3Smiod 
487072953e3Smiod 	return 0;
488ea4ebcbaSkettenis }
489ea4ebcbaSkettenis 
490072953e3Smiod int
gfxp_copyrows(void * cookie,int src,int dst,int num)491ea4ebcbaSkettenis gfxp_copyrows(void *cookie, int src, int dst, int num)
492ea4ebcbaSkettenis {
493ea4ebcbaSkettenis 	struct rasops_info *ri = cookie;
494ea4ebcbaSkettenis 	struct gfxp_softc *sc = ri->ri_hw;
495ea4ebcbaSkettenis 
496ea4ebcbaSkettenis 	num *= ri->ri_font->fontheight;
497ea4ebcbaSkettenis 	src *= ri->ri_font->fontheight;
498ea4ebcbaSkettenis 	dst *= ri->ri_font->fontheight;
499ea4ebcbaSkettenis 
500ea4ebcbaSkettenis 	gfxp_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
501ea4ebcbaSkettenis 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
502072953e3Smiod 
503072953e3Smiod 	return 0;
504ea4ebcbaSkettenis }
505ea4ebcbaSkettenis 
506072953e3Smiod int
gfxp_eraserows(void * cookie,int row,int num,uint32_t attr)507e0c3e559Sjsg gfxp_eraserows(void *cookie, int row, int num, uint32_t attr)
508ea4ebcbaSkettenis {
509ea4ebcbaSkettenis 	struct rasops_info *ri = cookie;
510ea4ebcbaSkettenis 	struct gfxp_softc *sc = ri->ri_hw;
511ea4ebcbaSkettenis 	int bg, fg;
512ea4ebcbaSkettenis 	int x, y, w;
513ea4ebcbaSkettenis 
514ea4ebcbaSkettenis 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
515ea4ebcbaSkettenis 
516ea4ebcbaSkettenis 	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
517ea4ebcbaSkettenis 		num = ri->ri_height;
518ea4ebcbaSkettenis 		x = y = 0;
519ea4ebcbaSkettenis 		w = ri->ri_width;
520ea4ebcbaSkettenis 	} else {
521ea4ebcbaSkettenis 		num *= ri->ri_font->fontheight;
522ea4ebcbaSkettenis 		x = ri->ri_xorigin;
523ea4ebcbaSkettenis 		y = ri->ri_yorigin + row * ri->ri_font->fontheight;
524ea4ebcbaSkettenis 		w = ri->ri_emuwidth;
525ea4ebcbaSkettenis 	}
526ea4ebcbaSkettenis 	gfxp_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
527072953e3Smiod 
528072953e3Smiod 	return 0;
529ea4ebcbaSkettenis }
530ea4ebcbaSkettenis 
53159d99acbSkettenis void
gfxp_init(struct gfxp_softc * sc)53259d99acbSkettenis gfxp_init(struct gfxp_softc *sc)
53359d99acbSkettenis {
534fcf0d935Skettenis 	/* XXX Save. */
53559d99acbSkettenis 	sc->sc_read_mode = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
53659d99acbSkettenis 	    PM2_FB_READ_MODE);
5378b23122bSkettenis 	sc->sc_read_pixel = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
5388b23122bSkettenis 	    PM2_FB_READ_PIXEL);
53959d99acbSkettenis }
54059d99acbSkettenis 
54159d99acbSkettenis void
gfxp_reinit(struct gfxp_softc * sc)54259d99acbSkettenis gfxp_reinit(struct gfxp_softc *sc)
54359d99acbSkettenis {
544380ef23fSkettenis 	struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
545fcf0d935Skettenis 	int i;
546fcf0d935Skettenis 
547fcf0d935Skettenis 	/* XXX Restore. */
54859d99acbSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
54959d99acbSkettenis 	    PM2_FB_READ_MODE, sc->sc_read_mode);
5508b23122bSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
5518b23122bSkettenis 	    PM2_FB_READ_PIXEL, sc->sc_read_pixel);
552fcf0d935Skettenis 
553fcf0d935Skettenis 	/* Disable cursor. */
554fcf0d935Skettenis 	gfxp_indexed_write(sc, PM2V_CURSOR_MODE, 0x10);
555fcf0d935Skettenis 
556fcf0d935Skettenis 	/* Clear cursor image. */
557fcf0d935Skettenis 	for (i = 0; i < 1024; i++)
558fcf0d935Skettenis 		gfxp_indexed_write(sc, PM2V_CURSOR_PATTERN + i, 0x00);
559380ef23fSkettenis 
560380ef23fSkettenis 	/* Clear screen. */
561380ef23fSkettenis 	gfxp_fillrect(sc, 0, 0, ri->ri_width, ri->ri_height,
562380ef23fSkettenis 	    ri->ri_devcmap[WSCOL_WHITE]);
563fcf0d935Skettenis }
564fcf0d935Skettenis 
565fcf0d935Skettenis void
gfxp_indexed_write(struct gfxp_softc * sc,bus_size_t offset,uint32_t value)566fcf0d935Skettenis gfxp_indexed_write(struct gfxp_softc *sc, bus_size_t offset, uint32_t value)
567fcf0d935Skettenis {
568fcf0d935Skettenis 	gfxp_wait_fifo(sc, 3);
569fcf0d935Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
570fcf0d935Skettenis 	    PM2V_INDEX_HIGH, offset >> 8);
571fcf0d935Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
572fcf0d935Skettenis 	    PM2V_INDEX_LOW, offset & 0xff);
573fcf0d935Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2V_INDEX_DATA, value);
57459d99acbSkettenis }
57559d99acbSkettenis 
576df2aaf71Skettenis int
gfxp_wait_fifo(struct gfxp_softc * sc,int n)577df2aaf71Skettenis gfxp_wait_fifo(struct gfxp_softc *sc, int n)
578df2aaf71Skettenis {
579df2aaf71Skettenis 	int i;
580df2aaf71Skettenis 
581df2aaf71Skettenis 	for (i = 1000000; i != 0; i--) {
582ea4ebcbaSkettenis 		if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
583df2aaf71Skettenis 		     PM2_IN_FIFO_SPACE) >= n)
584df2aaf71Skettenis 			break;
585df2aaf71Skettenis 		DELAY(1);
586df2aaf71Skettenis 	}
587df2aaf71Skettenis 
588df2aaf71Skettenis 	return i;
589df2aaf71Skettenis }
590ea4ebcbaSkettenis 
591ea4ebcbaSkettenis int
gfxp_wait(struct gfxp_softc * sc)592ea4ebcbaSkettenis gfxp_wait(struct gfxp_softc *sc)
593ea4ebcbaSkettenis {
594ea4ebcbaSkettenis 	int i;
595ea4ebcbaSkettenis 
596ea4ebcbaSkettenis 	for (i = 1000000; i != 0; i--) {
597ea4ebcbaSkettenis 		if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
598ea4ebcbaSkettenis 		    PM2_DMA_COUNT) == 0)
599ea4ebcbaSkettenis 			break;
600ea4ebcbaSkettenis 		DELAY(1);
601ea4ebcbaSkettenis 	}
602ea4ebcbaSkettenis 
603ea4ebcbaSkettenis 	/*
604ea4ebcbaSkettenis 	 * Insert a sync into the FIFO...
605ea4ebcbaSkettenis 	 */
606ea4ebcbaSkettenis 	gfxp_wait_fifo(sc, 2);
607ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
608ea4ebcbaSkettenis 	    PM2_FILTER_MODE, PM2_FM_PASS_SYNC_TAG);
609ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_SYNC, 0);
610ea4ebcbaSkettenis 
611ea4ebcbaSkettenis 	/*
612ea4ebcbaSkettenis 	 * ...and wait for it to appear on the other end, indicating
613ea4ebcbaSkettenis 	 * completion of the operations before it.
614ea4ebcbaSkettenis 	 */
615ea4ebcbaSkettenis 	for (i = 1000000; i != 0; i--) {
616ea4ebcbaSkettenis 		if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
617ea4ebcbaSkettenis 		    PM2_OUT_FIFO_SPACE) > 0 &&
618ea4ebcbaSkettenis 		    bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
619ea4ebcbaSkettenis 		    PM2_OUT_FIFO) == PM2_SYNC_TAG)
620ea4ebcbaSkettenis 			break;
621ea4ebcbaSkettenis 		DELAY(1);
622ea4ebcbaSkettenis 	}
623ea4ebcbaSkettenis 
624ea4ebcbaSkettenis 	return i;
625ea4ebcbaSkettenis }
626ea4ebcbaSkettenis 
627ea4ebcbaSkettenis void
gfxp_copyrect(struct gfxp_softc * sc,int sx,int sy,int dx,int dy,int w,int h)628ea4ebcbaSkettenis gfxp_copyrect(struct gfxp_softc *sc, int sx, int sy, int dx, int dy,
629ea4ebcbaSkettenis     int w, int h)
630ea4ebcbaSkettenis {
631ea4ebcbaSkettenis 	int dir = 0;
632ea4ebcbaSkettenis 
633ea4ebcbaSkettenis 	if (sx > dx)
634ea4ebcbaSkettenis 		dir |= PM2_INCREASE_X;
635ea4ebcbaSkettenis 	if (sy > dy)
636ea4ebcbaSkettenis 		dir |= PM2_INCREASE_Y;
637ea4ebcbaSkettenis 
638ea4ebcbaSkettenis 	gfxp_wait_fifo(sc, 5);
639ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_CONFIG,
640ea4ebcbaSkettenis 	    PM2_CONFIG_FB_WRITE_EN | PM2_CONFIG_FB_READ_SRC_EN);
641ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_FB_SRC_DELTA,
64246ed5d68Smiod 	    PM2_COORDS((sx - dx) & 0xffff, (sy - dy) & 0xffff));
643ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_ORIG,
644ea4ebcbaSkettenis 	    PM2_COORDS(dx, dy));
645ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_SIZE,
646ea4ebcbaSkettenis 	    PM2_COORDS(w, h));
647ea4ebcbaSkettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RENDER,
648ea4ebcbaSkettenis 	    PM2_RENDER_RECT | dir);
649ea4ebcbaSkettenis 
650ea4ebcbaSkettenis 	gfxp_wait(sc);
651ea4ebcbaSkettenis }
652ea4ebcbaSkettenis 
653ea4ebcbaSkettenis void
gfxp_fillrect(struct gfxp_softc * sc,int x,int y,int w,int h,int color)654ea4ebcbaSkettenis gfxp_fillrect(struct gfxp_softc *sc, int x, int y, int w, int h, int color)
655ea4ebcbaSkettenis {
65610f81fd2Skettenis 	gfxp_wait_fifo(sc, 5);
65710f81fd2Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_CONFIG,
65810f81fd2Skettenis 	    PM2_CONFIG_FB_WRITE_EN);
65910f81fd2Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_ORIG,
66010f81fd2Skettenis 	    PM2_COORDS(x, y));
66110f81fd2Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_SIZE,
66210f81fd2Skettenis 	    PM2_COORDS(w, h));
66310f81fd2Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_FB_BLOCK_COLOR,
66410f81fd2Skettenis 	    color);
66510f81fd2Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RENDER,
66610f81fd2Skettenis 	    PM2_RENDER_RECT | PM2_RENDER_FASTFILL);
66710f81fd2Skettenis 
66810f81fd2Skettenis 	gfxp_wait(sc);
669ea4ebcbaSkettenis }
670