summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-11-30 23:32:58 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-11-30 23:32:58 +0000
commitc95187e928a60ab0ba7bb3a5dfd0463ab098d8a5 (patch)
treea6de03a88c8af1eb5ee973ebaa41da941cd2d1f7 /sys/arch/sparc64/dev
parenta85299975aa7ac217ce2b2b66aa26f731942e339 (diff)
Load firmware that is needed for accelerated X on Elite3D boards.
The firmware is loaded from /etc/firmware/afb, which will be provided soon.
Diffstat (limited to 'sys/arch/sparc64/dev')
-rw-r--r--sys/arch/sparc64/dev/creator.c142
-rw-r--r--sys/arch/sparc64/dev/creatorreg.h12
2 files changed, 151 insertions, 3 deletions
diff --git a/sys/arch/sparc64/dev/creator.c b/sys/arch/sparc64/dev/creator.c
index 52593ea6a03..c194072a32e 100644
--- a/sys/arch/sparc64/dev/creator.c
+++ b/sys/arch/sparc64/dev/creator.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: creator.c,v 1.42 2009/09/05 14:09:35 miod Exp $ */
+/* $OpenBSD: creator.c,v 1.43 2009/11/30 23:32:57 kettenis Exp $ */
/*
* Copyright (c) 2002 Jason L. Wright (jason@thought.net)
@@ -32,7 +32,7 @@
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/conf.h>
-#include <sys/timeout.h>
+#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/autoconf.h>
@@ -50,6 +50,7 @@ int creator_match(struct device *, void *, void *);
void creator_attach(struct device *, struct device *, void *);
int creator_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t creator_mmap(void *, off_t, int);
+
void creator_ras_fifo_wait(struct creator_softc *, int);
void creator_ras_wait(struct creator_softc *);
void creator_ras_init(struct creator_softc *);
@@ -58,10 +59,14 @@ int creator_ras_erasecols(void *, int, int, int, long int);
int creator_ras_eraserows(void *, int, int, long int);
void creator_ras_fill(struct creator_softc *);
void creator_ras_setfg(struct creator_softc *, int32_t);
+
int creator_setcursor(struct creator_softc *, struct wsdisplay_cursor *);
int creator_updatecursor(struct creator_softc *, u_int);
void creator_curs_enable(struct creator_softc *, u_int);
+void creator_load_firmware(void *);
+void creator_load_sram(struct creator_softc *, u_int32_t *, u_int32_t);
+
struct wsdisplay_accessops creator_accessops = {
creator_ioctl,
creator_mmap,
@@ -190,6 +195,15 @@ creator_attach(parent, self, aux)
sc->sc_sunfb.sf_ro.ri_ops.erasecols = creator_ras_erasecols;
sc->sc_sunfb.sf_ro.ri_ops.copyrows = creator_ras_copyrows;
creator_ras_init(sc);
+
+ /*
+ * Elite3D cards need a firmware for accelerated X to
+ * work. Console framebuffer acceleration will work
+ * without it though, so doing this late should be
+ * fine.
+ */
+ if (sc->sc_type == FFB_AFB)
+ mountroothook_establish(creator_load_firmware, sc);
}
if (sc->sc_console)
@@ -719,3 +733,127 @@ creator_ras_setfg(sc, fg)
FBC_WRITE(sc, FFB_FBC_FG, fg);
creator_ras_wait(sc);
}
+
+struct creator_firmware {
+ char fw_ident[8];
+ u_int32_t fw_size;
+ u_int32_t fw_reserved[2];
+ u_int32_t fw_ucode[0];
+};
+
+#define CREATOR_FIRMWARE_REV 0x101
+
+void
+creator_load_firmware(void *vsc)
+{
+ struct creator_softc *sc = vsc;
+ struct creator_firmware *fw;
+ u_int32_t ascr;
+ size_t buflen;
+ u_char *buf;
+ int error;
+
+ error = loadfirmware("afb", &buf, &buflen);
+ if (error) {
+ printf("%s: error %d, could not read firmware %s\n",
+ sc->sc_sunfb.sf_dev.dv_xname, error, "afb");
+ return;
+ }
+
+ fw = (struct creator_firmware *)buf;
+ if (sizeof(*fw) > buflen ||
+ fw->fw_size * sizeof(u_int32_t) > (buflen - sizeof(*fw))) {
+ printf("%s: corrupt firmware\n", sc->sc_sunfb.sf_dev.dv_xname);
+ free(buf, M_DEVBUF);
+ return;
+ }
+
+ printf("%s: firmware rev %d.%d.%d\n", sc->sc_sunfb.sf_dev.dv_xname,
+ (fw->fw_ucode[CREATOR_FIRMWARE_REV] >> 16) & 0xff,
+ (fw->fw_ucode[CREATOR_FIRMWARE_REV] >> 8) & 0xff,
+ fw->fw_ucode[CREATOR_FIRMWARE_REV] & 0xff);
+
+ ascr = FBC_READ(sc, FFB_FBC_ASCR);
+
+ /* Stop all floats. */
+ FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3f);
+ FBC_WRITE(sc, FFB_FBC_ASCR, FBC_ASCR_STOP);
+
+ creator_ras_wait(sc);
+
+ /* Load firmware into all secondary floats. */
+ if (ascr & 0x3e) {
+ FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3e);
+ creator_load_sram(sc, fw->fw_ucode, fw->fw_size);
+ }
+
+ /* Load firmware into primary float. */
+ FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x01);
+ creator_load_sram(sc, fw->fw_ucode, fw->fw_size);
+
+ /* Restart all floats. */
+ FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3f);
+ FBC_WRITE(sc, FFB_FBC_ASCR, FBC_ASCR_RESTART);
+
+ creator_ras_wait(sc);
+
+ free(buf, M_DEVBUF);
+}
+
+void
+creator_load_sram(struct creator_softc *sc, u_int32_t *ucode, u_int32_t size)
+{
+ uint64_t pstate, fprs;
+ caddr_t sram;
+
+ sram = bus_space_vaddr(sc->sc_bt, sc->sc_fbc_h) + FFB_FBC_SRAM36;
+
+ /*
+ * Apparently, loading the firmware into SRAM needs to be done
+ * using block copies. And block copies use the
+ * floating-point registers. Generally, using the FPU in the
+ * kernel is verboten. But since we load the firmware before
+ * userland processes are started, thrashing the
+ * floating-point registers is fine. We do need to enable the
+ * FPU before we access them though, otherwise we'll trap.
+ */
+ pstate = sparc_rdpr(pstate);
+ sparc_wrpr(pstate, pstate | PSTATE_PEF, 0);
+ fprs = sparc_rd(fprs);
+ sparc_wr(fprs, FPRS_FEF, 0);
+
+ FBC_WRITE(sc, FFB_FBC_SRAMAR, 0);
+
+ while (size > 0) {
+ creator_ras_fifo_wait(sc, 16);
+
+ __asm__ __volatile__("ld [%0 + 0x00], %%f1\n\t"
+ "ld [%0 + 0x04], %%f0\n\t"
+ "ld [%0 + 0x08], %%f3\n\t"
+ "ld [%0 + 0x0c], %%f2\n\t"
+ "ld [%0 + 0x10], %%f5\n\t"
+ "ld [%0 + 0x14], %%f4\n\t"
+ "ld [%0 + 0x18], %%f7\n\t"
+ "ld [%0 + 0x1c], %%f6\n\t"
+ "ld [%0 + 0x20], %%f9\n\t"
+ "ld [%0 + 0x24], %%f8\n\t"
+ "ld [%0 + 0x28], %%f11\n\t"
+ "ld [%0 + 0x2c], %%f10\n\t"
+ "ld [%0 + 0x30], %%f13\n\t"
+ "ld [%0 + 0x34], %%f12\n\t"
+ "ld [%0 + 0x38], %%f15\n\t"
+ "ld [%0 + 0x3c], %%f14\n\t"
+ "membar #Sync\n\t"
+ "stda %%f0, [%1] 240\n\t"
+ "membar #Sync"
+ : : "r" (ucode), "r" (sram));
+
+ ucode += 16;
+ size -= 16;
+ }
+
+ sparc_wr(fprs, fprs, 0);
+ sparc_wrpr(pstate, pstate, 0);
+
+ creator_ras_wait(sc);
+}
diff --git a/sys/arch/sparc64/dev/creatorreg.h b/sys/arch/sparc64/dev/creatorreg.h
index 6ad4c52a250..b9f5b477b26 100644
--- a/sys/arch/sparc64/dev/creatorreg.h
+++ b/sys/arch/sparc64/dev/creatorreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: creatorreg.h,v 1.8 2003/06/20 19:54:37 miod Exp $ */
+/* $OpenBSD: creatorreg.h,v 1.9 2009/11/30 23:32:57 kettenis Exp $ */
/*
* Copyright (c) 2002 Jason L. Wright (jason@thought.net)
@@ -242,6 +242,13 @@
#define FFB_FBC_UCSR 0x900 /* User Control & Status */
#define FFB_FBC_MER 0x980
+#define FFB_FBC_FEM 0x1540
+#define FFB_FBC_SRAMAR 0x1550
+
+#define FFB_FBC_ASCR 0x10800
+#define FFB_FBC_KCSR 0x10900
+#define FFB_FBC_SRAM36 0x114c0
+
#define FFB_FBC_WB_A 0x20000000
#define FFB_FBC_WM_COMBINED 0x00080000
#define FFB_FBC_RB_A 0x00004000
@@ -288,6 +295,9 @@
#define FBC_UCSR_READ_ERR 0x40000000
#define FBC_UCSR_FIFO_OVFL 0x80000000
+#define FBC_ASCR_STOP 0x00020000
+#define FBC_ASCR_RESTART 0x00040000
+
#define FBC_DRAWOP_DOT 0x00
#define FBC_DRAWOP_AADOT 0x01
#define FBC_DRAWOP_BRLINECAP 0x02