From bc4a856ae0ca1535670148dbea99ceead38983f4 Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 15 Aug 2021 01:23:09 +0300 Subject: [PATCH] support SST flash chips --- flashkit.c | 177 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 69 deletions(-) diff --git a/flashkit.c b/flashkit.c index a2ebdb8..843decb 100644 --- a/flashkit.c +++ b/flashkit.c @@ -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) -- 2.39.5