attempt to add 8bit flash support
[flashkit-mdc.git] / flashkit.c
index 3e687fc..5d8a587 100644 (file)
@@ -119,17 +119,38 @@ static int read_serial(int fd, void *data, size_t size)
        return 0;
 }
 
-static void set_addr(int fd, uint32_t addr)
+/* addr arg is always byte address */
+static void set_addr8(int fd, uint32_t addr)
 {
        uint8_t cmd[6] = {
-               CMD_ADDR, addr >> 17,
-               CMD_ADDR, addr >> 9,
-               CMD_ADDR, addr >> 1
+               CMD_ADDR, addr >> 16,
+               CMD_ADDR, addr >> 8,
+               CMD_ADDR, addr >> 0
+       };
+       write_serial(fd, cmd, sizeof(cmd));
+}
+
+static void set_addr16(int fd, uint32_t addr)
+{
+       set_addr8(fd, addr >> 1);
+}
+
+static uint16_t read_bus8(int fd, uint32_t addr)
+{
+       uint8_t cmd[7] = {
+               CMD_ADDR, addr >> 16,
+               CMD_ADDR, addr >> 8,
+               CMD_ADDR, addr >> 0,
+               CMD_RD | PAR_SINGE | PAR_MODE8
        };
+       uint8_t r;
+
        write_serial(fd, cmd, sizeof(cmd));
+       read_serial(fd, &r, sizeof(r));
+       return r;
 }
 
-static uint16_t read_word(int fd, uint32_t addr)
+static uint16_t read_bus16(int fd, uint32_t addr)
 {
        uint8_t cmd[7] = {
                CMD_ADDR, addr >> 17,
@@ -144,7 +165,20 @@ static uint16_t read_word(int fd, uint32_t addr)
        return ntohs(r);
 }
 
-static void write_word(int fd, uint32_t addr, uint16_t d)
+static void write_bus8(int fd, uint32_t addr, uint16_t d)
+{
+       uint8_t cmd[8] = {
+               CMD_ADDR, addr >> 16,
+               CMD_ADDR, addr >> 8,
+               CMD_ADDR, addr >> 0,
+               CMD_WR | PAR_SINGE | PAR_MODE8,
+               d
+       };
+
+       write_serial(fd, cmd, sizeof(cmd));
+}
+
+static void write_bus16(int fd, uint32_t addr, uint16_t d)
 {
        uint8_t cmd[9] = {
                CMD_ADDR, addr >> 17,
@@ -157,42 +191,71 @@ static void write_word(int fd, uint32_t addr, uint16_t d)
        write_serial(fd, cmd, sizeof(cmd));
 }
 
-static void read_block(int fd, void *dst, uint32_t size)
+static void read_block8(int fd, void *dst, uint32_t size)
 {
+       // PAR_MODE8 does not work, so read as 16bit and throw away MSB
+       uint8_t tmp[0x10000], *d8 = dst;
        uint8_t cmd[5] = {
-               CMD_LEN, size >> 9,
-               CMD_LEN, size >> 1,
+               CMD_LEN, size >> 8,
+               CMD_LEN, size >> 0,
                CMD_RD | PAR_INC
        };
+       int i;
 
        assert(size <= 0x10000);
        write_serial(fd, cmd, sizeof(cmd));
        read_serial(fd, dst, size);
+       read_serial(fd, tmp, size);
+
+       for (i = 0; i < size / 2; i++)
+               d8[i] = d8[i * 2 + 1];
+       d8 += size / 2;
+       for (i = 0; i < size / 2; i++)
+               d8[i] = tmp[i * 2 + 1];
 }
 
-static uint16_t flash_seq_r(int fd, uint8_t cmd, uint32_t addr)
+static void read_block16(int fd, void *dst, uint32_t size)
 {
-       // unlock
-       write_word(fd, 0xaaa, 0xaa);
-       write_word(fd, 0x555, 0x55);
+       uint8_t cmd[5] = {
+               CMD_LEN, size >> 9,
+               CMD_LEN, size >> 1,
+               CMD_RD | PAR_INC
+       };
 
-       write_word(fd, 0xaaa, cmd);
-       return read_word(fd, addr);
+       assert(size <= 0x10000);
+       write_serial(fd, cmd, sizeof(cmd));
+       read_serial(fd, dst, size);
 }
 
-static void flash_seq_erase(int fd, uint32_t addr)
+static void flash_seq_write8(int fd, uint32_t addr, const uint8_t *d)
 {
-       // printf("erase %06x\n", addr);
-       write_word(fd, 0xaaa, 0xaa);
-       write_word(fd, 0x555, 0x55);
-       write_word(fd, 0xaaa, 0x80);
+       uint8_t cmd[] = {
+               // unlock
+               CMD_ADDR, 0,
+               CMD_ADDR, 0x0a,
+               CMD_ADDR, 0xaa,
+               CMD_WR | PAR_SINGE | PAR_MODE8, 0xaa,
+               CMD_ADDR, 0,
+               CMD_ADDR, 0x05,
+               CMD_ADDR, 0x55,
+               CMD_WR | PAR_SINGE | PAR_MODE8, 0x55,
+               // program setup
+               CMD_ADDR, 0,
+               CMD_ADDR, 0x0a,
+               CMD_ADDR, 0xaa,
+               CMD_WR | PAR_SINGE | PAR_MODE8, 0xa0,
+               // program data
+               CMD_ADDR, addr >> 16,
+               CMD_ADDR, addr >> 8,
+               CMD_ADDR, addr >> 0,
+               CMD_WR | PAR_SINGE | PAR_MODE8, *d,
+               CMD_RY
+       };
 
-       write_word(fd, 0xaaa, 0xaa);
-       write_word(fd, 0x555, 0x55);
-       write_word(fd, addr, 0x30);
+       write_serial(fd, cmd, sizeof(cmd));
 }
 
-static void flash_seq_write(int fd, uint32_t addr, uint8_t *d)
+static void flash_seq_write16(int fd, uint32_t addr, const uint8_t *d)
 {
        uint8_t cmd[] = {
                // unlock
@@ -220,6 +283,44 @@ static void flash_seq_write(int fd, uint32_t addr, uint8_t *d)
        write_serial(fd, cmd, sizeof(cmd));
 }
 
+static const struct iof
+{
+       void     (*set_addr)(int fd, uint32_t addr);
+       uint16_t (*read_bus)(int fd, uint32_t addr);
+       void     (*write_bus)(int fd, uint32_t addr, uint16_t d);
+       void     (*read_block)(int fd, void *dst, uint32_t size);
+       void     (*flash_seq_write)(int fd, uint32_t addr, const uint8_t *d);
+}
+io_ops[] =
+{
+       { set_addr8,  read_bus8,  write_bus8,  read_block8,  flash_seq_write8  },
+       { set_addr16, read_bus16, write_bus16, read_block16, flash_seq_write16 },
+};
+
+static const struct iof *io = &io_ops[1];
+
+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);
+
+       io->write_bus(fd, 0xaaa, cmd);
+       return io->read_bus(fd, addr);
+}
+
+static void flash_seq_erase(int fd, uint32_t addr)
+{
+       // printf("erase %06x\n", addr);
+       io->write_bus(fd, 0xaaa, 0xaa);
+       io->write_bus(fd, 0x555, 0x55);
+       io->write_bus(fd, 0xaaa, 0x80);
+
+       io->write_bus(fd, 0xaaa, 0xaa);
+       io->write_bus(fd, 0x555, 0x55);
+       io->write_bus(fd, addr, 0x30);
+}
+
 // status wait + dummy read to cause a wait?
 static uint16_t ry_read(int fd)
 {
@@ -259,29 +360,29 @@ static void read_info(int fd)
        uint32_t i, a;
 
        info.mid = flash_seq_r(fd, 0x90, 0); // autoselect
-       info.did = read_word(fd, 2);
+       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
-       write_word(fd, 0, 0xf0);
+       io->write_bus(fd, 0, 0xf0);
 
-       write_word(fd, 0xaa, 0x98); // CFI Query
-       resp[0] = read_word(fd, 0x20);
-       resp[1] = read_word(fd, 0x22);
-       resp[2] = read_word(fd, 0x24);
+       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.size = 1u << read_word(fd, 0x4e);
-       info.region_cnt = read_word(fd, 0x58);
+       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 = read_word(fd, a + 0) + 1;
-               info.region[i].block_count += read_word(fd, a + 2) << 8;
-               info.region[i].block_size = read_word(fd, a + 4) << 8;
-               info.region[i].block_size |= read_word(fd, a + 6) << 16;
+               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;
@@ -289,7 +390,7 @@ static void read_info(int fd)
                total += info.region[i].size;
        }
 
-       write_word(fd, 0, 0xf0); // flash reset
+       io->write_bus(fd, 0, 0xf0); // flash reset
 
        printf("Flash info:\n");
        printf("Manufacturer ID: %04x\n", info.mid);
@@ -328,10 +429,7 @@ static void print_progress(uint32_t done, uint32_t total)
 {
        int i, step;
 
-       printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
-       printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */
-       printf("\b\b\b\b\b\b");
-       printf("%06x/%06x |", done, total);
+       printf("\r%06x/%06x |", done, total);
 
        step = (total + 19) / 20;
        for (i = step; i <= total; i += step)
@@ -351,6 +449,7 @@ static void usage(const char *argv0)
                "  -w <file> [size]    flash the cart (file size)\n"
                "  -e <size>           erase (rounds to block size)\n"
                "  -a <start_address>  cart start address (default 0)\n"
+               "  -8                  8bit flash\n"
                "  -v                  verify written data\n"
                "  -i                  get info about the flash chip\n"
                , argv0);
@@ -389,6 +488,7 @@ int main(int argc, char *argv[])
        long a, a_blk, end;
        int do_info = 0;
        int do_verify = 0;
+       int write_step = 2;
        FILE *f_w = NULL;
        FILE *f_r = NULL;
        uint8_t id[2] = { 0, 0 };
@@ -435,6 +535,11 @@ int main(int argc, char *argv[])
                                invarg(argc, argv, arg);
                        continue;
                }
+               if (!strcmp(argv[arg], "-8")) {
+                       io = &io_ops[0];
+                       write_step = 1;
+                       continue;
+               }
                if (!strcmp(argv[arg], "-v")) {
                        do_verify = 1;
                        continue;
@@ -491,7 +596,7 @@ int main(int argc, char *argv[])
        printf("flashkit id: %02x\n", id[0]);
 
        set_delay(fd, 1);
-       write_word(fd, 0, 0xf0); // flash reset
+       io->write_bus(fd, 0, 0xf0); // flash reset
 
        if (do_info || size_e)
                read_info(fd);
@@ -520,24 +625,24 @@ int main(int argc, char *argv[])
                uint8_t b[2];
                set_delay(fd, 0);
                printf("writing %ld bytes:\n", size_w);
-               for (a = 0; a < size_w; a += 2) {
+               for (a = 0; a < size_w; a += write_step) {
                        ssize_t r;
 
                        b[1] = 0xff;
-                       len = min(size_w - a, 2);
+                       len = min(size_w - a, write_step);
                        r = fread(b, 1, len, f_w);
                        if (r != len) {
                                perror("\nfread");
                                return 1;
                        }
-                       flash_seq_write(fd, address_in + a, b);
+                       io->flash_seq_write(fd, address_in + a, b);
 
-                       if (!(a & 0x3fe))
+                       if (!(a & 0x3ff))
                                print_progress(a, size_w);
                }
                print_progress(a, size_w);
                rv = ry_read(fd);
-               if (rv != ((b[0] << 8) | b[1]))
+               if (write_step == 2 && rv != ((b[0] << 8) | b[1]))
                        fprintf(stderr, "warning: last bytes: %04x %02x%02x\n",
                                rv, b[0], b[1]);
                rewind(f_w);
@@ -561,9 +666,9 @@ int main(int argc, char *argv[])
 
                printf("reading %ld bytes:\n", max(size_r, size_v));
                print_progress(0, blks * sizeof(g_block));
-               set_addr(fd, address_in);
+               io->set_addr(fd, address_in);
                for (done = 0; done < size_r || done < size_v; ) {
-                       read_block(fd, g_block, sizeof(g_block));
+                       io->read_block(fd, g_block, sizeof(g_block));
                        if (f_r && done < size_r) {
                                len = min(size_r - done, sizeof(g_block));
                                if (fwrite(g_block, 1, len, f_r) != len) {