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