/* /* flashprog - Programmer for flash on Digital Devices Octopus * * Copyright (C) 2010-2011 Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 only, as published by the Free Software Foundation. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include #include #define DDB_MAGIC 'd' static uint32_t linknr = 0; struct ddb_id { __u16 vendor; __u16 device; __u16 subvendor; __u16 subdevice; __u32 hw; __u32 regmap; }; struct ddb_flashio { __u8 *write_buf; __u32 write_len; __u8 *read_buf; __u32 read_len; __u32 link; }; #define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) #define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id) int flashio(int ddb, uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen) { struct ddb_flashio fio = { .write_buf=wbuf, .write_len=wlen, .read_buf=rbuf, .read_len=rlen, .link=linknr, }; return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio); } enum { UNKNOWN_FLASH = 0, ATMEL_AT45DB642D = 1, SSTI_SST25VF016B = 2, SSTI_SST25VF032B = 3, SSTI_SST25VF064C = 4, SPANSION_S25FL116K = 5, }; int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) { uint8_t cmd[4]= {0x03, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff}; return flashio(ddb, cmd, 4, buf, len); } int flashdump(int ddb, uint32_t addr, uint32_t len) { int i, j; uint8_t buf[32]; int bl = sizeof(buf); for (j=0; j= 8192; int i; if (BlockErase) { for(i = 0; i < BufferSize; i += 8192 ) { uint8_t Cmd[4]; if( (i & 0xFFFF) == 0 ) printf(" Erase %08x\n",FlashOffset + i); Cmd[0] = 0x50; // Block Erase Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; err = flashio(dev,Cmd,4,NULL,0); if( err < 0 ) break; while( 1 ) { Cmd[0] = 0xD7; // Read Status register err = flashio(dev,Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x80) == 0x80 ) break; } } } for(i = 0; i < BufferSize; i += 1024 ) { uint8_t Cmd[4 + 1024]; if( (i & 0xFFFF) == 0 ) { printf(" Program %08x\n",FlashOffset + i); } Cmd[0] = 0x84; // Buffer 1 Cmd[1] = 0x00; Cmd[2] = 0x00; Cmd[3] = 0x00; memcpy(&Cmd[4],&Buffer[i],1024); err = flashio(dev,Cmd,4 + 1024,NULL,0); if( err < 0 ) break; Cmd[0] = BlockErase ? 0x88 : 0x83; // Buffer to Main Memory (with Erase) Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; err = flashio(dev,Cmd,4,NULL,0); if( err < 0 ) break; while( 1 ) { Cmd[0] = 0xD7; // Read Status register err = flashio(dev,Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x80) == 0x80 ) break; } if( err < 0 ) break; } return err; } int FlashWritePageMode(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize, uint8_t LockBits) { int err = 0, i, j; uint8_t Cmd[260]; if( (BufferSize % 4096) != 0 ) return -1; // Must be multiple of sector size do { Cmd[0] = 0x50; // EWSR err = flashio(dev, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x00; // BPx = 0, Unlock all blocks err = flashio(dev, Cmd,2,NULL,0); if( err < 0 ) break; for(i = 0; i < BufferSize; i += 4096 ) { if( (i & 0xFFFF) == 0 ) { printf(" Erase %08x\n",FlashOffset + i); } Cmd[0] = 0x06; // WREN err = flashio(dev, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x20; // Sector erase ( 4Kb) Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; err = flashio(dev, Cmd,4,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS err = flashio(dev, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } if( err < 0 ) break; } if( err < 0 ) break; for (j = BufferSize - 256; j >= 0; j -= 256 ) { if( (j & 0xFFFF) == 0 ) { printf(" Programm %08x\n",FlashOffset + j); } Cmd[0] = 0x06; // WREN err = flashio(dev, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x02; // PP Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF ); Cmd[3] = 0x00; memcpy(&Cmd[4],&Buffer[j],256); err = flashio(dev, Cmd,260,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS err = flashio(dev, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } if( err < 0 ) break; } if( err < 0 ) break; Cmd[0] = 0x50; // EWSR err = flashio(dev, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = LockBits; // BPx = 0, Lock all blocks err = flashio(dev, Cmd,2,NULL,0); } while(0); return err; } int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSize) { int err = 0; uint8_t Cmd[6]; int i, j; // Must be multiple of sector size if( (BufferSize % 4096) != 0 ) return -1; do { Cmd[0] = 0x50; // EWSR err = flashio(dev,Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x00; // BPx = 0, Unlock all blocks err = flashio(dev,Cmd,2,NULL,0); if( err < 0 ) break; for(i = 0; i < BufferSize; i += 4096 ) { if( (i & 0xFFFF) == 0 ) printf(" Erase %08x\n",FlashOffset + i); Cmd[0] = 0x06; // WREN err = flashio(dev,Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x20; // Sector erase ( 4Kb) Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; err = flashio(dev,Cmd,4,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS err = flashio(dev,Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } if( err < 0 ) break; } if( err < 0 ) break; for(j = BufferSize - 4096; j >= 0; j -= 4096 ) { if( (j & 0xFFFF) == 0 ) printf(" Program %08x\n",FlashOffset + j); for(i = 0; i < 4096; i += 2 ) { if( i == 0 ) { Cmd[0] = 0x06; // WREN err = flashio(dev,Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0xAD; // AAI Cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF ); Cmd[3] = 0x00; Cmd[4] = Buffer[j+i]; Cmd[5] = Buffer[j+i+1]; err = flashio(dev,Cmd,6,NULL,0); } else { Cmd[0] = 0xAD; // AAI Cmd[1] = Buffer[j+i]; Cmd[2] = Buffer[j+i+1]; err = flashio(dev,Cmd,3,NULL,0); } if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS err = flashio(dev,Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } if( err < 0 ) break; } if( err < 0 ) break; Cmd[0] = 0x04; // WDIS err = flashio(dev,Cmd,1,NULL,0); if( err < 0 ) break; } if( err < 0 ) break; Cmd[0] = 0x50; // EWSR err = flashio(dev,Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x1C; // BPx = 0, Lock all blocks err = flashio(dev,Cmd,2,NULL,0); } while(0); return err; } void get_id(int ddb, struct ddb_id *ddbid) { uint8_t id[4]; if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0) return; memset(ddbid, 0, sizeof(*ddbid)); flashread(ddb, id, 0, 4); printf("%02x %02x %02x %02x\n", id[0], id[1], id[2], id[3]); ddbid->subvendor=(id[0] << 8) | id[1]; ddbid->subdevice=(id[2] << 8) | id[3]; } int sure() { char c; printf("\n\nWARNING! Flashing a new FPGA image might make your card unusable!\n"); printf("\n\nWARNUNG! Das Flashen eines neuen FPGA-Images kann Ihre Karte unbrauchbar machen.\n"); printf("\n\nAre you sure? y/n?"); printf("\n\nSind Sie sicher? y/n?"); fflush(0); c = getchar(); if (c!='y') { printf("\nFlashing aborted.\n\n"); return -1; } printf("\nStarting to flash\n\n"); return 0; } int main(int argc, char **argv) { char ddbname[80]; int type = 0; struct ddb_id ddbid; uint8_t *buffer; int BufferSize = 0; int BlockErase = 0; uint32_t FlashOffset = 0x10000; int ddb; int i, err; int SectorSize=0; int FlashSize=0; int Flash; uint32_t svid=0, jump=0, dump=0; int bin; int ddbnum = 0; int force = 0; char *fname = NULL; while (1) { int option_index = 0; int c; static struct option long_options[] = { {"svid", required_argument, NULL, 's'}, {"help", no_argument , NULL, 'h'}, {"force", no_argument , NULL, 'f'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "d:n:s:o:l:dfhjb:", long_options, &option_index); if (c==-1) break; switch (c) { case 'b': fname = optarg; break; case 'd': dump = strtoul(optarg, NULL, 16); break; case 's': svid = strtoul(optarg, NULL, 16); break; case 'o': FlashOffset = strtoul(optarg, NULL, 16); break; case 'n': ddbnum = strtol(optarg, NULL, 0); break; case 'l': linknr = strtol(optarg, NULL, 0); break; case 'f': force = 1; break; case 'j': jump = 1; break; case 'h': default: break; } } if (optind> 16 ) & 0xFF ); buffer[BufferSize - 256 + 0x20] = ( ( Jump >> 8 ) & 0xFF ); buffer[BufferSize - 256 + 0x21] = ( ( Jump ) & 0xFF ); } else if (svid) { BufferSize = SectorSize; FlashOffset = 0; buffer = malloc(BufferSize); if (!buffer) { printf("out of memory\n"); return 0; } memset(buffer,0xFF,BufferSize); buffer[0] = ((svid >> 24 ) & 0xFF); buffer[1] = ((svid >> 16 ) & 0xFF); buffer[2] = ((svid >> 8 ) & 0xFF); buffer[3] = ((svid ) & 0xFF); } else { int fh, i; int fsize; if (!fname) switch (ddbid.device) { case 0x0002: fname="DVBBridgeV1A_DVBBridgeV1A.bit"; printf("Octopus 35\n"); break; case 0x0003: fname="DVBBridgeV1B_DVBBridgeV1B.bit"; printf("Octopus\n"); break; case 0x0007: fname="DVBBridgeV2A_DD01_0007_MXL.fpga"; printf("Octopus 4/8\n"); break; case 0x0008: fname="DVBBridgeV2A_DD01_0008_CXD.fpga"; printf("Octopus 4/8\n"); break; case 0x0011: fname="CIBridgeV1B_CIBridgeV1B.bit"; printf("Octopus CI\n"); break; case 0x0012: fname="DVBBridgeV2B_DD01_0012_STD.fpga"; printf("Octopus CI\n"); break; case 0x0013: fname="DVBBridgeV2B_DD01_0013_PRO.fpga"; printf("Octopus PRO\n"); break; case 0x0201: fname="DVBModulatorV1B_DVBModulatorV1B.bit"; printf("Modulator\n"); break; case 0x0203: fname="DVBModulatorV1B_DD01_0203.fpga"; printf("Modulator Test\n"); break; case 0x0210: fname="DVBModulatorV2A_DD01_0210.fpga"; printf("Modulator V2\n"); break; default: printf("UNKNOWN\n"); break; } fh = open(fname, O_RDONLY); if (fh < 0 ) { printf("File %s not found \n", fname); return 0; } printf("Using bitstream %s\n", fname); fsize = lseek(fh,0,SEEK_END); if( fsize > 4000000 || fsize < SectorSize ) { close(fh); printf("Invalid File Size \n"); return 0; } if( Flash == ATMEL_AT45DB642D ) { BlockErase = fsize >= 8192; if( BlockErase ) BufferSize = (fsize + 8191) & ~8191; else BufferSize = (fsize + 1023) & ~1023; } else { BufferSize = (fsize + SectorSize - 1 ) & ~(SectorSize - 1); } printf(" Size %08x, target %08x\n", BufferSize, FlashOffset); buffer = malloc(BufferSize); if( buffer == NULL ) { close(fh); printf("out of memory\n"); return 0; } memset(buffer, 0xFF, BufferSize); lseek(fh, 0, SEEK_SET); read(fh, buffer, fsize); close(fh); if (BufferSize >= 0x10000) { for(i = 0; i < 0x200; i += 1 ) { if ( *(uint16_t *) (&buffer[i]) == 0xFFFF ) break; buffer[i] = 0xFF; } } } if (!force && sure()<0) return 0; switch(Flash) { case ATMEL_AT45DB642D: err = FlashWriteAtmel(ddb,FlashOffset,buffer,BufferSize); break; case SSTI_SST25VF016B: case SSTI_SST25VF032B: err = FlashWriteSSTI_B(ddb,FlashOffset,buffer,BufferSize); break; case SSTI_SST25VF064C: err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x3C); break; case SPANSION_S25FL116K: err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x1C); break; } if (err < 0) printf("Programming Error\n"); else printf("Programming Done\n"); free(buffer); return 0; }