support SST flash chips
authornotaz <notasas@gmail.com>
Sat, 14 Aug 2021 22:23:09 +0000 (01:23 +0300)
committernotaz <notasas@gmail.com>
Sat, 14 Aug 2021 22:23:09 +0000 (01:23 +0300)
flashkit.c

index a2ebdb8..843decb 100644 (file)
@@ -53,6 +53,20 @@ enum dev_cmd {
 #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;
@@ -231,18 +245,18 @@ static void flash_seq_write8(int fd, uint32_t addr, const uint8_t *d)
 {
        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,
@@ -252,6 +266,7 @@ static void flash_seq_write8(int fd, uint32_t addr, const uint8_t *d)
                CMD_RY
        };
 
+       assert(info.prog_addr);
        write_serial(fd, cmd, sizeof(cmd));
 }
 
@@ -259,18 +274,18 @@ static void flash_seq_write16(int fd, uint32_t addr, const uint8_t *d)
 {
        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,
@@ -280,6 +295,7 @@ static void flash_seq_write16(int fd, uint32_t addr, const uint8_t *d)
                CMD_RY
        };
 
+       assert(info.prog_addr);
        write_serial(fd, cmd, sizeof(cmd));
 }
 
@@ -452,22 +468,24 @@ static const struct iof *io = &io_ops[0];
 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);
 }
 
@@ -478,7 +496,7 @@ static void flash_seq_erase(int fd, uint32_t addr)
 
 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?
@@ -499,59 +517,82 @@ static void set_delay(int fd, uint8_t delay)
        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);
@@ -560,8 +601,6 @@ static void read_info(int fd)
        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)