> Date: Sat, 18 Jul 2009 14:10:39 +0100
> From: Edd Barrett <[email protected]>
> 
> On Sat, Jul 18, 2009 at 10:43:49AM +0200, Mark Kettenis wrote:
> >      int newmode, oldmode;
> > 
> >      ioctl(fd, WSDISPLAYIO_GMODE, &oldmode);
> >      newmode = WSDISPLAYIO_MODE_MAPPED;
> >      ioctl(fd, WSDISPLAYIO_SMODE, &newmode);
> > 
> >      ...
> > 
> >      ioctl(fd, WSSDISPLAYIO_SMODE, &oldmode);
> > 
> > (with proper error checking of course).
> 
> OK, I have patched the sources and added error checking. Works fine!
> 
> Many thanks for the pointer.

Hi Edd,

I think it would be a good idea if the kernel loaded the firmware
instead of forcing people to install a port and tweak their rc.local.

Here is a diff that implements this.  It expects to find the firmware
in the file /etc/firmware/afb to be more consistent with the firmwares
already there.  Can you test this for me?


Index: creator.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/creator.c,v
retrieving revision 1.41
diff -u -p -r1.41 creator.c
--- creator.c   16 Jul 2009 21:03:09 -0000      1.41
+++ creator.c   19 Jul 2009 14:12:35 -0000
@@ -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   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 @@ void        creator_ras_erasecols(void *, int, 
 void   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,
@@ -171,9 +176,18 @@ creator_attach(parent, self, aux)
 
        printf(", model %s, dac %u\n", model, sc->sc_dacrev);
 
-       if (sc->sc_type == FFB_AFB)
+       if (sc->sc_type == FFB_AFB) {
                sc->sc_dacrev = 10;
 
+               /*
+                * Elite3D cards need a firmware for accelerated X to
+                * work.  Console fraamebuffer acceleration will work
+                * without it though, so doing this late should be
+                * fine.
+                */
+               mountroothook_establish(creator_load_firmware, sc);
+       }
+
        fb_setsize(&sc->sc_sunfb, 32, 1152, 900, sc->sc_node, 0);
        /* linesize has a fixed value, compensate */
        sc->sc_sunfb.sf_linebytes = 8192;
@@ -711,5 +725,86 @@ creator_ras_setfg(sc, fg)
                return;
        sc->sc_fg_cache = 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)
+{
+       FBC_WRITE(sc, FFB_FBC_SRAMAR, 0);
+
+       while (size--) {
+               creator_ras_fifo_wait(sc, 16);
+               bus_space_write_region_4(sc->sc_bt, sc->sc_fbc_h,
+                   FFB_FBC_SRAM36, ucode, 16);
+               ucode += 16;
+       }
+
        creator_ras_wait(sc);
 }
Index: creatorreg.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/creatorreg.h,v
retrieving revision 1.8
diff -u -p -r1.8 creatorreg.h
--- creatorreg.h        20 Jun 2003 19:54:37 -0000      1.8
+++ creatorreg.h        19 Jul 2009 14:12:35 -0000
@@ -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_KSCR           0x10900
+#define FFB_FBC_SRAM36         0x1014c0
+
 #define        FFB_FBC_WB_A            0x20000000
 #define        FFB_FBC_WM_COMBINED     0x00080000
 #define        FFB_FBC_RB_A            0x00004000
@@ -287,6 +294,9 @@
 #define        FBC_UCSR_RP_BUSY        0x02000000
 #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

Reply via email to