enum { UNKNOWN_FLASH = 0, ATMEL_AT45DB642D = 1, SSTI_SST25VF016B = 2, SSTI_SST25VF032B = 3, SSTI_SST25VF064C = 4, SPANSION_S25FL116K = 5, SPANSION_S25FL132K = 6, SPANSION_S25FL164K = 7, WINBOND_W25Q16JV = 8, }; static uint32_t linknr = 0; 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); } int FlashDetect(int dev) { uint8_t Cmd = 0x9F; uint8_t Id[3]; int r = flashio(dev, &Cmd, 1, Id, 3); if (r < 0) return r; if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x41) r = SSTI_SST25VF016B; else if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4A) r = SSTI_SST25VF032B; else if ( Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4B ) r = SSTI_SST25VF064C; else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x15 ) r = SPANSION_S25FL116K; else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x16 ) r = SPANSION_S25FL132K; else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x17 ) r = SPANSION_S25FL164K; else if ( Id[0] == 0x1F && Id[1] == 0x28) r = ATMEL_AT45DB642D; else if ( Id[0] == 0xef && Id[1] == 0x40 && Id[2] == 0x15 ) r = WINBOND_W25Q16JV; else r = UNKNOWN_FLASH; switch(r) { case UNKNOWN_FLASH : printf("Unknown Flash Flash ID = %02x %02x %02x\n",Id[0],Id[1],Id[2]); break; case ATMEL_AT45DB642D : printf("Flash: Atmel AT45DB642D 64 MBit\n"); break; case SSTI_SST25VF016B : printf("Flash: SSTI SST25VF016B 16 MBit\n"); break; case SSTI_SST25VF032B : printf("Flash: SSTI SST25VF032B 32 MBit\n"); break; case SSTI_SST25VF064C : printf("Flash: SSTI SST25VF064C 64 MBit\n"); break; case SPANSION_S25FL116K : printf("Flash: SPANSION S25FL116K 16 MBit\n"); break; case SPANSION_S25FL132K : printf("Flash: SPANSION S25FL132K 32 MBit\n"); break; case SPANSION_S25FL164K : printf("Flash: SPANSION S25FL164K 64 MBit\n"); break; case WINBOND_W25Q16JV : printf("Flash: Winbond W25Q16JV 16 MBit\n"); break; } return r; } static int flashdetect(int fd, uint32_t *sector_size, uint32_t *flash_size) { uint8_t cmd = 0x9F; uint8_t id[3]; int flash_type; int r = flashio(fd, &cmd, 1, id, 3); if (r < 0) return r; if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) { flash_type = SSTI_SST25VF016B; printf("Flash: SSTI SST25VF016B 16 MBit\n"); *sector_size = 4096; *flash_size = 0x200000; } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) { flash_type = SSTI_SST25VF032B; printf("Flash: SSTI SST25VF032B 32 MBit\n"); *sector_size = 4096; *flash_size = 0x400000; } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) { flash_type = SSTI_SST25VF064C; printf("Flash: SSTI SST25VF064C 64 MBit\n"); *sector_size = 4096; *flash_size = 0x800000; } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) { flash_type = SPANSION_S25FL116K; printf("Flash: SPANSION S25FL116K 16 MBit\n"); *sector_size = 4096; *flash_size = 0x200000; } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) { flash_type = SPANSION_S25FL132K; printf("Flash: SPANSION S25FL132K 32 MBit\n"); *sector_size = 4096; *flash_size = 0x400000; } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) { flash_type = SPANSION_S25FL164K; printf("Flash: SPANSION S25FL164K 64 MBit\n"); *sector_size = 4096; *flash_size = 0x800000; } else if (id[0] == 0xef && id[1] == 0x40 && id[2] == 0x15) { flash_type = WINBOND_W25Q16JV; printf("Flash: Winbond 16 MBit\n"); *sector_size = 4096; *flash_size = 0x200000; } else if (id[0] == 0x1F && id[1] == 0x28) { flash_type = ATMEL_AT45DB642D; printf("Flash: Atmel AT45DB642D 64 MBit\n"); *sector_size = 1024; *flash_size = 0x800000; } else { printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]); return -1; } return flash_type; } #if 1 int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) { int ret; uint8_t cmd[4]; uint32_t l; while (len) { cmd[0] = 3; cmd[1] = (addr >> 16) & 0xff; cmd[2] = (addr >> 8) & 0xff; cmd[3] = addr & 0xff; if (len > 1024) l = 1024; else l = len; ret = flashio(ddb, cmd, 4, buf, l); if (ret < 0) return ret; addr += l; buf += l; len -= l; } return 0; } #else static 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); } #endif 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 31 && b[i] < 127) ? b[i] : '.'); printf("\n"); } } void Dump(const uint8_t *b, uint32_t start, int l) { int i, j; for (j = 0; j < l; j += 16, b += 16) { printf("%08x: ", start + j); for (i = 0; i < 16; i++) if (i + j < l) printf("%02x ", b[i]); else printf(" "); printf(" |"); for (i = 0; i < 16; i++) if (i + j < l) putchar((b[i] > 31 && b[i] < 127) ? b[i] : '.'); printf("|\n"); } } int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize) { int err = 0; int BlockErase = BufferSize >= 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 FlashWriteSSTI(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; } 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; } int FlashWritePageMode(int dev, uint32_t FlashOffset, uint8_t *Buffer,int BufferSize,uint8_t LockBits) { int err = 0; uint8_t Cmd[260]; int i, j; 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; }