X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fflash%2Fcfi.c;h=93e661c2f2eb5edc6286043c698f87672b7cbf3f;hb=fc116380bf26ac00b8d0a37fee91e74118e12d8d;hp=ffc9d27069f7bbec08d3fff649e9719fd7b58ac5;hpb=8e39f86ef493a4bcae622d220245398fb7a517b3;p=openocd diff --git a/src/flash/cfi.c b/src/flash/cfi.c index ffc9d270..93e661c2 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -641,8 +641,12 @@ static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, return ERROR_FLASH_BANK_INVALID; } - if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH) - || (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH)) + uint16_t chip_width, bus_width; + COMMAND_PARSE_NUMBER(u16, args[3], bus_width); + COMMAND_PARSE_NUMBER(u16, args[4], chip_width); + + if ((chip_width > CFI_MAX_CHIP_WIDTH) + || (bus_width > CFI_MAX_BUS_WIDTH)) { LOG_ERROR("chip and bus width have to specified in bytes"); return ERROR_FLASH_BANK_INVALID; @@ -2143,6 +2147,45 @@ static void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param) pri_ext->_unlock2 = unlock_addresses->unlock2; } + +static int cfi_query_string(struct flash_bank_s *bank, int address) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + int retval; + uint8_t command[8]; + + cfi_command(bank, 0x98, command); + if ((retval = target_write_memory(target, flash_address(bank, 0, address), bank->bus_width, 1, command)) != ERROR_OK) + { + return retval; + } + + cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10); + cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11); + cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12); + + LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); + + if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) + { + cfi_command(bank, 0xf0, command); + if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) + { + return retval; + } + cfi_command(bank, 0xff, command); + if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) + { + return retval; + } + LOG_ERROR("Could not probe bank: no QRY"); + return ERROR_FLASH_BANK_INVALID; + } + + return ERROR_OK; +} + static int cfi_probe(struct flash_bank_s *bank) { cfi_flash_bank_t *cfi_info = bank->driver_priv; @@ -2236,6 +2279,8 @@ static int cfi_probe(struct flash_bank_s *bank) */ if (cfi_info->not_cfi == 0) { + int retval; + /* enter CFI query mode * according to JEDEC Standard No. 68.01, * a single bus sequence with address = 0x55, data = 0x98 should put @@ -2243,33 +2288,21 @@ static int cfi_probe(struct flash_bank_s *bank) * * SST flashes clearly violate this, and we will consider them incompatbile for now */ - cfi_command(bank, 0x98, command); - if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK) - { - return retval; - } - cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10); - cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11); - cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12); - - LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); - - if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) + retval = cfi_query_string(bank, 0x55); + if (retval != ERROR_OK) { - cfi_command(bank, 0xf0, command); - if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) - { - return retval; - } - cfi_command(bank, 0xff, command); - if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) - { - return retval; - } - LOG_ERROR("Could not probe bank: no QRY"); - return ERROR_FLASH_BANK_INVALID; + /* + * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should + * be harmless enough: + * + * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html + */ + LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY."); + retval = cfi_query_string(bank, 0x555); } + if (retval != ERROR_OK) + return retval; cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13); cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);