From d32c587511762ff4b15fd7e22a3cadcdcdc249de Mon Sep 17 00:00:00 2001 From: joerg_wunsch Date: Tue, 16 Jan 2018 21:17:04 +0000 Subject: [PATCH] Submitted by Jan Egil Ruud patch #9507: Fix UPDI chip erase * libavrdude.h (PROGRAMMER): add unlock method * avr.c (avr_unlock): Generic unlock function * jtag3.c: Implement unlock feature; avoid calling jtag3_edbg_prepare() and jtag3_edbg_signoff() on XplainedMini boards to work around a bug in early firmware versions; implement "userrow" memory region * main.c: Call avr_unlock() rather than avr_chip_erase() when encountering a locked UPDI chip git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1417 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 13 ++++++++ avr.c | 10 +++++++ jtag3.c | 84 +++++++++++++++++++++++++++++++++++++--------------- libavrdude.h | 3 ++ main.c | 2 +- 5 files changed, 87 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b2ba6d0..bf5dbffc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2018-01-16 Joerg Wunsch + + Submitted by Jan Egil Ruud + patch #9507: Fix UPDI chip erase + * libavrdude.h (PROGRAMMER): add unlock method + * avr.c (avr_unlock): Generic unlock function + * jtag3.c: Implement unlock feature; avoid calling + jtag3_edbg_prepare() and jtag3_edbg_signoff() on XplainedMini + boards to work around a bug in early firmware versions; + implement "userrow" memory region + * main.c: Call avr_unlock() rather than avr_chip_erase() when + encountering a locked UPDI chip + 2018-01-16 Joerg Wunsch Submitted by Nicolas BRULEZ diff --git a/avr.c b/avr.c index fa46f498..9abe6707 100644 --- a/avr.c +++ b/avr.c @@ -1195,6 +1195,16 @@ int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p) return rc; } +int avr_unlock(PROGRAMMER * pgm, AVRPART * p) +{ + int rc = -1; + + if (pgm->unlock) + rc = pgm->unlock(pgm, p); + + return rc; +} + /* * Report the progress of a read or write operation from/to the * device. diff --git a/jtag3.c b/jtag3.c index 1dbf3280..9460c168 100644 --- a/jtag3.c +++ b/jtag3.c @@ -864,9 +864,14 @@ int jtag3_getsync(PROGRAMMER * pgm, int mode) { avrdude_message(MSG_DEBUG, "%s: jtag3_getsync()\n", progname); + /* XplainedMini boards do not need this, and early revisions had a + * firmware bug where they complained about it. */ if (pgm->flag & PGM_FL_IS_EDBG) { - if (jtag3_edbg_prepare(pgm) < 0) - return -1; + if (strcmp(pgm->id, "xplainedmini_updi") != 0) { + if (jtag3_edbg_prepare(pgm) < 0) { + return -1; + } + } } /* Get the sign-on information. */ @@ -903,9 +908,9 @@ static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p) } /* - * UPDI 'chip erase' -> 'enter progmode' with chip erase key + * UPDI 'unlock' -> 'enter progmode' with chip erase key */ -static int jtag3_chip_erase_updi(PROGRAMMER * pgm, AVRPART * p) +static int jtag3_unlock_erase_key(PROGRAMMER * pgm, AVRPART * p) { unsigned char buf[8], *resp; @@ -1573,8 +1578,13 @@ void jtag3_close(PROGRAMMER * pgm) if (jtag3_command(pgm, buf, 4, &resp, "sign-off") >= 0) free(resp); - if (pgm->flag & PGM_FL_IS_EDBG) - jtag3_edbg_signoff(pgm); + /* XplainedMini boards do not need this, and early revisions had a + * firmware bug where they complained about it. */ + if (pgm->flag & PGM_FL_IS_EDBG) { + if (strcmp(pgm->id, "xplainedmini_updi") != 0) { + jtag3_edbg_signoff(pgm); + } + } serial_close(&pgm->fd); pgm->fd.ifd = -1; @@ -1636,8 +1646,13 @@ static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int status, dynamic_memtype = 0; long otimeout = serial_recv_timeout; - avrdude_message(MSG_NOTICE2, "%s: jtag3_paged_write(.., %s, %d, %d)\n", - progname, m->desc, page_size, n_bytes); + avrdude_message(MSG_NOTICE2, "%s: jtag3_paged_write(.., %s, %d, 0x%lx, %d)\n", + progname, m->desc, page_size, addr, n_bytes); + + block_size = jtag3_memaddr(pgm, p, m, addr); + if(block_size != addr) + avrdude_message(MSG_NOTICE2, " mapped to address: 0x%lx\n", block_size); + block_size = 0; if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0) return -1; @@ -1679,6 +1694,8 @@ static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) { cmd[3] = MTYPE_USERSIG; + } else if ( ( strcmp(m->desc, "userrow") == 0 ) ) { + cmd[3] = MTYPE_USERSIG; } else if ( ( strcmp(m->desc, "boot") == 0 ) ) { cmd[3] = MTYPE_BOOT_FLASH; } else if ( p->flags & AVRPART_HAS_PDI || p->flags & AVRPART_HAS_UPDI ) { @@ -1740,8 +1757,13 @@ static int jtag3_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int status, dynamic_memtype = 0; long otimeout = serial_recv_timeout; - avrdude_message(MSG_NOTICE2, "%s: jtag3_paged_load(.., %s, %d, %d)\n", - progname, m->desc, page_size, n_bytes); + avrdude_message(MSG_NOTICE2, "%s: jtag3_paged_load(.., %s, %d, 0x%lx, %d)\n", + progname, m->desc, page_size, addr, n_bytes); + + block_size = jtag3_memaddr(pgm, p, m, addr); + if(block_size != addr) + avrdude_message(MSG_NOTICE2, " mapped to address: 0x%lx\n", block_size); + block_size = 0; if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0) return -1; @@ -1765,6 +1787,8 @@ static int jtag3_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, cmd[3] = MTYPE_PRODSIG; } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) { cmd[3] = MTYPE_USERSIG; + } else if ( ( strcmp(m->desc, "userrow") == 0 ) ) { + cmd[3] = MTYPE_USERSIG; } else if ( ( strcmp(m->desc, "boot") == 0 ) ) { cmd[3] = MTYPE_BOOT_FLASH; } else if ( p->flags & AVRPART_HAS_PDI || p->flags & AVRPART_HAS_UPDI ) { @@ -1819,6 +1843,11 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, avrdude_message(MSG_NOTICE2, "%s: jtag3_read_byte(.., %s, 0x%lx, ...)\n", progname, mem->desc, addr); + paddr = jtag3_memaddr(pgm, p, mem, addr); + if(paddr != addr) + avrdude_message(MSG_NOTICE2, " mapped to address: 0x%lx\n", paddr); + paddr = 0; + if (!(pgm->flag & PGM_FL_IS_DW)) if ((status = jtag3_program_enable(pgm)) < 0) return status; @@ -1828,8 +1857,6 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, cmd[2] = 0; cmd[3] = ( p->flags & AVRPART_HAS_PDI || p->flags & AVRPART_HAS_UPDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE; - if (p->flags & AVRPART_HAS_UPDI) - addr += mem->offset; if (strcmp(mem->desc, "flash") == 0 || strcmp(mem->desc, "application") == 0 || strcmp(mem->desc, "apptable") == 0 || @@ -1874,6 +1901,8 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, addr = mem->offset & 7; } else if (strcmp(mem->desc, "usersig") == 0) { cmd[3] = MTYPE_USERSIG; + } else if (strcmp(mem->desc, "userrow") == 0) { + cmd[3] = MTYPE_USERSIG; } else if (strcmp(mem->desc, "prodsig") == 0) { cmd[3] = MTYPE_PRODSIG; } else if (strcmp(mem->desc, "calibration") == 0) { @@ -1892,11 +1921,7 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, * harm for other connection types either. */ u32_to_b4(cmd + 8, 3); - u32_to_b4(cmd + 4, mem->offset); - - if (p->flags & AVRPART_HAS_UPDI){ - addr -= mem->offset; - } + u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, mem, addr)); if (addr == 0) { if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0) @@ -1942,10 +1967,11 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, if (pagesize) { u32_to_b4(cmd + 8, pagesize); - u32_to_b4(cmd + 4, paddr); + u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, mem, paddr)); + } else { u32_to_b4(cmd + 8, 1); - u32_to_b4(cmd + 4, addr); + u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, mem, addr)); } if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0) @@ -1978,16 +2004,19 @@ static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned char *cache_ptr = 0; int status, unsupp = 0; unsigned int pagesize = 0; + unsigned long mapped_addr; avrdude_message(MSG_NOTICE2, "%s: jtag3_write_byte(.., %s, 0x%lx, ...)\n", progname, mem->desc, addr); + mapped_addr = jtag3_memaddr(pgm, p, mem, addr); + if(mapped_addr != addr) + avrdude_message(MSG_NOTICE2, " mapped to address: 0x%lx\n", mapped_addr); + cmd[0] = SCOPE_AVR; cmd[1] = CMD3_WRITE_MEMORY; cmd[2] = 0; cmd[3] = ( p->flags & AVRPART_HAS_PDI || p->flags & AVRPART_HAS_UPDI ) ? MTYPE_FLASH : MTYPE_SPM; - if (p->flags & AVRPART_HAS_UPDI) - addr += mem->offset; if (strcmp(mem->desc, "flash") == 0) { cache_ptr = PDATA(pgm)->flash_pagecache; pagesize = PDATA(pgm)->flash_pagesize; @@ -2070,7 +2099,7 @@ static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, return -1; u32_to_b4(cmd + 8, 1); - u32_to_b4(cmd + 4, addr); + u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, mem, addr)); cmd[12] = 0; cmd[13] = data; @@ -2325,7 +2354,13 @@ static unsigned int jtag3_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, uns * Non-Xmega device. */ if (p->flags & AVRPART_HAS_UPDI) { - if (strcmp(m->desc, "flash") != 0) { + if (strcmp(m->desc, "fuses") == 0) { + addr += m->offset; + } + else if (strncmp(m->desc, "fuse", strlen("fuse")) == 0) { + addr = m->offset; + } + else if (strcmp(m->desc, "flash") != 0) { addr += m->offset; } } @@ -2448,7 +2483,7 @@ void jtag3_updi_initpgm(PROGRAMMER * pgm) pgm->enable = jtag3_enable; pgm->disable = jtag3_disable; pgm->program_enable = jtag3_program_enable_dummy; - pgm->chip_erase = jtag3_chip_erase_updi; + pgm->chip_erase = jtag3_chip_erase; pgm->open = jtag3_open_updi; pgm->close = jtag3_close; pgm->read_byte = jtag3_read_byte; @@ -2466,6 +2501,7 @@ void jtag3_updi_initpgm(PROGRAMMER * pgm) pgm->teardown = jtag3_teardown; pgm->page_size = 256; pgm->flag = PGM_FL_IS_UPDI; + pgm->unlock = jtag3_unlock_erase_key; pgm->read_sib = jtag3_read_sib; } diff --git a/libavrdude.h b/libavrdude.h index 7ba3a719..b80ad797 100644 --- a/libavrdude.h +++ b/libavrdude.h @@ -647,6 +647,7 @@ typedef struct programmer_t { void (*powerdown) (struct programmer_t * pgm); int (*program_enable) (struct programmer_t * pgm, AVRPART * p); int (*chip_erase) (struct programmer_t * pgm, AVRPART * p); + int (*unlock) (struct programmer_t * pgm, AVRPART * p); int (*cmd) (struct programmer_t * pgm, const unsigned char *cmd, unsigned char *res); int (*cmd_tpi) (struct programmer_t * pgm, const unsigned char *cmd, @@ -764,6 +765,8 @@ int avr_mem_hiaddr(AVRMEM * mem); int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p); +int avr_unlock(PROGRAMMER * pgm, AVRPART * p); + void report_progress (int completed, int total, char *hdr); #ifdef __cplusplus diff --git a/main.c b/main.c index 4521aea5..1de907c8 100644 --- a/main.c +++ b/main.c @@ -1077,7 +1077,7 @@ int main(int argc, char * argv []) if (quell_progress < 2) { avrdude_message(MSG_INFO, "%s: erasing chip\n", progname); } - exitrc = avr_chip_erase(pgm, p); + exitrc = avr_unlock(pgm, p); if(exitrc) goto main_exit; goto sig_again; }