/* $Id: afbinit.c,v 1.1.1.1 1999/09/08 06:42:36 davem Exp $ * afbinit.c: Init AFB for general purpose usage at system * boot. Actually all this program does is * load the firmware ucode needed on the AFB_FLOAT * chips. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ #include #include #include #include #include #include /* Define this to debug the microcode loading procedure. */ #undef DEBUG_UCODE_LOAD /* Default microcode file name if none explicitly specified. */ #define UCODE_FILE "/usr/lib/afb.ucode" /* In order to make this quick hack completely self-contained, I * hardcode the AFB register offsets with these macros. */ #define AFB_UREG_UCSR(uregs) ((volatile unsigned int *)(((char *)uregs) + 0x0900)) #define AFB_UREG_FEM(uregs) ((volatile unsigned int *)(((char *)uregs) + 0x1540)) #define AFB_UREG_SRAMAR(uregs) ((volatile unsigned int *)(((char *)uregs) + 0x1550)) #define AFB_KREG_SRAM36(kregs) (((char *)kregs) + 0x14c0) #define AFB_KREG_ASCR(kregs) ((volatile unsigned int *)(((char *)kregs) + 0x0800)) #define AFB_ASCR_RESTART 0x00040000 #define AFB_ASCR_STOP 0x00020000 #define AFB_KREG_KCSR(kregs) ((volatile unsigned int *)(((char *)kregs) + 0x0900)) #define FFB_UCSR_ALL_BUSY 0x03000000 #define FFBFifo(uregs, __n) \ do { void *tmp = (uregs); \ while(((*AFB_UREG_UCSR(tmp) & 0xfff) - 8) < (__n)) \ __asm__ __volatile__("" : : : "memory"); \ } while(0) #define FFBWait(uregs) \ do { void *tmp = (uregs); \ while(*(AFB_UREG_UCSR(tmp)) & FFB_UCSR_ALL_BUSY) \ __asm__ __volatile__("membar #Sync" : : : "memory"); \ } while(0) static void sandblast_sram(char *ucodep, int blocks, void *afb_uregs, void *afb_kregs) { char *sram = AFB_KREG_SRAM36(afb_kregs); /* Reset SRAM address. */ *(AFB_UREG_SRAMAR(afb_uregs)) = 0; /* Poke it. */ while(blocks--) { FFBFifo(afb_uregs, 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" (ucodep), "r" (sram)); ucodep += 64; } /* Wait for the chip to eat it. */ FFBWait(afb_uregs); /* Read it back to ensure completion. */ __asm__ __volatile__("ldda [%0] 240, %%f0\n\t" "membar #Sync" : : "r" (sram)); } /* Note, if you try to enable a non-existant float chip * this will lock up the chip. */ static void afb_ucode_upload(char *ucodep, int nblocks, void *uregs, void *kregs) { unsigned int all_floats = *(AFB_KREG_ASCR(kregs)) & 0x3f; unsigned int orig_fem; /* Idle raster processor. Touching the float enable mask * while the floats are busy can flatline the machine. */ FFBWait(uregs); /* Set all valid float enable bits. */ #ifdef DEBUG_UCODE_LOAD printf("\nSet FEM %08x\n", all_floats); fflush(stdout); #endif *(AFB_UREG_FEM(uregs)) = all_floats; /* Stop all floats. */ #ifdef DEBUG_UCODE_LOAD printf("Set ASCR %08x\n", AFB_ASCR_STOP); fflush(stdout); #endif *(AFB_KREG_ASCR(kregs)) = AFB_ASCR_STOP; /* Idle again, just to be sure. */ #ifdef DEBUG_UCODE_LOAD printf("Idle RP\n"); fflush(stdout); #endif FFBWait(uregs); /* Ok, we should be in a state where it is safe to write * into the SRAM of the float processors. */ if (all_floats & ~1) { /* Enable all floats except float zero. */ #ifdef DEBUG_UCODE_LOAD printf("Set FEM %08x\n", (all_floats & ~1) & 0x3f); fflush(stdout); #endif *(AFB_UREG_FEM(uregs)) = (all_floats & ~1) & 0x3f; /* Load ucode into SRAM. */ #ifdef DEBUG_UCODE_LOAD printf("Write SRAM\n"); fflush(stdout); #endif sandblast_sram(ucodep, nblocks, uregs, kregs); } /* Now, enable _only_ float zero. */ #ifdef DEBUG_UCODE_LOAD printf("Set FEM %08x\n", (all_floats & 1)); fflush(stdout); #endif *(AFB_UREG_FEM(uregs)) = (all_floats & 1); /* Load ucode again. */ #ifdef DEBUG_UCODE_LOAD printf("Write SRAM\n"); fflush(stdout); #endif sandblast_sram(ucodep, nblocks, uregs, kregs); /* No we must get the floats going once more. * First enable all floats again. */ #ifdef DEBUG_UCODE_LOAD printf("Set FEM %08x\n", all_floats); fflush(stdout); #endif *(AFB_UREG_FEM(uregs)) = all_floats; /* Kick the ASCR to restart them. */ #ifdef DEBUG_UCODE_LOAD printf("Set ASCR %08x\n", AFB_ASCR_RESTART); fflush(stdout); #endif *(AFB_KREG_ASCR(kregs)) = AFB_ASCR_RESTART; /* Idle FBC/RP once more... */ #ifdef DEBUG_UCODE_LOAD printf("Idle RP\n"); fflush(stdout); #endif FFBWait(uregs); #ifdef DEBUG_UCODE_LOAD printf("Done!!!!\n"); fflush(stdout); #endif } static void usage(char *me) { printf("Usage: %s /dev/fb[0123] [ucode_file]\n", me); exit(1); } int main(int argc, char **argp) { struct afb_ucode_header { char ident[8]; unsigned int ucode_words; unsigned int __unused[2]; } ucheader; unsigned int *ucode; int afb_fd, ucode_fd, ucode_version; void *uregs, *kregs; char *afb_fname; char *ucode_fname = UCODE_FILE; if(argc != 2 && argc != 3) usage(argp[0]); afb_fname = argp[1]; if(argc == 3) ucode_fname = argp[2]; afb_fd = open(afb_fname, O_RDWR); if(afb_fd == -1) { perror("Open AFB device"); exit(1); } ucode_fd = open(ucode_fname, O_RDONLY); if(ucode_fd == -1) { perror("Open AFB ucode file"); exit(1); } memset(&ucheader, 0, sizeof(ucheader)); if(read(ucode_fd, &ucheader, sizeof(ucheader)) == -1) { perror("Read UCODE header"); exit(1); } ucode = (unsigned int *)malloc(ucheader.ucode_words << 2); if(ucode == NULL) { fprintf(stderr, "Cannot malloc %d bytes for UCODE.\n", ucheader.ucode_words << 2); exit(1); } if(read(ucode_fd, ucode, ucheader.ucode_words << 2) == -1) { perror("Read UCODE contents"); exit(1); } /* MMAP the registers. */ uregs = mmap(0, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE, afb_fd, 0x04000000); if (uregs == (void *)-1L) { perror("mmap user regs"); exit(1); } kregs = mmap(0, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE, afb_fd, 0x0bc04000); if (kregs == (void *)-1L) { perror("mmap kernel regs"); exit(1); } /* Say what UCODE version we are loading. */ ucode_version = *(ucode + (0x404 / sizeof(unsigned int))); printf("Revision-%d.%d.%d ", (ucode_version >> 16) & 0xff, (ucode_version >> 8) & 0xff, (ucode_version >> 0) & 0xff); afb_ucode_upload((char *)ucode, ucheader.ucode_words / 16, uregs, kregs); munmap(kregs, 0x2000); munmap(uregs, 0x2000); close(ucode_fd); close(afb_fd); exit(0); }