#define PAR_SINGE (1 << 6)
#define PAR_INC (1 << 7)
+static struct flash_info {
+ uint32_t prog_addr;
+ uint16_t mid;
+ uint16_t did;
+ uint32_t size;
+ uint16_t region_cnt;
+ struct {
+ uint32_t block_size;
+ uint32_t block_count;
+ uint32_t start;
+ uint32_t size;
+ } region[4];
+} info;
+
static int setup(int fd)
{
struct termios tty;
{
uint8_t cmd[] = {
// unlock
- CMD_ADDR, 0,
- CMD_ADDR, 0x0a,
- CMD_ADDR, 0xaa,
+ CMD_ADDR, info.prog_addr >> 16,
+ CMD_ADDR, info.prog_addr >> 8,
+ CMD_ADDR, info.prog_addr >> 0,
CMD_WR | PAR_SINGE | PAR_MODE8, 0xaa,
- CMD_ADDR, 0,
- CMD_ADDR, 0x05,
- CMD_ADDR, 0x55,
+ CMD_ADDR, info.prog_addr >> 17,
+ CMD_ADDR, info.prog_addr >> 9,
+ CMD_ADDR, info.prog_addr >> 1,
CMD_WR | PAR_SINGE | PAR_MODE8, 0x55,
// program setup
- CMD_ADDR, 0,
- CMD_ADDR, 0x0a,
- CMD_ADDR, 0xaa,
+ CMD_ADDR, info.prog_addr >> 16,
+ CMD_ADDR, info.prog_addr >> 8,
+ CMD_ADDR, info.prog_addr >> 0,
CMD_WR | PAR_SINGE | PAR_MODE8, 0xa0,
// program data
CMD_ADDR, addr >> 16,
CMD_RY
};
+ assert(info.prog_addr);
write_serial(fd, cmd, sizeof(cmd));
}
{
uint8_t cmd[] = {
// unlock
- CMD_ADDR, 0,
- CMD_ADDR, 0x05,
- CMD_ADDR, 0x55,
+ CMD_ADDR, info.prog_addr >> 17,
+ CMD_ADDR, info.prog_addr >> 9,
+ CMD_ADDR, info.prog_addr >> 1,
CMD_WR | PAR_SINGE | PAR_MODE8, 0xaa,
- CMD_ADDR, 0,
- CMD_ADDR, 0x02,
- CMD_ADDR, 0xaa,
+ CMD_ADDR, info.prog_addr >> 18,
+ CMD_ADDR, info.prog_addr >> 10,
+ CMD_ADDR, info.prog_addr >> 2,
CMD_WR | PAR_SINGE | PAR_MODE8, 0x55,
// program setup
- CMD_ADDR, 0,
- CMD_ADDR, 0x05,
- CMD_ADDR, 0x55,
+ CMD_ADDR, info.prog_addr >> 17,
+ CMD_ADDR, info.prog_addr >> 9,
+ CMD_ADDR, info.prog_addr >> 1,
CMD_WR | PAR_SINGE | PAR_MODE8, 0xa0,
// program data
CMD_ADDR, addr >> 17,
CMD_RY
};
+ assert(info.prog_addr);
write_serial(fd, cmd, sizeof(cmd));
}
static uint16_t flash_seq_r(int fd, uint8_t cmd, uint32_t addr)
{
// unlock
- io->write_bus(fd, 0xaaa, 0xaa);
- io->write_bus(fd, 0x555, 0x55);
+ assert(info.prog_addr);
+ io->write_bus(fd, info.prog_addr >> 0, 0xaa);
+ io->write_bus(fd, info.prog_addr >> 1, 0x55);
- io->write_bus(fd, 0xaaa, cmd);
+ io->write_bus(fd, info.prog_addr >> 0, cmd);
return io->read_bus(fd, addr);
}
static void flash_seq_erase_d(int fd, uint32_t addr, uint8_t d)
{
// printf("erase %06x\n", addr);
- io->write_bus(fd, 0xaaa, 0xaa);
- io->write_bus(fd, 0x555, 0x55);
- io->write_bus(fd, 0xaaa, 0x80);
+ assert(info.prog_addr);
+ io->write_bus(fd, info.prog_addr >> 0, 0xaa);
+ io->write_bus(fd, info.prog_addr >> 1, 0x55);
+ io->write_bus(fd, info.prog_addr >> 0, 0x80);
- io->write_bus(fd, 0xaaa, 0xaa);
- io->write_bus(fd, 0x555, 0x55);
+ io->write_bus(fd, info.prog_addr >> 0, 0xaa);
+ io->write_bus(fd, info.prog_addr >> 1, 0x55);
io->write_bus(fd, addr, d);
}
static void flash_seq_erase_full(int fd)
{
- flash_seq_erase_d(fd, 0xaaa, 0x10);
+ flash_seq_erase_d(fd, info.prog_addr, 0x10);
}
// status wait + dummy read to cause a wait?
write_serial(fd, cmd, sizeof(cmd));
}
-static struct flash_info {
- uint16_t mid;
- uint16_t did;
- uint32_t size;
- uint16_t region_cnt;
- struct {
- uint32_t block_size;
- uint32_t block_count;
- uint32_t start;
- uint32_t size;
- } region[4];
-} info;
-
static void read_info(int fd)
{
static const uint16_t qry[3] = { 'Q', 'R', 'Y' };
+ uint16_t resp_cfi[3], sst_mid = ~0;
uint32_t total = 0;
- uint16_t resp[3];
uint32_t i, a;
- info.mid = flash_seq_r(fd, 0x90, 0); // autoselect
- info.did = io->read_bus(fd, 2);
- // could enter CFI directly, but there seems to be a "stack"
- // of modes, so 2 exits would be needed
- io->write_bus(fd, 0, 0xf0);
+ // see if this chip understands CFI (common flash interface)
+ io->write_bus(fd, 0xaa, 0x98);
+ resp_cfi[0] = io->read_bus(fd, 0x20);
+ resp_cfi[1] = io->read_bus(fd, 0x22);
+ resp_cfi[2] = io->read_bus(fd, 0x24);
+ if (memcmp(resp_cfi, qry, sizeof(resp_cfi)) == 0)
+ {
+ info.size = 1u << io->read_bus(fd, 0x4e);
+ info.region_cnt = io->read_bus(fd, 0x58);
+ assert(0 < info.region_cnt && info.region_cnt <= 4);
+ for (i = 0, a = 0x5a; i < info.region_cnt; i++, a += 8) {
+ info.region[i].block_count = io->read_bus(fd, a + 0) + 1;
+ info.region[i].block_count += io->read_bus(fd, a + 2) << 8;
+ info.region[i].block_size = io->read_bus(fd, a + 4) << 8;
+ info.region[i].block_size |= io->read_bus(fd, a + 6) << 16;
+ info.region[i].start = total;
+ info.region[i].size =
+ info.region[i].block_size * info.region[i].block_count;
+ assert(info.region[i].size);
+ total += info.region[i].size;
+ }
+ if (info.size != total)
+ fprintf(stderr, "warning: total is %u, bad CFI?\n", total);
- io->write_bus(fd, 0xaa, 0x98); // CFI Query
- resp[0] = io->read_bus(fd, 0x20);
- resp[1] = io->read_bus(fd, 0x22);
- resp[2] = io->read_bus(fd, 0x24);
- if (memcmp(resp, qry, sizeof(resp))) {
- fprintf(stderr, "unexpected CFI response: %04x %04x %04x\n",
- resp[0], resp[1], resp[2]);
- exit(1);
+ info.prog_addr = 0xaaa;
+ io->write_bus(fd, 0, 0xf0);
+ info.mid = flash_seq_r(fd, 0x90, 0); // autoselect
+ info.did = io->read_bus(fd, 2);
}
- info.size = 1u << io->read_bus(fd, 0x4e);
- info.region_cnt = io->read_bus(fd, 0x58);
- assert(0 < info.region_cnt && info.region_cnt <= 4);
- for (i = 0, a = 0x5a; i < info.region_cnt; i++, a += 8) {
- info.region[i].block_count = io->read_bus(fd, a + 0) + 1;
- info.region[i].block_count += io->read_bus(fd, a + 2) << 8;
- info.region[i].block_size = io->read_bus(fd, a + 4) << 8;
- info.region[i].block_size |= io->read_bus(fd, a + 6) << 16;
- info.region[i].start = total;
- info.region[i].size =
- info.region[i].block_size * info.region[i].block_count;
- assert(info.region[i].size);
- total += info.region[i].size;
+ else
+ {
+ // try the SST protocol
+ info.prog_addr = 0x5555;
+ sst_mid = flash_seq_r(fd, 0x90, 0);
+ if (sst_mid == 0xbf)
+ {
+ info.mid = sst_mid;
+ info.did = io->read_bus(fd, 0x01);
+ switch (info.did) {
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ info.size = 128 * 1024 << (info.did - 0xb5);
+ break;
+ default:
+ fprintf(stderr, "unrecognized SST device %02x\n", info.did);
+ exit(1);
+ }
+ info.region_cnt = 1;
+ info.region[0].block_count = info.size / 4096;
+ info.region[0].block_size = 4096;
+ info.region[0].start = 0;
+ info.region[0].size = info.size;
+ }
+ else
+ info.prog_addr = 0;
}
io->write_bus(fd, 0, 0xf0); // flash reset
+ if (info.prog_addr == 0) {
+ fprintf(stderr, "unable to identify the flash chip :(\n");
+ fprintf(stderr, "CFI response: %02x %02x %02x\n",
+ resp_cfi[0], resp_cfi[1], resp_cfi[2]);
+ fprintf(stderr, "SST MID: %02x\n", sst_mid);
+ exit(1);
+ }
+
printf("Flash info:\n");
printf("Manufacturer ID: %04x\n", info.mid);
printf("Device ID: %04x\n", info.did);
for (i = 0; i < info.region_cnt; i++)
printf(" %5u x %u\n", info.region[i].block_size,
info.region[i].block_count);
- if (info.size != total)
- fprintf(stderr, "warning: total is %u, bad CFI?\n", total);
}
static uint32_t get_block_addr(uint32_t addr, uint32_t blk_offset)