diff options
Diffstat (limited to 'spi25.c')
-rw-r--r-- | spi25.c | 267 |
1 files changed, 153 insertions, 114 deletions
@@ -27,6 +27,26 @@ #include "programmer.h" #include "spi.h" +enum id_type { + RDID, + RDID4, + REMS, + RES2, + RES3, + NUM_ID_TYPES, +}; + +static struct { + bool is_cached; + unsigned char bytes[4]; /* enough to hold largest ID type */ +} id_cache[NUM_ID_TYPES]; + +void clear_spi_id_cache(void) +{ + memset(id_cache, 0, sizeof(id_cache)); + return; +} + static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes) { static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID }; @@ -93,19 +113,9 @@ int spi_write_disable(struct flashctx *flash) return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); } -static int probe_spi_rdid_generic(struct flashctx *flash, int bytes) +static void rdid_get_ids(unsigned char *readarr, int bytes, + uint32_t *id1, uint32_t *id2) { - const struct flashchip *chip = flash->chip; - unsigned char readarr[4]; - uint32_t id1; - uint32_t id2; - - const int ret = spi_rdid(flash, readarr, bytes); - if (ret == SPI_INVALID_LENGTH) - msg_cinfo("%d byte RDID not supported on this SPI controller\n", bytes); - if (ret) - return 0; - if (!oddparity(readarr[0])) msg_cdbg("RDID byte 0 parity violation. "); @@ -115,19 +125,23 @@ static int probe_spi_rdid_generic(struct flashctx *flash, int bytes) if (readarr[0] == 0x7f) { if (!oddparity(readarr[1])) msg_cdbg("RDID byte 1 parity violation. "); - id1 = (readarr[0] << 8) | readarr[1]; - id2 = readarr[2]; + *id1 = (readarr[0] << 8) | readarr[1]; + *id2 = readarr[2]; if (bytes > 3) { - id2 <<= 8; - id2 |= readarr[3]; + *id2 <<= 8; + *id2 |= readarr[3]; } } else { - id1 = readarr[0]; - id2 = (readarr[1] << 8) | readarr[2]; + *id1 = readarr[0]; + *id2 = (readarr[1] << 8) | readarr[2]; } +} - msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); +static int compare_id(const struct flashctx *flash, uint32_t id1, uint32_t id2) +{ + const struct flashchip *chip = flash->chip; + msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2); if (id1 == chip->manufacture_id && id2 == chip->model_id) return 1; @@ -142,6 +156,24 @@ static int probe_spi_rdid_generic(struct flashctx *flash, int bytes) return 0; } +static int probe_spi_rdid_generic(struct flashctx *flash, int bytes) +{ + uint32_t id1, id2; + enum id_type idty = bytes == 3 ? RDID : RDID4; + + if (!id_cache[idty].is_cached) { + const int ret = spi_rdid(flash, id_cache[idty].bytes, bytes); + if (ret == SPI_INVALID_LENGTH) + msg_cinfo("%d byte RDID not supported on this SPI controller\n", bytes); + if (ret) + return 0; + id_cache[idty].is_cached = true; + } + + rdid_get_ids(id_cache[idty].bytes, bytes, &id1, &id2); + return compare_id(flash, id1, id2); +} + int probe_spi_rdid(struct flashctx *flash) { return probe_spi_rdid_generic(flash, 3); @@ -154,31 +186,17 @@ int probe_spi_rdid4(struct flashctx *flash) int probe_spi_rems(struct flashctx *flash) { - const struct flashchip *chip = flash->chip; - unsigned char readarr[JEDEC_REMS_INSIZE]; uint32_t id1, id2; - if (spi_rems(flash, readarr)) { - return 0; + if (!id_cache[REMS].is_cached) { + if (spi_rems(flash, id_cache[REMS].bytes)) + return 0; + id_cache[REMS].is_cached = true; } - id1 = readarr[0]; - id2 = readarr[1]; - - msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); - - if (id1 == chip->manufacture_id && id2 == chip->model_id) - return 1; - - /* Test if this is a pure vendor match. */ - if (id1 == chip->manufacture_id && GENERIC_DEVICE_ID == chip->model_id) - return 1; - - /* Test if there is any vendor ID. */ - if (GENERIC_MANUF_ID == chip->manufacture_id && id1 != 0xff && id1 != 0x00) - return 1; - - return 0; + id1 = id_cache[REMS].bytes[0]; + id2 = id_cache[REMS].bytes[1]; + return compare_id(flash, id1, id2); } int probe_spi_res1(struct flashctx *flash) @@ -214,7 +232,7 @@ int probe_spi_res1(struct flashctx *flash) id2 = readarr[0]; - msg_cdbg("%s: id 0x%x\n", __func__, id2); + msg_cdbg("%s: id 0x%"PRIx32"\n", __func__, id2); if (id2 != flash->chip->model_id) return 0; @@ -224,17 +242,17 @@ int probe_spi_res1(struct flashctx *flash) int probe_spi_res2(struct flashctx *flash) { - unsigned char readarr[2]; uint32_t id1, id2; - if (spi_res(flash, readarr, 2)) { - return 0; + if (!id_cache[RES2].is_cached) { + if (spi_res(flash, id_cache[RES2].bytes, 2)) + return 0; + id_cache[RES2].is_cached = true; } - id1 = readarr[0]; - id2 = readarr[1]; - - msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); + id1 = id_cache[RES2].bytes[0]; + id2 = id_cache[RES2].bytes[1]; + msg_cdbg("%s: id1 0x%"PRIx32", id2 0x%"PRIx32"\n", __func__, id1, id2); if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id) return 0; @@ -244,17 +262,17 @@ int probe_spi_res2(struct flashctx *flash) int probe_spi_res3(struct flashctx *flash) { - unsigned char readarr[3]; uint32_t id1, id2; - if (spi_res(flash, readarr, 3)) { - return 0; + if (!id_cache[RES3].is_cached) { + if (spi_res(flash, id_cache[RES3].bytes, 3)) + return 0; + id_cache[RES3].is_cached = true; } - id1 = (readarr[0] << 8) | readarr[1]; - id2 = readarr[2]; - - msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); + id1 = (id_cache[RES3].bytes[0] << 8) | id_cache[RES3].bytes[1]; + id2 = id_cache[RES3].bytes[3]; + msg_cdbg("%s: id1 0x%"PRIx32", id2 0x%"PRIx32"\n", __func__, id1, id2); if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id) return 0; @@ -276,7 +294,7 @@ int probe_spi_at25f(struct flashctx *flash) id1 = readarr[0]; id2 = readarr[1]; - msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); + msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2); if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id) return 1; @@ -286,12 +304,17 @@ int probe_spi_at25f(struct flashctx *flash) static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay) { - /* FIXME: We can't tell if spi_read_status_register() failed. */ /* FIXME: We don't time out. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(poll_delay); - /* FIXME: Check the status register for errors. */ - return 0; + while (true) { + uint8_t status; + int ret = spi_read_register(flash, STATUS1, &status); + if (ret) + return ret; + if (!(status & SPI_SR_WIP)) + return 0; + + programmer_delay(flash, poll_delay); + } } /** @@ -307,7 +330,7 @@ static int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, struct spi_command cmds[] = { { .readarr = 0, - .writecnt = 1, + .writecnt = JEDEC_WREN_OUTSIZE, .writearr = (const unsigned char[]){ JEDEC_WREN }, }, { .readarr = 0, @@ -328,7 +351,16 @@ static int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata) { - const uint8_t op = flash->chip->wrea_override ? : JEDEC_WRITE_EXT_ADDR_REG; + uint8_t op; + if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) { + op = JEDEC_WRITE_EXT_ADDR_REG; + } else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) { + op = ALT_WRITE_EXT_ADDR_REG_17; + } else { + msg_cerr("Flash misses feature flag for extended-address register.\n"); + return -1; + } + struct spi_command cmds[] = { { .readarr = 0, @@ -371,7 +403,7 @@ static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[], cmd_buf[4] = (addr >> 0) & 0xff; return 4; } else { - if (flash->chip->feature_bits & FEATURE_4BA_EXT_ADDR) { + if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) { if (spi_set_extended_address(flash, addr >> 24)) return -1; } else if (addr >> 24) { @@ -427,6 +459,8 @@ static int spi_write_cmd(struct flashctx *const flash, const uint8_t op, msg_cerr("%s called for too long a write\n", __func__); return 1; } + if (!out_bytes && out_len > 0) + return 1; memcpy(cmd + 1 + addr_len, out_bytes, out_len); cmds[1].writecnt = 1 + addr_len + out_len; @@ -443,26 +477,26 @@ static int spi_write_cmd(struct flashctx *const flash, const uint8_t op, static int spi_chip_erase_60(struct flashctx *flash) { /* This usually takes 1-85s, so wait in 1s steps. */ - return spi_simple_write_cmd(flash, 0x60, 1000 * 1000); + return spi_simple_write_cmd(flash, JEDEC_CE_60, 1000 * 1000); } static int spi_chip_erase_62(struct flashctx *flash) { /* This usually takes 2-5s, so wait in 100ms steps. */ - return spi_simple_write_cmd(flash, 0x62, 100 * 1000); + return spi_simple_write_cmd(flash, JEDEC_CE_62, 100 * 1000); } static int spi_chip_erase_c7(struct flashctx *flash) { /* This usually takes 1-85s, so wait in 1s steps. */ - return spi_simple_write_cmd(flash, 0xc7, 1000 * 1000); + return spi_simple_write_cmd(flash, JEDEC_CE_C7, 1000 * 1000); } int spi_block_erase_52(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 100-4000ms, so wait in 100ms steps. */ - return spi_write_cmd(flash, 0x52, false, addr, NULL, 0, 100 * 1000); + return spi_write_cmd(flash, JEDEC_BE_52, false, addr, NULL, 0, 100 * 1000); } /* Block size is usually @@ -471,7 +505,7 @@ int spi_block_erase_52(struct flashctx *flash, unsigned int addr, int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 240-480s, so wait in 500ms steps. */ - return spi_write_cmd(flash, 0xc4, false, addr, NULL, 0, 500 * 1000); + return spi_write_cmd(flash, JEDEC_BE_C4, false, addr, NULL, 0, 500 * 1000); } /* Block size is usually @@ -483,7 +517,7 @@ int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 100-4000ms, so wait in 100ms steps. */ - return spi_write_cmd(flash, 0xd8, false, addr, NULL, 0, 100 * 1000); + return spi_write_cmd(flash, JEDEC_BE_D8, false, addr, NULL, 0, 100 * 1000); } /* Block size is usually @@ -493,7 +527,7 @@ int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 100-4000ms, so wait in 100ms steps. */ - return spi_write_cmd(flash, 0xd7, false, addr, NULL, 0, 100 * 1000); + return spi_write_cmd(flash, JEDEC_BE_D7, false, addr, NULL, 0, 100 * 1000); } /* Page erase (usually 256B blocks) */ @@ -509,19 +543,19 @@ int spi_block_erase_20(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 15-800ms, so wait in 10ms steps. */ - return spi_write_cmd(flash, 0x20, false, addr, NULL, 0, 10 * 1000); + return spi_write_cmd(flash, JEDEC_SE, false, addr, NULL, 0, 10 * 1000); } int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 10ms, so wait in 1ms steps. */ - return spi_write_cmd(flash, 0x50, false, addr, NULL, 0, 1 * 1000); + return spi_write_cmd(flash, JEDEC_BE_50, false, addr, NULL, 0, 1 * 1000); } int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 8ms, so wait in 1ms steps. */ - return spi_write_cmd(flash, 0x81, false, addr, NULL, 0, 1 * 1000); + return spi_write_cmd(flash, JEDEC_BE_81, false, addr, NULL, 0, 1 * 1000); } int spi_block_erase_60(struct flashctx *flash, unsigned int addr, @@ -564,6 +598,13 @@ int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int b } /* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */ +int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen) +{ + /* This usually takes 100-4000ms, so wait in 100ms steps. */ + return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000); +} + +/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */ int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { /* This usually takes 100-4000ms, so wait in 100ms steps. */ @@ -577,46 +618,37 @@ int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int b return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000); } -erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode) -{ - switch(opcode){ - case 0xff: - case 0x00: - /* Not specified, assuming "not supported". */ - return NULL; - case 0x20: - return &spi_block_erase_20; - case 0x21: - return &spi_block_erase_21; - case 0x50: - return &spi_block_erase_50; - case 0x52: - return &spi_block_erase_52; - case 0x5c: - return &spi_block_erase_5c; - case 0x60: - return &spi_block_erase_60; - case 0x62: - return &spi_block_erase_62; - case 0x81: - return &spi_block_erase_81; - case 0xc4: - return &spi_block_erase_c4; - case 0xc7: - return &spi_block_erase_c7; - case 0xd7: - return &spi_block_erase_d7; - case 0xd8: - return &spi_block_erase_d8; - case 0xdb: - return &spi_block_erase_db; - case 0xdc: - return &spi_block_erase_dc; - default: - msg_cinfo("%s: unknown erase opcode (0x%02x). Please report " - "this at flashrom@flashrom.org\n", __func__, opcode); - return NULL; +static const struct { + enum block_erase_func func; + uint8_t opcode; +} spi25_function_opcode_list[] = { + {SPI_BLOCK_ERASE_20, 0x20}, + {SPI_BLOCK_ERASE_21, 0x21}, + {SPI_BLOCK_ERASE_50, 0x50}, + {SPI_BLOCK_ERASE_52, 0x52}, + {SPI_BLOCK_ERASE_53, 0x53}, + {SPI_BLOCK_ERASE_5C, 0x5c}, + {SPI_BLOCK_ERASE_60, 0x60}, + {SPI_BLOCK_ERASE_62, 0x62}, + {SPI_BLOCK_ERASE_81, 0x81}, + {SPI_BLOCK_ERASE_C4, 0xc4}, + {SPI_BLOCK_ERASE_C7, 0xc7}, + {SPI_BLOCK_ERASE_D7, 0xd7}, + {SPI_BLOCK_ERASE_D8, 0xd8}, + {SPI_BLOCK_ERASE_DB, 0xdb}, + {SPI_BLOCK_ERASE_DC, 0xdc}, +}; + +enum block_erase_func spi25_get_erasefn_from_opcode(uint8_t opcode) +{ + size_t i; + for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) { + if (spi25_function_opcode_list[i].opcode == opcode) + return spi25_function_opcode_list[i].func; } + msg_cinfo("%s: unknown erase opcode (0x%02x). Please report " + "this at flashrom@flashrom.org\n", __func__, opcode); + return NO_BLOCK_ERASE_FUNC; } static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len) @@ -629,7 +661,7 @@ static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const ui int spi_nbyte_read(struct flashctx *flash, unsigned int address, uint8_t *bytes, unsigned int len) { - const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash); + const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash); uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN] = { native_4ba ? JEDEC_READ_4BA : JEDEC_READ, }; const int addr_len = spi_prepare_address(flash, cmd, native_4ba, address); @@ -649,11 +681,14 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, { int ret; size_t to_read; + size_t start_address = start; + size_t end_address = len - start; for (; len; len -= to_read, buf += to_read, start += to_read) { to_read = min(chunksize, len); ret = spi_nbyte_read(flash, start, buf, to_read); if (ret) return ret; + update_progress(flash, FLASHROM_PROGRESS_READ, start - start_address + to_read, end_address); } return 0; } @@ -673,6 +708,8 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s * we're OK for now. */ unsigned int page_size = flash->chip->page_size; + size_t start_address = start; + size_t end_address = len - start; /* Warning: This loop has a very unusual condition and body. * The loop needs to go through each page with at least one affected @@ -697,6 +734,7 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s if (rc) return rc; } + update_progress(flash, FLASHROM_PROGRESS_WRITE, start - start_address + lenhere, end_address); } return 0; @@ -716,6 +754,7 @@ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int st for (i = start; i < start + len; i++) { if (spi_nbyte_program(flash, i, buf + i - start, 1)) return 1; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i - start, len - start); } return 0; } |