diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-07-05 17:13:26 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-07-05 17:13:26 +0000 |
commit | 43f135881c40fa6943497a30e9cabadf1bfc3bb4 (patch) | |
tree | 5ca3dbcc4873b460a7995edbef4f82e0bfc6f41b | |
parent | 8d9366c7243ef541871aa5ebc659b5a1ec80af2e (diff) |
radeonfb(4), an accelerated framebuffer for Sun XVR-100 boards (which have an
ATI Radeon 7000 chip on them). While there, make gfxp(4) depend on rasops32
just in case somebody removes other framebuffers that pull this in from their
kernel config.
ok deraadt@, miod@
-rw-r--r-- | share/man/man4/man4.sparc64/Makefile | 4 | ||||
-rw-r--r-- | share/man/man4/man4.sparc64/radeonfb.4 | 44 | ||||
-rw-r--r-- | sys/arch/sparc64/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/sparc64/conf/RAMDISK | 4 | ||||
-rw-r--r-- | sys/arch/sparc64/conf/files.sparc64 | 8 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/radeonfb.c | 662 |
6 files changed, 720 insertions, 6 deletions
diff --git a/share/man/man4/man4.sparc64/Makefile b/share/man/man4/man4.sparc64/Makefile index e653d68bc62..14661e92fc2 100644 --- a/share/man/man4/man4.sparc64/Makefile +++ b/share/man/man4/man4.sparc64/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.75 2009/06/04 00:31:10 kettenis Exp $ +# $OpenBSD: Makefile,v 1.76 2009/07/05 17:13:25 kettenis Exp $ MAN= agten.4 apio.4 asio.4 audioce.4 audiocs.4 autoconf.4 auxio.4 \ bbc.4 be.4 beeper.4 bpp.4 bwtwo.4 cbus.4 central.4 cgsix.4 cgthree.4 \ @@ -6,7 +6,7 @@ MAN= agten.4 apio.4 asio.4 audioce.4 audiocs.4 autoconf.4 auxio.4 \ ebus.4 ecadc.4 environ.4 esp.4 fhc.4 gfxp.4 ifb.4 intro.4 le.4 led.4 \ machfb.4 magma.4 mem.4 mgx.4 openprom.4 \ pcons.4 pmc.4 power.4 ppm.4 prtc.4 psycho.4 pyro.4 qe.4 qec.4 \ - raptor.4 rfx.4 \ + radeonfb.4 raptor.4 rfx.4 \ sab.4 sbbc.4 schizo.4 spif.4 ssm.4 \ tda.4 timer.4 tvtwo.4 upa.4 uperf.4 \ vbus.4 vcc.4 vcons.4 vdsk.4 vigra.4 vnet.4 vpci.4 vrng.4 vrtc.4 \ diff --git a/share/man/man4/man4.sparc64/radeonfb.4 b/share/man/man4/man4.sparc64/radeonfb.4 new file mode 100644 index 00000000000..d8dd3c44044 --- /dev/null +++ b/share/man/man4/man4.sparc64/radeonfb.4 @@ -0,0 +1,44 @@ +.\" $OpenBSD: radeonfb.4,v 1.1 2009/07/05 17:13:25 kettenis Exp $ +.\" +.\" Copyright (c) 2009 Mark Kettenis. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 5 2009 $ +.Dt RADEONFB 4 sparc64 +.Os +.Sh NAME +.Nm radeonfb +.Nd accelerated color frame buffer +.Sh SYNOPSIS +.Cd "radeonfb* at pci?" +.Cd "wsdisplay* at radeonfb?" +.Sh DESCRIPTION +The +.Nm +driver supports Sun PCI frame buffer cards based on the +ATI +.Sq Radeon +chips, such as the +Sun +XVR-100 +boards. +It does not provide direct device driver entry points +but makes its functions available via the internal +.Xr wsdisplay 4 +interface. +.Sh SEE ALSO +.Xr intro 4 , +.Xr pci 4 , +.Xr wscons 4 , +.Xr wsdisplay 4 diff --git a/sys/arch/sparc64/conf/GENERIC b/sys/arch/sparc64/conf/GENERIC index 3c9b6cecc21..cb9c6e7c784 100644 --- a/sys/arch/sparc64/conf/GENERIC +++ b/sys/arch/sparc64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.240 2009/06/24 11:38:40 deraadt Exp $ +# $OpenBSD: GENERIC,v 1.241 2009/07/05 17:13:25 kettenis Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -485,6 +485,8 @@ machfb* at pci? # PGX/PGX64 framebuffers wsdisplay* at machfb? mgx* at sbus? # SMS MGX/MGXPlus framebuffer wsdisplay* at mgx? +radeonfb* at pci? # XVR-100 framebuffer +wsdisplay* at radeonfb? raptor* at pci? # Raptor framebuffer wsdisplay* at raptor? rfx* at sbus? # RasterFlex framebuffer series diff --git a/sys/arch/sparc64/conf/RAMDISK b/sys/arch/sparc64/conf/RAMDISK index 9b1d246b212..b6c9eb05e89 100644 --- a/sys/arch/sparc64/conf/RAMDISK +++ b/sys/arch/sparc64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.92 2009/06/24 15:02:18 todd Exp $ +# $OpenBSD: RAMDISK,v 1.93 2009/07/05 17:13:25 kettenis Exp $ # Machine architecture; required by config(8) machine sparc64 @@ -293,6 +293,8 @@ machfb* at pci? # PGX/PGX64 framebuffers wsdisplay* at machfb? mgx* at sbus? # SMS MGX/MGXPlus framebuffer wsdisplay* at mgx? +radeonfb* at pci? # XVR-100 framebuffer +wsdisplay* at radeonfb? raptor* at pci? # Raptor framebuffer wsdisplay* at raptor? rfx* at sbus? # RasterFlex framebuffer series diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64 index f70f55631e1..ac70dfdf778 100644 --- a/sys/arch/sparc64/conf/files.sparc64 +++ b/sys/arch/sparc64/conf/files.sparc64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.sparc64,v 1.125 2009/06/03 23:45:15 kettenis Exp $ +# $OpenBSD: files.sparc64,v 1.126 2009/07/05 17:13:25 kettenis Exp $ # $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $ # maxpartitions must be first item in files.${ARCH} @@ -140,6 +140,10 @@ device machfb: wsemuldisplaydev, rasops_bswap, rasops8 attach machfb at pci file arch/sparc64/dev/machfb.c machfb +device radeonfb: wsemuldisplaydev, rasops_bswap, rasops8, rasops32 +attach radeonfb at pci +file arch/sparc64/dev/radeonfb.c radeonfb + device ifb: ifb_ident, wsemuldisplaydev, rasops_bswap, rasops8 attach ifb at pci file arch/sparc64/dev/ifb.c ifb @@ -148,7 +152,7 @@ device raptor: wsemuldisplaydev, rasops_bswap, rasops8 attach raptor at pci file arch/sparc64/dev/raptor.c raptor -device gfxp: wsemuldisplaydev, rasops_bswap, rasops8 +device gfxp: wsemuldisplaydev, rasops_bswap, rasops8, rasops32 attach gfxp at pci file arch/sparc64/dev/gfxp.c gfxp diff --git a/sys/arch/sparc64/dev/radeonfb.c b/sys/arch/sparc64/dev/radeonfb.c new file mode 100644 index 00000000000..94056d17117 --- /dev/null +++ b/sys/arch/sparc64/dev/radeonfb.c @@ -0,0 +1,662 @@ +/* $OpenBSD: radeonfb.c,v 1.1 2009/07/05 17:13:25 kettenis Exp $ */ + +/* + * Copyright (c) 2009 Mark Kettenis. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/pciio.h> +#include <sys/systm.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/openfirm.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> + +#include <dev/rasops/rasops.h> + +#include <machine/fbvar.h> + +#define RADEON_PCI_MEM 0x10 +#define RADEON_PCI_MMIO 0x18 + +#define RADEON_PALETTE_INDEX 0x00b0 +#define RADEON_PALETTE_DATA 0x00b4 + +#define RADEON_CRTC_OFFSET 0x0224 + +#define RADEON_SURFACE_CNTL 0x0b00 +#define RADEON_NONSURF_AP0_SWP_16BPP 0x00100000 +#define RADEON_NONSURF_AP0_SWP_32BPP 0x00200000 +#define RADEON_NONSURF_AP1_SWP_16BPP 0x00400000 +#define RADEON_NONSURF_AP1_SWP_32BPP 0x00800000 + +#define RADEON_RBBM_STATUS 0x0e40 +#define RADEON_RBBM_FIFOCNT_MASK 0x0000007f +#define RADEON_RBBM_ACTIVE 0x80000000 + +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_DST_Y_X 0x1438 +#define RADEON_DST_HEIGHT_WIDTH 0x143c + +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +#define RADEON_GMC_DST_8BPP 0x00000200 +#define RADEON_GMC_DST_32BPP 0x00000600 +#define RADEON_GMC_BRUSH_NONE 0x000000e0 +#define RADEON_GMC_BRUSH_SOLID_COLOR 0x000000d0 +#define RADEON_GMC_SRC_DATATYPE_COLOR 0x00003000 +#define RADEON_GMC_SRC_SOURCE_MEMORY 0x02000000 +#define RADEON_ROP3_S 0x00cc0000 +#define RADEON_ROP3_P 0x00f00000 +#define RADEON_GMC_CLR_CMP_CNTL_DIS 0x10000000 + +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c + +#define RADEON_DP_CNTL 0x16c0 +#define RADEON_DST_X_LEFT_TO_RIGHT 0x00000001 +#define RADEON_DST_Y_TOP_TO_BOTTOM 0x00000002 +#define RADEON_DP_WRITE_MASK 0x16cc + +#define RADEON_DEFAULT_PITCH_OFFSET 0x16e0 +#define RADEON_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 + +#define RADEON_WAIT_UNTIL 0x1720 +#define RADEON_WAIT_2D_IDLECLEAN 0x00010000 +#define RADEON_WAIT_3D_IDLECLEAN 0x00020000 +#define RADEON_WAIT_HOST_IDLECLEAN 0x00040000 + +#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c +#define RADEON_RB3D_DC_FLUSH_ALL 0x0000000f +#define RADEON_RB3D_DC_BUSY 0x80000000 + +#define RADEON_COORDS(x, y) ((y << 16) | (x)) + +#ifdef APERTURE +extern int allowaperture; +#endif + +struct radeonfb_softc { + struct sunfb sc_sunfb; + + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + bus_addr_t sc_membase; + bus_size_t sc_memsize; + bus_size_t sc_memoff; + + bus_space_tag_t sc_mmiot; + bus_space_handle_t sc_mmioh; + bus_addr_t sc_mmiobase; + bus_size_t sc_mmiosize; + + pcitag_t sc_pcitag; + + int sc_mode; + u_int8_t sc_cmap_red[256]; + u_int8_t sc_cmap_green[256]; + u_int8_t sc_cmap_blue[256]; +}; + +int radeonfb_ioctl(void *, u_long, caddr_t, int, struct proc *); +paddr_t radeonfb_mmap(void *, off_t, int); + +struct wsdisplay_accessops radeonfb_accessops = { + radeonfb_ioctl, + radeonfb_mmap, + NULL, /* alloc_screen */ + NULL, /* free_screen */ + NULL, /* show_screen */ + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + NULL, /* burner */ + NULL /* pollc */ +}; + +int radeonfb_match(struct device *, void *, void *); +void radeonfb_attach(struct device *, struct device *, void *); + +struct cfattach radeonfb_ca = { + sizeof(struct radeonfb_softc), radeonfb_match, radeonfb_attach +}; + +struct cfdriver radeonfb_cd = { + NULL, "radeonfb", DV_DULL +}; + +int radeonfb_is_console(int); +int radeonfb_getcmap(struct radeonfb_softc *, struct wsdisplay_cmap *); +int radeonfb_putcmap(struct radeonfb_softc *, struct wsdisplay_cmap *); +void radeonfb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); + +void radeonfb_copycols(void *, int, int, int, int); +void radeonfb_erasecols(void *, int, int, int, long); +void radeonfb_copyrows(void *, int, int, int); +void radeonfb_eraserows(void *, int, int, long); + +void radeonfb_wait_fifo(struct radeonfb_softc *, int); +void radeonfb_wait(struct radeonfb_softc *); +void radeonfb_copyrect(struct radeonfb_softc *, int, int, int, int, int, int); +void radeonfb_fillrect(struct radeonfb_softc *, int, int, int, int, int); + +int +radeonfb_match(struct device *parent, void *cf, void *aux) +{ + struct pci_attach_args *pa = aux; + char buf[32]; + int node; + + node = PCITAG_NODE(pa->pa_tag); + OF_getprop(node, "name", buf, sizeof(buf)); + if (strcmp(buf, "SUNW,XVR-100") == 0) + return (10); + + return (0); +} + +void +radeonfb_attach(struct device *parent, struct device *self, void *aux) +{ + struct radeonfb_softc *sc = (struct radeonfb_softc *)self; + struct pci_attach_args *pa = aux; + struct rasops_info *ri; + int node, console, flags; + char *model; + + sc->sc_pcitag = pa->pa_tag; + + node = PCITAG_NODE(pa->pa_tag); + console = radeonfb_is_console(node); + + printf("\n"); + + model = getpropstring(node, "model"); + printf("%s: %s", self->dv_xname, model); + + if (pci_mapreg_map(pa, RADEON_PCI_MEM, PCI_MAPREG_TYPE_MEM, + BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh, + &sc->sc_membase, &sc->sc_memsize, 0)) { + printf("\n%s: can't map video memory\n", self->dv_xname); + return; + } + + if (pci_mapreg_map(pa, RADEON_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0, + &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase, + &sc->sc_mmiosize, 0)) { + printf("\n%s: can't map registers\n", self->dv_xname); + return; + } + + fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); + + printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); + + /* + * The firmware sets up the framebuffer such that at starts at + * an offset from the start of video memory. + */ + sc->sc_memoff = + bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_CRTC_OFFSET); + + ri = &sc->sc_sunfb.sf_ro; + ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh); + ri->ri_bits += sc->sc_memoff; + ri->ri_hw = sc; + + if (sc->sc_sunfb.sf_depth == 32) + flags = 0; + else + flags = RI_BSWAP; + + fbwscons_init(&sc->sc_sunfb, flags, console); + fbwscons_setcolormap(&sc->sc_sunfb, radeonfb_setcolor); + sc->sc_mode = WSDISPLAYIO_MODE_EMUL; + + /* + * Setup acceleration engine. + */ + radeonfb_wait_fifo(sc, 2); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DEFAULT_PITCH_OFFSET, + ((sc->sc_sunfb.sf_linebytes >> 6) << 22) | (sc->sc_memoff >> 10)); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff); + + ri->ri_ops.copyrows = radeonfb_copyrows; + ri->ri_ops.copycols = radeonfb_copycols; + ri->ri_ops.eraserows = radeonfb_eraserows; + ri->ri_ops.erasecols = radeonfb_erasecols; + + if (console) + fbwscons_console_init(&sc->sc_sunfb, -1); + fbwscons_attach(&sc->sc_sunfb, &radeonfb_accessops, console); +} + +int +radeonfb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) +{ + struct radeonfb_softc *sc = v; + struct wsdisplay_fbinfo *wdf; + struct pcisel *sel; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_RADEONFB; + break; + case WSDISPLAYIO_SMODE: + sc->sc_mode = *(u_int *)data; + if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { + struct rasops_info *ri = &sc->sc_sunfb.sf_ro; + + /* Restore colormap. */ + fbwscons_setcolormap(&sc->sc_sunfb, radeonfb_setcolor); + + /* Clear screen. */ + ri = &sc->sc_sunfb.sf_ro; + radeonfb_fillrect(sc, 0, 0, ri->ri_width, + ri->ri_height, ri->ri_devcmap[WSCOL_WHITE]); + } + break; + + case WSDISPLAYIO_GINFO: + wdf = (void *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + if (sc->sc_sunfb.sf_depth == 32) + wdf->cmsize = 0; + else + wdf->cmsize = 256; + break; + case WSDISPLAYIO_GETSUPPORTEDDEPTH: + if (sc->sc_sunfb.sf_depth == 32) + *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; + else + return (-1); + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; + break; + + case WSDISPLAYIO_GETCMAP: + return radeonfb_getcmap(sc, (struct wsdisplay_cmap *)data); + case WSDISPLAYIO_PUTCMAP: + return radeonfb_putcmap(sc, (struct wsdisplay_cmap *)data); + + case WSDISPLAYIO_GPCIID: + sel = (struct pcisel *)data; + sel->pc_bus = PCITAG_BUS(sc->sc_pcitag); + sel->pc_dev = PCITAG_DEV(sc->sc_pcitag); + sel->pc_func = PCITAG_FUN(sc->sc_pcitag); + break; + + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + break; + + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return -1; /* not supported yet */ + } + + return (0); +} + +paddr_t +radeonfb_mmap(void *v, off_t off, int prot) +{ + struct radeonfb_softc *sc = v; + + if (off & PGOFSET) + return (-1); + + switch (sc->sc_mode) { + case WSDISPLAYIO_MODE_MAPPED: +#ifdef APERTURE + if (allowaperture == 0) + return (-1); +#endif + + if (sc->sc_mmiosize == 0) + return (-1); + + if (off >= sc->sc_membase && + off < (sc->sc_membase + sc->sc_memsize)) + return (bus_space_mmap(sc->sc_memt, + sc->sc_membase, off - sc->sc_membase, + prot, BUS_SPACE_MAP_LINEAR)); + + if (off >= sc->sc_mmiobase && + off < (sc->sc_mmiobase + sc->sc_mmiosize)) + return (bus_space_mmap(sc->sc_mmiot, + sc->sc_mmiobase, off - sc->sc_mmiobase, + prot, BUS_SPACE_MAP_LINEAR)); + break; + + case WSDISPLAYIO_MODE_DUMBFB: + if ((sc->sc_memoff % PAGE_SIZE) != 0) + return (-1); + + if (off >= 0 && off < sc->sc_memsize / 2) { + bus_addr_t base = sc->sc_membase + sc->sc_memoff; + + /* + * In 32bpp mode, use the second aperture, + * which has been set up by the firmware to do + * proper byte swapping. + */ + if (sc->sc_sunfb.sf_depth == 32) + base += sc->sc_memsize / 2; + + return (bus_space_mmap(sc->sc_memt, base, off, + prot, BUS_SPACE_MAP_LINEAR)); + } + break; + } + + return (-1); +} + +int +radeonfb_is_console(int node) +{ + extern int fbnode; + + return (fbnode == node); +} + +int +radeonfb_getcmap(struct radeonfb_softc *sc, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index; + u_int count = cm->count; + int error; + + if (index >= 256 || count > 256 - index) + return (EINVAL); + + error = copyout(&sc->sc_cmap_red[index], cm->red, count); + if (error) + return (error); + error = copyout(&sc->sc_cmap_green[index], cm->green, count); + if (error) + return (error); + error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); + if (error) + return (error); + return (0); +} + +int +radeonfb_putcmap(struct radeonfb_softc *sc, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index; + u_int count = cm->count; + u_int i; + int error; + u_char *r, *g, *b; + + if (index >= 256 || count > 256 - index) + return (EINVAL); + + if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0) + return (error); + if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0) + return (error); + if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0) + return (error); + + r = &sc->sc_cmap_red[index]; + g = &sc->sc_cmap_green[index]; + b = &sc->sc_cmap_blue[index]; + + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_PALETTE_INDEX, index); + for (i = 0; i < count; i++) { + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_PALETTE_DATA, (*r << 16) | (*g << 8) | *b); + r++, g++, b++; + } + return (0); +} + +void +radeonfb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) +{ + struct radeonfb_softc *sc = v; + + sc->sc_cmap_red[index] = r; + sc->sc_cmap_green[index] = g; + sc->sc_cmap_blue[index] = b; + + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_PALETTE_INDEX, index); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_PALETTE_DATA, (r << 16) | (g << 8) | b); +} + +/* + * Accelerated routines. + */ + +void +radeonfb_copycols(void *cookie, int row, int src, int dst, int num) +{ + struct rasops_info *ri = cookie; + struct radeonfb_softc *sc = ri->ri_hw; + + num *= ri->ri_font->fontwidth; + src *= ri->ri_font->fontwidth; + dst *= ri->ri_font->fontwidth; + row *= ri->ri_font->fontheight; + + radeonfb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row, + ri->ri_xorigin + dst, ri->ri_yorigin + row, + num, ri->ri_font->fontheight); +} + +void +radeonfb_erasecols(void *cookie, int row, int col, int num, long attr) +{ + struct rasops_info *ri = cookie; + struct radeonfb_softc *sc = ri->ri_hw; + int bg, fg; + + ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); + + row *= ri->ri_font->fontheight; + col *= ri->ri_font->fontwidth; + num *= ri->ri_font->fontwidth; + + radeonfb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row, + num, ri->ri_font->fontheight, ri->ri_devcmap[bg]); +} + +void +radeonfb_copyrows(void *cookie, int src, int dst, int num) +{ + struct rasops_info *ri = cookie; + struct radeonfb_softc *sc = ri->ri_hw; + + num *= ri->ri_font->fontheight; + src *= ri->ri_font->fontheight; + dst *= ri->ri_font->fontheight; + + radeonfb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src, + ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num); +} + +void +radeonfb_eraserows(void *cookie, int row, int num, long attr) +{ + struct rasops_info *ri = cookie; + struct radeonfb_softc *sc = ri->ri_hw; + int bg, fg; + int x, y, w; + + ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); + + if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) { + num = ri->ri_height; + x = y = 0; + w = ri->ri_width; + } else { + num *= ri->ri_font->fontheight; + x = ri->ri_xorigin; + y = ri->ri_yorigin + row * ri->ri_font->fontheight; + w = ri->ri_emuwidth; + } + radeonfb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]); +} + +void +radeonfb_wait_fifo(struct radeonfb_softc *sc, int n) +{ + int i; + + for (i = 1000000; i != 0; i--) { + if ((bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK) >= n) + break; + DELAY(1); + } +} + +void +radeonfb_wait(struct radeonfb_softc *sc) +{ + int i; + + radeonfb_wait_fifo(sc, 64); + + for (i = 1000000; i != 0; i--) { + if ((bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) == 0) + break; + DELAY(1); + } + + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_RB3D_DSTCACHE_CTLSTAT, RADEON_RB3D_DC_FLUSH_ALL); + + for (i = 1000000; i != 0; i--) { + if ((bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_RB3D_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY) == 0) + break; + DELAY(1); + } +} + +void +radeonfb_copyrect(struct radeonfb_softc *sc, int sx, int sy, int dx, int dy, + int w, int h) +{ + uint32_t gmc; + uint32_t dir; + + radeonfb_wait_fifo(sc, 1); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_WAIT_UNTIL, + RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN); + + if (dy < sy) { + dir = RADEON_DST_Y_TOP_TO_BOTTOM; + } else { + sy += h - 1; + dy += h - 1; + dir = 0; + } + if (dx < sx) { + dir |= RADEON_DST_X_LEFT_TO_RIGHT; + } else { + sx += w - 1; + dx += w - 1; + } + + radeonfb_wait_fifo(sc, 6); + + if (sc->sc_sunfb.sf_depth == 32) + gmc = RADEON_GMC_DST_32BPP; + else + gmc = RADEON_GMC_DST_8BPP; + gmc |= RADEON_GMC_BRUSH_NONE; + gmc |= RADEON_GMC_SRC_DATATYPE_COLOR; + gmc |= RADEON_GMC_SRC_SOURCE_MEMORY; + gmc |= RADEON_ROP3_S; + gmc |= RADEON_GMC_CLR_CMP_CNTL_DIS; + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DP_GUI_MASTER_CNTL, gmc); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DP_WRITE_MASK, 0xffffffff); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DP_CNTL, dir); + + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_SRC_Y_X, RADEON_COORDS(sx, sy)); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DST_Y_X, RADEON_COORDS(dx, dy)); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DST_HEIGHT_WIDTH, RADEON_COORDS(w, h)); + + radeonfb_wait(sc); +} + +void +radeonfb_fillrect(struct radeonfb_softc *sc, int x, int y, int w, int h, + int color) +{ + uint32_t gmc; + + radeonfb_wait_fifo(sc, 1); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_WAIT_UNTIL, + RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN); + + radeonfb_wait_fifo(sc, 6); + + if (sc->sc_sunfb.sf_depth == 32) + gmc = RADEON_GMC_DST_32BPP; + else + gmc = RADEON_GMC_DST_8BPP; + gmc |= RADEON_GMC_BRUSH_SOLID_COLOR; + gmc |= RADEON_GMC_SRC_DATATYPE_COLOR; + gmc |= RADEON_ROP3_P; + gmc |= RADEON_GMC_CLR_CMP_CNTL_DIS; + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DP_GUI_MASTER_CNTL, gmc); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DP_BRUSH_FRGD_CLR, color); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DP_WRITE_MASK, 0xffffffff); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, RADEON_DP_CNTL, + RADEON_DST_Y_TOP_TO_BOTTOM | RADEON_DST_X_LEFT_TO_RIGHT); + + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DST_Y_X, RADEON_COORDS(x, y)); + bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, + RADEON_DST_HEIGHT_WIDTH, RADEON_COORDS(w, h)); + + radeonfb_wait(sc); +} |