xref: /openbsd-src/sys/arch/sparc64/dev/radeonfb.c (revision 63294167c4eaf171adac4fb2d8cc6d072a13af61)
1*63294167Skettenis /*	$OpenBSD: radeonfb.c,v 1.8 2022/07/15 17:57:26 kettenis Exp $	*/
264543cf9Skettenis 
364543cf9Skettenis /*
464543cf9Skettenis  * Copyright (c) 2009 Mark Kettenis.
564543cf9Skettenis  *
664543cf9Skettenis  * Permission to use, copy, modify, and distribute this software for any
764543cf9Skettenis  * purpose with or without fee is hereby granted, provided that the above
864543cf9Skettenis  * copyright notice and this permission notice appear in all copies.
964543cf9Skettenis  *
1064543cf9Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1164543cf9Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1264543cf9Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1364543cf9Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1464543cf9Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1564543cf9Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1664543cf9Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1764543cf9Skettenis  */
1864543cf9Skettenis 
1964543cf9Skettenis #include <sys/param.h>
2064543cf9Skettenis #include <sys/device.h>
2164543cf9Skettenis #include <sys/pciio.h>
2264543cf9Skettenis #include <sys/systm.h>
2364543cf9Skettenis 
2464543cf9Skettenis #include <machine/autoconf.h>
2564543cf9Skettenis #include <machine/bus.h>
2664543cf9Skettenis #include <machine/openfirm.h>
2764543cf9Skettenis 
2864543cf9Skettenis #include <dev/pci/pcireg.h>
2964543cf9Skettenis #include <dev/pci/pcivar.h>
3064543cf9Skettenis #include <dev/pci/pcidevs.h>
3164543cf9Skettenis 
3264543cf9Skettenis #include <dev/wscons/wsconsio.h>
3364543cf9Skettenis #include <dev/wscons/wsdisplayvar.h>
3464543cf9Skettenis 
3564543cf9Skettenis #include <dev/rasops/rasops.h>
3664543cf9Skettenis 
3764543cf9Skettenis #include <machine/fbvar.h>
3864543cf9Skettenis 
3964543cf9Skettenis #define RADEON_PCI_MEM		0x10
4064543cf9Skettenis #define RADEON_PCI_MMIO		0x18
4164543cf9Skettenis 
4264543cf9Skettenis #define RADEON_PALETTE_INDEX		0x00b0
4364543cf9Skettenis #define RADEON_PALETTE_DATA		0x00b4
4464543cf9Skettenis 
4564543cf9Skettenis #define RADEON_CRTC_OFFSET		0x0224
4664543cf9Skettenis 
4764543cf9Skettenis #define RADEON_SURFACE_CNTL		0x0b00
4864543cf9Skettenis #define  RADEON_NONSURF_AP0_SWP_16BPP	0x00100000
4964543cf9Skettenis #define  RADEON_NONSURF_AP0_SWP_32BPP	0x00200000
5064543cf9Skettenis #define  RADEON_NONSURF_AP1_SWP_16BPP	0x00400000
5164543cf9Skettenis #define  RADEON_NONSURF_AP1_SWP_32BPP	0x00800000
5264543cf9Skettenis 
5364543cf9Skettenis #define RADEON_RBBM_STATUS		0x0e40
5464543cf9Skettenis #define  RADEON_RBBM_FIFOCNT_MASK	0x0000007f
5564543cf9Skettenis #define  RADEON_RBBM_ACTIVE		0x80000000
5664543cf9Skettenis 
5764543cf9Skettenis #define RADEON_SRC_Y_X			0x1434
5864543cf9Skettenis #define RADEON_DST_Y_X			0x1438
5964543cf9Skettenis #define RADEON_DST_HEIGHT_WIDTH		0x143c
6064543cf9Skettenis 
6164543cf9Skettenis #define RADEON_DP_GUI_MASTER_CNTL	0x146c
6264543cf9Skettenis #define  RADEON_GMC_DST_8BPP		0x00000200
6364543cf9Skettenis #define  RADEON_GMC_DST_32BPP		0x00000600
6464543cf9Skettenis #define  RADEON_GMC_BRUSH_NONE		0x000000e0
6564543cf9Skettenis #define  RADEON_GMC_BRUSH_SOLID_COLOR	0x000000d0
6664543cf9Skettenis #define  RADEON_GMC_SRC_DATATYPE_COLOR	0x00003000
6764543cf9Skettenis #define  RADEON_GMC_SRC_SOURCE_MEMORY	0x02000000
6864543cf9Skettenis #define  RADEON_ROP3_S			0x00cc0000
6964543cf9Skettenis #define  RADEON_ROP3_P			0x00f00000
7064543cf9Skettenis #define  RADEON_GMC_CLR_CMP_CNTL_DIS    0x10000000
7164543cf9Skettenis 
7264543cf9Skettenis #define RADEON_DP_BRUSH_BKGD_CLR	0x1478
7364543cf9Skettenis #define RADEON_DP_BRUSH_FRGD_CLR	0x147c
7464543cf9Skettenis 
7564543cf9Skettenis #define RADEON_DP_CNTL			0x16c0
7664543cf9Skettenis #define  RADEON_DST_X_LEFT_TO_RIGHT	0x00000001
7764543cf9Skettenis #define  RADEON_DST_Y_TOP_TO_BOTTOM	0x00000002
7864543cf9Skettenis #define RADEON_DP_WRITE_MASK		0x16cc
7964543cf9Skettenis 
8064543cf9Skettenis #define RADEON_DEFAULT_PITCH_OFFSET	0x16e0
8164543cf9Skettenis #define RADEON_DEFAULT_SC_BOTTOM_RIGHT	0x16e8
8264543cf9Skettenis 
8364543cf9Skettenis #define RADEON_WAIT_UNTIL		0x1720
8464543cf9Skettenis #define  RADEON_WAIT_2D_IDLECLEAN	0x00010000
8564543cf9Skettenis #define  RADEON_WAIT_3D_IDLECLEAN	0x00020000
8664543cf9Skettenis #define  RADEON_WAIT_HOST_IDLECLEAN	0x00040000
8764543cf9Skettenis 
8864543cf9Skettenis #define RADEON_RB3D_DSTCACHE_CTLSTAT	0x325c
8964543cf9Skettenis #define  RADEON_RB3D_DC_FLUSH_ALL	0x0000000f
9064543cf9Skettenis #define  RADEON_RB3D_DC_BUSY		0x80000000
9164543cf9Skettenis 
9264543cf9Skettenis #define RADEON_COORDS(x, y)	((y << 16) | (x))
9364543cf9Skettenis 
9464543cf9Skettenis #ifdef APERTURE
9564543cf9Skettenis extern int allowaperture;
9664543cf9Skettenis #endif
9764543cf9Skettenis 
9864543cf9Skettenis struct radeonfb_softc {
9964543cf9Skettenis 	struct sunfb	sc_sunfb;
10064543cf9Skettenis 
10164543cf9Skettenis 	bus_space_tag_t sc_memt;
10264543cf9Skettenis 	bus_space_handle_t sc_memh;
10364543cf9Skettenis 	bus_addr_t	sc_membase;
10464543cf9Skettenis 	bus_size_t	sc_memsize;
10564543cf9Skettenis 	bus_size_t	sc_memoff;
10664543cf9Skettenis 
10764543cf9Skettenis 	bus_space_tag_t	sc_mmiot;
10864543cf9Skettenis 	bus_space_handle_t sc_mmioh;
10964543cf9Skettenis 	bus_addr_t	sc_mmiobase;
11064543cf9Skettenis 	bus_size_t	sc_mmiosize;
11164543cf9Skettenis 
11264543cf9Skettenis 	pcitag_t	sc_pcitag;
11364543cf9Skettenis 
11464543cf9Skettenis 	int		sc_mode;
11564543cf9Skettenis 	u_int8_t	sc_cmap_red[256];
11664543cf9Skettenis 	u_int8_t	sc_cmap_green[256];
11764543cf9Skettenis 	u_int8_t	sc_cmap_blue[256];
11864543cf9Skettenis };
11964543cf9Skettenis 
12064543cf9Skettenis int	radeonfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
12164543cf9Skettenis paddr_t	radeonfb_mmap(void *, off_t, int);
12264543cf9Skettenis 
12364543cf9Skettenis struct wsdisplay_accessops radeonfb_accessops = {
12487eec248Smiod 	.ioctl = radeonfb_ioctl,
12587eec248Smiod 	.mmap = radeonfb_mmap
12664543cf9Skettenis };
12764543cf9Skettenis 
12864543cf9Skettenis int	radeonfb_match(struct device *, void *, void *);
12964543cf9Skettenis void	radeonfb_attach(struct device *, struct device *, void *);
13064543cf9Skettenis 
131eb7eaf8dSmpi const struct cfattach radeonfb_ca = {
13264543cf9Skettenis 	sizeof(struct radeonfb_softc), radeonfb_match, radeonfb_attach
13364543cf9Skettenis };
13464543cf9Skettenis 
13564543cf9Skettenis struct cfdriver radeonfb_cd = {
13664543cf9Skettenis 	NULL, "radeonfb", DV_DULL
13764543cf9Skettenis };
13864543cf9Skettenis 
13964543cf9Skettenis int	radeonfb_is_console(int);
14064543cf9Skettenis int	radeonfb_getcmap(struct radeonfb_softc *, struct wsdisplay_cmap *);
14164543cf9Skettenis int	radeonfb_putcmap(struct radeonfb_softc *, struct wsdisplay_cmap *);
14264543cf9Skettenis void	radeonfb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
14364543cf9Skettenis 
144072953e3Smiod int	radeonfb_copycols(void *, int, int, int, int);
145e0c3e559Sjsg int	radeonfb_erasecols(void *, int, int, int, uint32_t);
146072953e3Smiod int	radeonfb_copyrows(void *, int, int, int);
147e0c3e559Sjsg int	radeonfb_eraserows(void *, int, int, uint32_t);
14864543cf9Skettenis 
1493f5212b6Skettenis void	radeonfb_init(struct radeonfb_softc *);
15064543cf9Skettenis void	radeonfb_wait_fifo(struct radeonfb_softc *, int);
15164543cf9Skettenis void	radeonfb_wait(struct radeonfb_softc *);
15264543cf9Skettenis void	radeonfb_copyrect(struct radeonfb_softc *, int, int, int, int, int, int);
15364543cf9Skettenis void	radeonfb_fillrect(struct radeonfb_softc *, int, int, int, int, int);
15464543cf9Skettenis 
15564543cf9Skettenis int
radeonfb_match(struct device * parent,void * cf,void * aux)15664543cf9Skettenis radeonfb_match(struct device *parent, void *cf, void *aux)
15764543cf9Skettenis {
15864543cf9Skettenis 	struct pci_attach_args *pa = aux;
15964543cf9Skettenis 	char buf[32];
16064543cf9Skettenis 	int node;
16164543cf9Skettenis 
16264543cf9Skettenis 	node = PCITAG_NODE(pa->pa_tag);
16364543cf9Skettenis 	OF_getprop(node, "name", buf, sizeof(buf));
16486c0bb38Skettenis 	if (strcmp(buf, "SUNW,XVR-100") == 0 ||
16586c0bb38Skettenis 	    strcmp(buf, "SUNW,XVR-300") == 0)
16664543cf9Skettenis 		return (10);
16764543cf9Skettenis 
16864543cf9Skettenis 	return (0);
16964543cf9Skettenis }
17064543cf9Skettenis 
17164543cf9Skettenis void
radeonfb_attach(struct device * parent,struct device * self,void * aux)17264543cf9Skettenis radeonfb_attach(struct device *parent, struct device *self, void *aux)
17364543cf9Skettenis {
17464543cf9Skettenis 	struct radeonfb_softc *sc = (struct radeonfb_softc *)self;
17564543cf9Skettenis 	struct pci_attach_args *pa = aux;
17664543cf9Skettenis 	struct rasops_info *ri;
17764543cf9Skettenis 	int node, console, flags;
17864543cf9Skettenis 	char *model;
17964543cf9Skettenis 
18064543cf9Skettenis 	sc->sc_pcitag = pa->pa_tag;
18164543cf9Skettenis 
18264543cf9Skettenis 	node = PCITAG_NODE(pa->pa_tag);
18364543cf9Skettenis 	console = radeonfb_is_console(node);
18464543cf9Skettenis 
18564543cf9Skettenis 	printf("\n");
18664543cf9Skettenis 
18764543cf9Skettenis 	model = getpropstring(node, "model");
18864543cf9Skettenis 	printf("%s: %s", self->dv_xname, model);
18964543cf9Skettenis 
19064543cf9Skettenis 	if (pci_mapreg_map(pa, RADEON_PCI_MEM, PCI_MAPREG_TYPE_MEM,
19164543cf9Skettenis 	    BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
19264543cf9Skettenis 	    &sc->sc_membase, &sc->sc_memsize, 0)) {
19364543cf9Skettenis 		printf("\n%s: can't map video memory\n", self->dv_xname);
19464543cf9Skettenis 		return;
19564543cf9Skettenis 	}
19664543cf9Skettenis 
19764543cf9Skettenis 	if (pci_mapreg_map(pa, RADEON_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
19864543cf9Skettenis 	    &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase,
19964543cf9Skettenis 	    &sc->sc_mmiosize, 0)) {
20064543cf9Skettenis 		printf("\n%s: can't map registers\n", self->dv_xname);
20164543cf9Skettenis 		return;
20264543cf9Skettenis 	}
20364543cf9Skettenis 
20464543cf9Skettenis 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
20564543cf9Skettenis 
20664543cf9Skettenis 	printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
20764543cf9Skettenis 
20864543cf9Skettenis 	/*
20964543cf9Skettenis 	 * The firmware sets up the framebuffer such that at starts at
21064543cf9Skettenis 	 * an offset from the start of video memory.
21164543cf9Skettenis 	 */
21264543cf9Skettenis 	sc->sc_memoff =
21364543cf9Skettenis 	    bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_CRTC_OFFSET);
21464543cf9Skettenis 
21564543cf9Skettenis 	ri = &sc->sc_sunfb.sf_ro;
21664543cf9Skettenis 	ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh);
21764543cf9Skettenis 	ri->ri_bits += sc->sc_memoff;
21864543cf9Skettenis 	ri->ri_hw = sc;
21964543cf9Skettenis 
22064543cf9Skettenis 	if (sc->sc_sunfb.sf_depth == 32)
22164543cf9Skettenis 		flags = 0;
22264543cf9Skettenis 	else
22364543cf9Skettenis 		flags = RI_BSWAP;
22464543cf9Skettenis 
22564543cf9Skettenis 	fbwscons_init(&sc->sc_sunfb, flags, console);
22664543cf9Skettenis 	fbwscons_setcolormap(&sc->sc_sunfb, radeonfb_setcolor);
22764543cf9Skettenis 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
22864543cf9Skettenis 
2293f5212b6Skettenis 	radeonfb_init(sc);
23064543cf9Skettenis 	ri->ri_ops.copyrows = radeonfb_copyrows;
23164543cf9Skettenis 	ri->ri_ops.copycols = radeonfb_copycols;
23264543cf9Skettenis 	ri->ri_ops.eraserows = radeonfb_eraserows;
23364543cf9Skettenis 	ri->ri_ops.erasecols = radeonfb_erasecols;
23464543cf9Skettenis 
23564543cf9Skettenis 	if (console)
23664543cf9Skettenis 		fbwscons_console_init(&sc->sc_sunfb, -1);
23764543cf9Skettenis 	fbwscons_attach(&sc->sc_sunfb, &radeonfb_accessops, console);
23864543cf9Skettenis }
23964543cf9Skettenis 
24064543cf9Skettenis int
radeonfb_ioctl(void * v,u_long cmd,caddr_t data,int flags,struct proc * p)24164543cf9Skettenis radeonfb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
24264543cf9Skettenis {
24364543cf9Skettenis 	struct radeonfb_softc *sc = v;
24464543cf9Skettenis 	struct wsdisplay_fbinfo *wdf;
24564543cf9Skettenis 	struct pcisel *sel;
24664543cf9Skettenis 
24764543cf9Skettenis 	switch (cmd) {
24864543cf9Skettenis 	case WSDISPLAYIO_GTYPE:
24964543cf9Skettenis 		*(u_int *)data = WSDISPLAY_TYPE_RADEONFB;
25064543cf9Skettenis 		break;
25164543cf9Skettenis 	case WSDISPLAYIO_SMODE:
25264543cf9Skettenis 		sc->sc_mode = *(u_int *)data;
25364543cf9Skettenis 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
25464543cf9Skettenis 			struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
25564543cf9Skettenis 
25664543cf9Skettenis 			/* Restore colormap. */
25764543cf9Skettenis 			fbwscons_setcolormap(&sc->sc_sunfb, radeonfb_setcolor);
25864543cf9Skettenis 
25964543cf9Skettenis 			/* Clear screen. */
2603f5212b6Skettenis 			radeonfb_init(sc);
26164543cf9Skettenis 			radeonfb_fillrect(sc, 0, 0, ri->ri_width,
26264543cf9Skettenis 			    ri->ri_height, ri->ri_devcmap[WSCOL_WHITE]);
26364543cf9Skettenis 		}
26464543cf9Skettenis 		break;
26564543cf9Skettenis 
26664543cf9Skettenis 	case WSDISPLAYIO_GINFO:
26764543cf9Skettenis 		wdf = (void *)data;
26864543cf9Skettenis 		wdf->height = sc->sc_sunfb.sf_height;
26964543cf9Skettenis 		wdf->width  = sc->sc_sunfb.sf_width;
27064543cf9Skettenis 		wdf->depth  = sc->sc_sunfb.sf_depth;
271*63294167Skettenis 		wdf->stride = sc->sc_sunfb.sf_linebytes;
272*63294167Skettenis 		wdf->offset = 0;
27364543cf9Skettenis 		if (sc->sc_sunfb.sf_depth == 32)
27464543cf9Skettenis 			wdf->cmsize = 0;
27564543cf9Skettenis 		else
27664543cf9Skettenis 			wdf->cmsize = 256;
27764543cf9Skettenis 		break;
27864543cf9Skettenis 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
27964543cf9Skettenis 		if (sc->sc_sunfb.sf_depth == 32)
28064543cf9Skettenis 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
28164543cf9Skettenis 		else
28264543cf9Skettenis 			return (-1);
28364543cf9Skettenis 		break;
28464543cf9Skettenis 	case WSDISPLAYIO_LINEBYTES:
28564543cf9Skettenis 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
28664543cf9Skettenis 		break;
28764543cf9Skettenis 
28864543cf9Skettenis 	case WSDISPLAYIO_GETCMAP:
28964543cf9Skettenis 		return radeonfb_getcmap(sc, (struct wsdisplay_cmap *)data);
29064543cf9Skettenis 	case WSDISPLAYIO_PUTCMAP:
29164543cf9Skettenis 		return radeonfb_putcmap(sc, (struct wsdisplay_cmap *)data);
29264543cf9Skettenis 
29364543cf9Skettenis 	case WSDISPLAYIO_GPCIID:
29464543cf9Skettenis 		sel = (struct pcisel *)data;
29564543cf9Skettenis 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
29664543cf9Skettenis 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
29764543cf9Skettenis 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
29864543cf9Skettenis 		break;
29964543cf9Skettenis 
30064543cf9Skettenis 	case WSDISPLAYIO_SVIDEO:
30164543cf9Skettenis 	case WSDISPLAYIO_GVIDEO:
30264543cf9Skettenis 		break;
30364543cf9Skettenis 
30464543cf9Skettenis 	case WSDISPLAYIO_GCURPOS:
30564543cf9Skettenis 	case WSDISPLAYIO_SCURPOS:
30664543cf9Skettenis 	case WSDISPLAYIO_GCURMAX:
30764543cf9Skettenis 	case WSDISPLAYIO_GCURSOR:
30864543cf9Skettenis 	case WSDISPLAYIO_SCURSOR:
30964543cf9Skettenis 	default:
31064543cf9Skettenis 		return -1; /* not supported yet */
31164543cf9Skettenis         }
31264543cf9Skettenis 
31364543cf9Skettenis 	return (0);
31464543cf9Skettenis }
31564543cf9Skettenis 
31664543cf9Skettenis paddr_t
radeonfb_mmap(void * v,off_t off,int prot)31764543cf9Skettenis radeonfb_mmap(void *v, off_t off, int prot)
31864543cf9Skettenis {
31964543cf9Skettenis 	struct radeonfb_softc *sc = v;
32064543cf9Skettenis 
32164543cf9Skettenis 	if (off & PGOFSET)
32264543cf9Skettenis 		return (-1);
32364543cf9Skettenis 
32464543cf9Skettenis 	switch (sc->sc_mode) {
32564543cf9Skettenis 	case WSDISPLAYIO_MODE_MAPPED:
32664543cf9Skettenis #ifdef APERTURE
32764543cf9Skettenis 		if (allowaperture == 0)
32864543cf9Skettenis 			return (-1);
32964543cf9Skettenis #endif
33064543cf9Skettenis 
33164543cf9Skettenis 		if (sc->sc_mmiosize == 0)
33264543cf9Skettenis 			return (-1);
33364543cf9Skettenis 
33464543cf9Skettenis 		if (off >= sc->sc_membase &&
33564543cf9Skettenis 		    off < (sc->sc_membase + sc->sc_memsize))
33664543cf9Skettenis 			return (bus_space_mmap(sc->sc_memt,
33764543cf9Skettenis 			    sc->sc_membase, off - sc->sc_membase,
33864543cf9Skettenis 			    prot, BUS_SPACE_MAP_LINEAR));
33964543cf9Skettenis 
34064543cf9Skettenis 		if (off >= sc->sc_mmiobase &&
34164543cf9Skettenis 		    off < (sc->sc_mmiobase + sc->sc_mmiosize))
34264543cf9Skettenis 			return (bus_space_mmap(sc->sc_mmiot,
34364543cf9Skettenis 			    sc->sc_mmiobase, off - sc->sc_mmiobase,
34464543cf9Skettenis 			    prot, BUS_SPACE_MAP_LINEAR));
34564543cf9Skettenis 		break;
34664543cf9Skettenis 
34764543cf9Skettenis 	case WSDISPLAYIO_MODE_DUMBFB:
34864543cf9Skettenis 		if ((sc->sc_memoff % PAGE_SIZE) != 0)
34964543cf9Skettenis 			return (-1);
35064543cf9Skettenis 
35164543cf9Skettenis 		if (off >= 0 && off < sc->sc_memsize / 2) {
35264543cf9Skettenis 			bus_addr_t base = sc->sc_membase + sc->sc_memoff;
35364543cf9Skettenis 
35464543cf9Skettenis 			/*
35564543cf9Skettenis 			 * In 32bpp mode, use the second aperture,
35664543cf9Skettenis 			 * which has been set up by the firmware to do
35764543cf9Skettenis 			 * proper byte swapping.
35864543cf9Skettenis 			 */
35964543cf9Skettenis 			if (sc->sc_sunfb.sf_depth == 32)
36064543cf9Skettenis 				base += sc->sc_memsize / 2;
36164543cf9Skettenis 
36264543cf9Skettenis 			return (bus_space_mmap(sc->sc_memt, base, off,
36364543cf9Skettenis 			    prot, BUS_SPACE_MAP_LINEAR));
36464543cf9Skettenis 		}
36564543cf9Skettenis 		break;
36664543cf9Skettenis 	}
36764543cf9Skettenis 
36864543cf9Skettenis 	return (-1);
36964543cf9Skettenis }
37064543cf9Skettenis 
37164543cf9Skettenis int
radeonfb_is_console(int node)37264543cf9Skettenis radeonfb_is_console(int node)
37364543cf9Skettenis {
37464543cf9Skettenis 	extern int fbnode;
37564543cf9Skettenis 
37664543cf9Skettenis 	return (fbnode == node);
37764543cf9Skettenis }
37864543cf9Skettenis 
37964543cf9Skettenis int
radeonfb_getcmap(struct radeonfb_softc * sc,struct wsdisplay_cmap * cm)38064543cf9Skettenis radeonfb_getcmap(struct radeonfb_softc *sc, struct wsdisplay_cmap *cm)
38164543cf9Skettenis {
38264543cf9Skettenis 	u_int index = cm->index;
38364543cf9Skettenis 	u_int count = cm->count;
38464543cf9Skettenis 	int error;
38564543cf9Skettenis 
38664543cf9Skettenis 	if (index >= 256 || count > 256 - index)
38764543cf9Skettenis 		return (EINVAL);
38864543cf9Skettenis 
38964543cf9Skettenis 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
39064543cf9Skettenis 	if (error)
39164543cf9Skettenis 		return (error);
39264543cf9Skettenis 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
39364543cf9Skettenis 	if (error)
39464543cf9Skettenis 		return (error);
39564543cf9Skettenis 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
39664543cf9Skettenis 	if (error)
39764543cf9Skettenis 		return (error);
39864543cf9Skettenis 	return (0);
39964543cf9Skettenis }
40064543cf9Skettenis 
40164543cf9Skettenis int
radeonfb_putcmap(struct radeonfb_softc * sc,struct wsdisplay_cmap * cm)40264543cf9Skettenis radeonfb_putcmap(struct radeonfb_softc *sc, struct wsdisplay_cmap *cm)
40364543cf9Skettenis {
40464543cf9Skettenis 	u_int index = cm->index;
40564543cf9Skettenis 	u_int count = cm->count;
40664543cf9Skettenis 	u_int i;
40764543cf9Skettenis 	int error;
40864543cf9Skettenis 	u_char *r, *g, *b;
40964543cf9Skettenis 
41064543cf9Skettenis 	if (index >= 256 || count > 256 - index)
41164543cf9Skettenis 		return (EINVAL);
41264543cf9Skettenis 
41364543cf9Skettenis 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
41464543cf9Skettenis 		return (error);
41564543cf9Skettenis 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
41664543cf9Skettenis 		return (error);
41764543cf9Skettenis 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
41864543cf9Skettenis 		return (error);
41964543cf9Skettenis 
42064543cf9Skettenis 	r = &sc->sc_cmap_red[index];
42164543cf9Skettenis 	g = &sc->sc_cmap_green[index];
42264543cf9Skettenis 	b = &sc->sc_cmap_blue[index];
42364543cf9Skettenis 
42464543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
42564543cf9Skettenis 	    RADEON_PALETTE_INDEX, index);
42664543cf9Skettenis 	for (i = 0; i < count; i++) {
42764543cf9Skettenis 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
42864543cf9Skettenis 		    RADEON_PALETTE_DATA, (*r << 16) | (*g << 8) | *b);
42964543cf9Skettenis 		r++, g++, b++;
43064543cf9Skettenis 	}
43164543cf9Skettenis 	return (0);
43264543cf9Skettenis }
43364543cf9Skettenis 
43464543cf9Skettenis void
radeonfb_setcolor(void * v,u_int index,u_int8_t r,u_int8_t g,u_int8_t b)43564543cf9Skettenis radeonfb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
43664543cf9Skettenis {
43764543cf9Skettenis 	struct radeonfb_softc *sc = v;
43864543cf9Skettenis 
43964543cf9Skettenis 	sc->sc_cmap_red[index] = r;
44064543cf9Skettenis 	sc->sc_cmap_green[index] = g;
44164543cf9Skettenis 	sc->sc_cmap_blue[index] = b;
44264543cf9Skettenis 
44364543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
44464543cf9Skettenis 	    RADEON_PALETTE_INDEX, index);
44564543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
44664543cf9Skettenis 	    RADEON_PALETTE_DATA, (r << 16) | (g << 8) | b);
44764543cf9Skettenis }
44864543cf9Skettenis 
44964543cf9Skettenis /*
45064543cf9Skettenis  * Accelerated routines.
45164543cf9Skettenis  */
45264543cf9Skettenis 
453072953e3Smiod int
radeonfb_copycols(void * cookie,int row,int src,int dst,int num)45464543cf9Skettenis radeonfb_copycols(void *cookie, int row, int src, int dst, int num)
45564543cf9Skettenis {
45664543cf9Skettenis 	struct rasops_info *ri = cookie;
45764543cf9Skettenis 	struct radeonfb_softc *sc = ri->ri_hw;
45864543cf9Skettenis 
45964543cf9Skettenis 	num *= ri->ri_font->fontwidth;
46064543cf9Skettenis 	src *= ri->ri_font->fontwidth;
46164543cf9Skettenis 	dst *= ri->ri_font->fontwidth;
46264543cf9Skettenis 	row *= ri->ri_font->fontheight;
46364543cf9Skettenis 
46464543cf9Skettenis 	radeonfb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
46564543cf9Skettenis 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
46664543cf9Skettenis 	    num, ri->ri_font->fontheight);
467072953e3Smiod 
468072953e3Smiod 	return 0;
46964543cf9Skettenis }
47064543cf9Skettenis 
471072953e3Smiod int
radeonfb_erasecols(void * cookie,int row,int col,int num,uint32_t attr)472e0c3e559Sjsg radeonfb_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
47364543cf9Skettenis {
47464543cf9Skettenis 	struct rasops_info *ri = cookie;
47564543cf9Skettenis 	struct radeonfb_softc *sc = ri->ri_hw;
47664543cf9Skettenis 	int bg, fg;
47764543cf9Skettenis 
47864543cf9Skettenis 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
47964543cf9Skettenis 
48064543cf9Skettenis 	row *= ri->ri_font->fontheight;
48164543cf9Skettenis 	col *= ri->ri_font->fontwidth;
48264543cf9Skettenis 	num *= ri->ri_font->fontwidth;
48364543cf9Skettenis 
48464543cf9Skettenis 	radeonfb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
48564543cf9Skettenis 	    num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
486072953e3Smiod 
487072953e3Smiod 	return 0;
48864543cf9Skettenis }
48964543cf9Skettenis 
490072953e3Smiod int
radeonfb_copyrows(void * cookie,int src,int dst,int num)49164543cf9Skettenis radeonfb_copyrows(void *cookie, int src, int dst, int num)
49264543cf9Skettenis {
49364543cf9Skettenis 	struct rasops_info *ri = cookie;
49464543cf9Skettenis 	struct radeonfb_softc *sc = ri->ri_hw;
49564543cf9Skettenis 
49664543cf9Skettenis 	num *= ri->ri_font->fontheight;
49764543cf9Skettenis 	src *= ri->ri_font->fontheight;
49864543cf9Skettenis 	dst *= ri->ri_font->fontheight;
49964543cf9Skettenis 
50064543cf9Skettenis 	radeonfb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
50164543cf9Skettenis 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
502072953e3Smiod 
503072953e3Smiod 	return 0;
50464543cf9Skettenis }
50564543cf9Skettenis 
506072953e3Smiod int
radeonfb_eraserows(void * cookie,int row,int num,uint32_t attr)507e0c3e559Sjsg radeonfb_eraserows(void *cookie, int row, int num, uint32_t attr)
50864543cf9Skettenis {
50964543cf9Skettenis 	struct rasops_info *ri = cookie;
51064543cf9Skettenis 	struct radeonfb_softc *sc = ri->ri_hw;
51164543cf9Skettenis 	int bg, fg;
51264543cf9Skettenis 	int x, y, w;
51364543cf9Skettenis 
51464543cf9Skettenis 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
51564543cf9Skettenis 
51664543cf9Skettenis 	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
51764543cf9Skettenis 		num = ri->ri_height;
51864543cf9Skettenis 		x = y = 0;
51964543cf9Skettenis 		w = ri->ri_width;
52064543cf9Skettenis 	} else {
52164543cf9Skettenis 		num *= ri->ri_font->fontheight;
52264543cf9Skettenis 		x = ri->ri_xorigin;
52364543cf9Skettenis 		y = ri->ri_yorigin + row * ri->ri_font->fontheight;
52464543cf9Skettenis 		w = ri->ri_emuwidth;
52564543cf9Skettenis 	}
52664543cf9Skettenis 	radeonfb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
527072953e3Smiod 
528072953e3Smiod 	return 0;
52964543cf9Skettenis }
53064543cf9Skettenis 
53164543cf9Skettenis void
radeonfb_init(struct radeonfb_softc * sc)5323f5212b6Skettenis radeonfb_init(struct radeonfb_softc *sc)
5333f5212b6Skettenis {
5343f5212b6Skettenis 	radeonfb_wait_fifo(sc, 2);
5353f5212b6Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
5363f5212b6Skettenis 	    RADEON_DEFAULT_PITCH_OFFSET,
5373f5212b6Skettenis 	    ((sc->sc_sunfb.sf_linebytes >> 6) << 22) | (sc->sc_memoff >> 10));
5383f5212b6Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
5393f5212b6Skettenis 	    RADEON_DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff);
5403f5212b6Skettenis }
5413f5212b6Skettenis 
5423f5212b6Skettenis void
radeonfb_wait_fifo(struct radeonfb_softc * sc,int n)54364543cf9Skettenis radeonfb_wait_fifo(struct radeonfb_softc *sc, int n)
54464543cf9Skettenis {
54564543cf9Skettenis 	int i;
54664543cf9Skettenis 
54764543cf9Skettenis 	for (i = 1000000; i != 0; i--) {
54864543cf9Skettenis 		if ((bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
54964543cf9Skettenis 		    RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK) >= n)
55064543cf9Skettenis 			break;
55164543cf9Skettenis 		DELAY(1);
55264543cf9Skettenis 	}
55364543cf9Skettenis }
55464543cf9Skettenis 
55564543cf9Skettenis void
radeonfb_wait(struct radeonfb_softc * sc)55664543cf9Skettenis radeonfb_wait(struct radeonfb_softc *sc)
55764543cf9Skettenis {
55864543cf9Skettenis 	int i;
55964543cf9Skettenis 
56064543cf9Skettenis 	radeonfb_wait_fifo(sc, 64);
56164543cf9Skettenis 
56264543cf9Skettenis 	for (i = 1000000; i != 0; i--) {
56364543cf9Skettenis 		if ((bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
56464543cf9Skettenis 		    RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) == 0)
56564543cf9Skettenis 			break;
56664543cf9Skettenis 		DELAY(1);
56764543cf9Skettenis 	}
56864543cf9Skettenis 
56964543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
57064543cf9Skettenis 	    RADEON_RB3D_DSTCACHE_CTLSTAT, RADEON_RB3D_DC_FLUSH_ALL);
57164543cf9Skettenis 
57264543cf9Skettenis 	for (i = 1000000; i != 0; i--) {
57364543cf9Skettenis 		if ((bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
57464543cf9Skettenis 		    RADEON_RB3D_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY) == 0)
57564543cf9Skettenis 			break;
57664543cf9Skettenis 		DELAY(1);
57764543cf9Skettenis 	}
57864543cf9Skettenis }
57964543cf9Skettenis 
58064543cf9Skettenis void
radeonfb_copyrect(struct radeonfb_softc * sc,int sx,int sy,int dx,int dy,int w,int h)58164543cf9Skettenis radeonfb_copyrect(struct radeonfb_softc *sc, int sx, int sy, int dx, int dy,
58264543cf9Skettenis     int w, int h)
58364543cf9Skettenis {
58464543cf9Skettenis 	uint32_t gmc;
58564543cf9Skettenis 	uint32_t dir;
58664543cf9Skettenis 
58764543cf9Skettenis 	radeonfb_wait_fifo(sc, 1);
58864543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_WAIT_UNTIL,
58964543cf9Skettenis 	    RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN);
59064543cf9Skettenis 
59164543cf9Skettenis 	if (dy < sy) {
59264543cf9Skettenis 		dir = RADEON_DST_Y_TOP_TO_BOTTOM;
59364543cf9Skettenis 	} else {
59464543cf9Skettenis 		sy += h - 1;
59564543cf9Skettenis 		dy += h - 1;
59664543cf9Skettenis 		dir = 0;
59764543cf9Skettenis 	}
59864543cf9Skettenis 	if (dx < sx) {
59964543cf9Skettenis 		dir |= RADEON_DST_X_LEFT_TO_RIGHT;
60064543cf9Skettenis 	} else {
60164543cf9Skettenis 		sx += w - 1;
60264543cf9Skettenis 		dx += w - 1;
60364543cf9Skettenis 	}
60464543cf9Skettenis 
60564543cf9Skettenis 	radeonfb_wait_fifo(sc, 6);
60664543cf9Skettenis 
60764543cf9Skettenis 	if (sc->sc_sunfb.sf_depth == 32)
60864543cf9Skettenis 		gmc = RADEON_GMC_DST_32BPP;
60964543cf9Skettenis 	else
61064543cf9Skettenis 		gmc = RADEON_GMC_DST_8BPP;
61164543cf9Skettenis 	gmc |= RADEON_GMC_BRUSH_NONE;
61264543cf9Skettenis 	gmc |= RADEON_GMC_SRC_DATATYPE_COLOR;
61364543cf9Skettenis 	gmc |= RADEON_GMC_SRC_SOURCE_MEMORY;
61464543cf9Skettenis 	gmc |= RADEON_ROP3_S;
61564543cf9Skettenis 	gmc |= RADEON_GMC_CLR_CMP_CNTL_DIS;
61664543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
61764543cf9Skettenis 	    RADEON_DP_GUI_MASTER_CNTL, gmc);
61864543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
61964543cf9Skettenis 	    RADEON_DP_WRITE_MASK, 0xffffffff);
62064543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
62164543cf9Skettenis 	    RADEON_DP_CNTL, dir);
62264543cf9Skettenis 
62364543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
62464543cf9Skettenis 	    RADEON_SRC_Y_X, RADEON_COORDS(sx, sy));
62564543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
62664543cf9Skettenis 	    RADEON_DST_Y_X, RADEON_COORDS(dx, dy));
62764543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
62864543cf9Skettenis 	    RADEON_DST_HEIGHT_WIDTH, RADEON_COORDS(w, h));
62964543cf9Skettenis 
63064543cf9Skettenis 	radeonfb_wait(sc);
63164543cf9Skettenis }
63264543cf9Skettenis 
63364543cf9Skettenis void
radeonfb_fillrect(struct radeonfb_softc * sc,int x,int y,int w,int h,int color)63464543cf9Skettenis radeonfb_fillrect(struct radeonfb_softc *sc, int x, int y, int w, int h,
63564543cf9Skettenis     int color)
63664543cf9Skettenis {
63764543cf9Skettenis 	uint32_t gmc;
63864543cf9Skettenis 
63964543cf9Skettenis 	radeonfb_wait_fifo(sc, 1);
64064543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_WAIT_UNTIL,
64164543cf9Skettenis 	    RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN);
64264543cf9Skettenis 
64364543cf9Skettenis 	radeonfb_wait_fifo(sc, 6);
64464543cf9Skettenis 
64564543cf9Skettenis 	if (sc->sc_sunfb.sf_depth == 32)
64664543cf9Skettenis 		gmc = RADEON_GMC_DST_32BPP;
64764543cf9Skettenis 	else
64864543cf9Skettenis 		gmc = RADEON_GMC_DST_8BPP;
64964543cf9Skettenis 	gmc |= RADEON_GMC_BRUSH_SOLID_COLOR;
65064543cf9Skettenis 	gmc |= RADEON_GMC_SRC_DATATYPE_COLOR;
65164543cf9Skettenis 	gmc |= RADEON_ROP3_P;
65264543cf9Skettenis 	gmc |= RADEON_GMC_CLR_CMP_CNTL_DIS;
65364543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
65464543cf9Skettenis 	    RADEON_DP_GUI_MASTER_CNTL, gmc);
65564543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
65664543cf9Skettenis 	    RADEON_DP_BRUSH_FRGD_CLR, color);
65764543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
65864543cf9Skettenis 	    RADEON_DP_WRITE_MASK, 0xffffffff);
65964543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_DP_CNTL,
66064543cf9Skettenis 	    RADEON_DST_Y_TOP_TO_BOTTOM | RADEON_DST_X_LEFT_TO_RIGHT);
66164543cf9Skettenis 
66264543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
66364543cf9Skettenis 	    RADEON_DST_Y_X, RADEON_COORDS(x, y));
66464543cf9Skettenis 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
66564543cf9Skettenis 	    RADEON_DST_HEIGHT_WIDTH, RADEON_COORDS(w, h));
66664543cf9Skettenis 
66764543cf9Skettenis         radeonfb_wait(sc);
66864543cf9Skettenis }
669