On Mon, Jul 20, 2009 at 10:46:17PM +0200, Mark Kettenis wrote: > Ugh, it seems that afbinit code does some sneaky word swapping. > Here's a new diff. > > > 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 20 Jul 2009 20:41:48 -0000 [snip] > @@ -711,5 +725,89 @@ 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) > +{ > + int i; > + > + FBC_WRITE(sc, FFB_FBC_SRAMAR, 0); > + > + while (size > 0) { > + creator_ras_fifo_wait(sc, 16); > + for (i = 0; i < 16; i ++) > + FBC_WRITE(sc, FFB_FBC_SRAM36 + i, ucode[i ^ 1]); > + ucode += 16; > + size -= 16; > + } > + > creator_ras_wait(sc); > }
I'm sure I'm missing something here; I'm not certain I understand what you are doing with the for()-loop iterating over 16. So, take the following comment with a grain of salt: Should there not be a check to make sure 'fw->fw_size', hence 'size' is a multiple of 16? --patrick