From b4077314730d283936fd85d517c693b1f3f11beb Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sat, 24 Aug 2024 17:43:37 +0100 Subject: [PATCH 1/4] Refrain from using page_erase on -U eeprom:w --- src/avr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avr.c b/src/avr.c index ea3f24314..f8fb74402 100644 --- a/src/avr.c +++ b/src/avr.c @@ -1120,7 +1120,7 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int if(need_write) { int rc = 0; - if(auto_erase && pgm->page_erase) + if(auto_erase && pgm->page_erase && !mem_is_eeprom(cm)) rc = pgm->page_erase(pgm, p, cm, pageaddr); if(rc >= 0) rc = pgm->paged_write(pgm, p, cm, cm->page_size, pageaddr, cm->page_size); From 93b512de70c104004a99e97ad1468598eee6f253 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sat, 24 Aug 2024 17:47:00 +0100 Subject: [PATCH 2/4] Change memory category for classic page erase in jtag3.c --- src/jtag3.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/jtag3.c b/src/jtag3.c index bda8bd8e1..a524f8a05 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -1864,7 +1864,6 @@ void jtag3_close(PROGRAMMER *pgm) { } static int jtag3_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int addr) { - unsigned char cmd[8], *resp; pmsg_notice2("jtag3_page_erase(.., %s, 0x%x)\n", m->desc, addr); @@ -1882,7 +1881,7 @@ static int jtag3_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRME cmd[2] = 0; if(mem_is_in_flash(m)) { - cmd[3] = is_updi(p) || jtag3_mtype(pgm, p, m, addr) == MTYPE_FLASH? XMEGA_ERASE_APP_PAGE: XMEGA_ERASE_BOOT_PAGE; + cmd[3] = !is_pdi(p) || jtag3_mtype(pgm, p, m, addr) == MTYPE_FLASH? XMEGA_ERASE_APP_PAGE: XMEGA_ERASE_BOOT_PAGE; my.flash_pageaddr = ~0UL; } else if(mem_is_eeprom(m)) { cmd[3] = XMEGA_ERASE_EEPROM_PAGE; @@ -1935,8 +1934,7 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM if(mem_is_flash(m)) { my.flash_pageaddr = ~0UL; cmd[3] = jtag3_mtype(pgm, p, m, addr); - if(is_pdi(p)) - // Dynamically decide between flash/boot mtype + if(is_pdi(p)) // Dynamically decide between flash/boot mtype dynamic_mtype = 1; } else if(mem_is_eeprom(m)) { if(pgm->flag & PGM_FL_IS_DW) { @@ -2765,11 +2763,11 @@ static void jtag3_print_parms(const PROGRAMMER *pgm, FILE *fp) { } static unsigned char jtag3_mtype(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr) { - return !is_pdi(p)? MTYPE_FLASH_PAGE: mem_is_boot(m)? MTYPE_BOOT_FLASH: - mem_is_flash(m) && is_pdi(p) && addr >= my.boot_start? MTYPE_BOOT_FLASH: MTYPE_FLASH; + mem_is_flash(m) && addr >= my.boot_start? MTYPE_BOOT_FLASH: + MTYPE_FLASH; } static unsigned int jtag3_memaddr(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr) { From 0c463fad9241546021b17fb9eed5d2d53175e6e8 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sat, 24 Aug 2024 17:56:32 +0100 Subject: [PATCH 3/4] Fix page erase for jtagmkII There were several problems with page_erase(): - Not working on UPDI eeprom/usersig memories: write a page of 0xff instead - Read cache not invalidated on page erase - PDI apptable and boot memories page erase possibly erases wrong page --- src/jtagmkII.c | 57 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/jtagmkII.c b/src/jtagmkII.c index 2b0eb7ea8..e9a198308 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -146,7 +146,7 @@ static int jtagmkII_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned static void jtagmkII_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); -static unsigned char jtagmkII_mtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr); +static unsigned char jtagmkII_mtype(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr); static unsigned int jtagmkII_memaddr(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr); // AVR32 @@ -1758,7 +1758,7 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV pmsg_notice2("jtagmkII_page_erase(.., %s, 0x%x)\n", m->desc, addr); if(is_classic(p) && !mem_is_userrow(m)) { - pmsg_error("page erase only available for AVR8X/XMEGAs or classic-part usersig mem\n"); + pmsg_error("page erase only available for UPDI/XMEGAs or for classic usersig mem\n"); return -1; } if((pgm->flag & PGM_FL_IS_DW)) { @@ -1766,21 +1766,31 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV return -1; } + // EEPROM/usersig page erase not implemented in jtagmkII UPDI programmers: write a page of 0xFF + if(is_updi(p) && (mem_is_eeprom(m) || mem_is_usersig(m)) && + m->page_size > 0 && !(m->page_size & (m->page_size-1)) && m->size > 0) { + + unsigned char *page = mmt_malloc(m->page_size); + memset(page, 0xff, m->page_size); + int rc = avr_write_page_default(pgm, p, m, addr, page); + mmt_free(page); + my.eeprom_pageaddr = ~0UL; + + return rc; + } + if(jtagmkII_program_enable(pgm) < 0) return -1; cmd[0] = CMND_XMEGA_ERASE; - if(mem_is_flash(m)) { - if(jtagmkII_mtype(pgm, p, addr) == MTYPE_FLASH) - cmd[1] = XMEGA_ERASE_APP_PAGE; - else - cmd[1] = XMEGA_ERASE_BOOT_PAGE; + if(mem_is_in_flash(m)) { + cmd[1] = jtagmkII_mtype(pgm, p, m, addr) == MTYPE_BOOT_FLASH? XMEGA_ERASE_BOOT_PAGE: XMEGA_ERASE_APP_PAGE; + my.flash_pageaddr = ~0UL; } else if(mem_is_eeprom(m)) { cmd[1] = XMEGA_ERASE_EEPROM_PAGE; + my.eeprom_pageaddr = ~0UL; } else if(mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[1] = XMEGA_ERASE_USERSIG; - } else if(mem_is_boot(m)) { - cmd[1] = XMEGA_ERASE_BOOT_PAGE; } else { cmd[1] = XMEGA_ERASE_APP_PAGE; } @@ -1792,6 +1802,12 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV * commands make an exception, and do require the NVM offsets as part of the * (page) address. */ + if(is_pdi(p) && mem_is_in_flash(m)) { + if(addr >= my.boot_start) // Boot is special and gets its own region + addr -= my.boot_start; + if(!mem_is_boot(m)) // Apptable, application and flash + addr += avr_flash_offset(p, m, addr); + } u32_to_b4(cmd + 2, addr + m->offset); tries = 0; @@ -1853,7 +1869,7 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A cmd[0] = CMND_WRITE_MEMORY; if(mem_is_flash(m)) { my.flash_pageaddr = ~0UL; - cmd[1] = jtagmkII_mtype(pgm, p, addr); + cmd[1] = jtagmkII_mtype(pgm, p, m, addr); if(p->prog_modes & (PM_PDI | PM_UPDI)) // Dynamically decide between flash/boot mtype dynamic_mtype = 1; } else if(mem_is_eeprom(m)) { @@ -1892,7 +1908,7 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size); if(dynamic_mtype) - cmd[1] = jtagmkII_mtype(pgm, p, addr); + cmd[1] = jtagmkII_mtype(pgm, p, m, addr); u32_to_b4(cmd + 2, page_size); u32_to_b4(cmd + 6, jtagmkII_memaddr(pgm, p, m, addr)); @@ -1966,7 +1982,7 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV cmd[0] = CMND_READ_MEMORY; if(mem_is_flash(m)) { - cmd[1] = jtagmkII_mtype(pgm, p, addr); + cmd[1] = jtagmkII_mtype(pgm, p, m, addr); if(p->prog_modes & (PM_PDI | PM_UPDI)) // Dynamically decide between flash/boot mtype dynamic_mtype = 1; } else if(mem_is_eeprom(m)) { @@ -1993,7 +2009,7 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV pmsg_debug("%s(): block_size at addr %d is %d\n", __func__, addr, block_size); if(dynamic_mtype) - cmd[1] = jtagmkII_mtype(pgm, p, addr); + cmd[1] = jtagmkII_mtype(pgm, p, m, addr); u32_to_b4(cmd + 2, block_size); u32_to_b4(cmd + 6, jtagmkII_memaddr(pgm, p, m, addr)); @@ -2579,15 +2595,12 @@ static void jtagmkII_print_parms(const PROGRAMMER *pgm, FILE *fp) { jtagmkII_print_parms1(pgm, "", fp); } -static unsigned char jtagmkII_mtype(const PROGRAMMER *pgm, const AVRPART *p, unsigned long addr) { - if(p->prog_modes & (PM_PDI | PM_UPDI)) { - if(addr >= my.boot_start) - return MTYPE_BOOT_FLASH; - else - return MTYPE_FLASH; - } else { - return MTYPE_FLASH_PAGE; - } +static unsigned char jtagmkII_mtype(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr) { + return + !is_pdi(p) && !is_updi(p)? MTYPE_FLASH_PAGE: + mem_is_boot(m)? MTYPE_BOOT_FLASH: + mem_is_flash(m) && is_pdi(p) && addr >= my.boot_start? MTYPE_BOOT_FLASH: + MTYPE_FLASH; } static unsigned int jtagmkII_memaddr(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr) { From 19279e33f82a66381e3c34286856e65e7dba547f Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sat, 24 Aug 2024 18:04:08 +0100 Subject: [PATCH 4/4] Fix flash paged r/w for jtagmkII There were several problems with page_erase(): - Read cache not invalidated on writes to boot and apptable - PDI apptable and boot memories paged access can get addresses wrong --- src/jtagmkII.c | 49 ++++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/jtagmkII.c b/src/jtagmkII.c index e9a198308..f0dfb516b 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -1867,20 +1867,16 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A cmd = mmt_malloc(page_size + 10); cmd[0] = CMND_WRITE_MEMORY; - if(mem_is_flash(m)) { + if(mem_is_in_flash(m)) { my.flash_pageaddr = ~0UL; cmd[1] = jtagmkII_mtype(pgm, p, m, addr); - if(p->prog_modes & (PM_PDI | PM_UPDI)) // Dynamically decide between flash/boot mtype + if(is_pdi(p)) // Dynamically decide between flash/boot mtype dynamic_mtype = 1; } else if(mem_is_eeprom(m)) { if(pgm->flag & PGM_FL_IS_DW) { - /* - * jtagmkII_paged_write() to EEPROM attempted while in DW mode. Use - * jtagmkII_write_byte() instead. - */ + // Cannot use paged write to EEPROM in DW mode; use jtagmkII_write_byte() instead for(; addr < maxaddr; addr++) { - status = jtagmkII_write_byte(pgm, p, m, addr, m->buf[addr]); - if(status < 0) { + if(jtagmkII_write_byte(pgm, p, m, addr, m->buf[addr]) < 0) { mmt_free(cmd); return -1; } @@ -1892,8 +1888,6 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A my.eeprom_pageaddr = ~0UL; } else if(mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[1] = MTYPE_USERSIG; - } else if(mem_is_boot(m)) { - cmd[1] = MTYPE_BOOT_FLASH; } else if(p->prog_modes & (PM_PDI | PM_UPDI)) { cmd[1] = MTYPE_FLASH; } else { @@ -1981,9 +1975,9 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV page_size = m->readsize; cmd[0] = CMND_READ_MEMORY; - if(mem_is_flash(m)) { + if(mem_is_in_flash(m)) { cmd[1] = jtagmkII_mtype(pgm, p, m, addr); - if(p->prog_modes & (PM_PDI | PM_UPDI)) // Dynamically decide between flash/boot mtype + if(is_pdi(p)) // Dynamically decide between flash/boot mtype dynamic_mtype = 1; } else if(mem_is_eeprom(m)) { cmd[1] = p->prog_modes & (PM_PDI | PM_UPDI)? MTYPE_EEPROM: MTYPE_EEPROM_PAGE; @@ -1993,8 +1987,6 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV cmd[1] = MTYPE_PRODSIG; } else if(mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[1] = MTYPE_USERSIG; - } else if(mem_is_boot(m)) { - cmd[1] = MTYPE_BOOT_FLASH; } else if(p->prog_modes & (PM_PDI | PM_UPDI)) { cmd[1] = MTYPE_FLASH; } else { @@ -2265,8 +2257,7 @@ static int jtagmkII_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AV cmd[0] = CMND_WRITE_MEMORY; cmd[1] = p->prog_modes & (PM_PDI | PM_UPDI)? MTYPE_FLASH: MTYPE_SPM; if(mem_is_flash(mem)) { - if((addr & 1) == 1) { - // Odd address = high byte + if(addr & 1) { // Odd address = high byte writedata = 0xFF; // Don't modify the low byte writedata2 = data; addr &= ~1L; @@ -2603,26 +2594,18 @@ static unsigned char jtagmkII_mtype(const PROGRAMMER *pgm, const AVRPART *p, con MTYPE_FLASH; } +// Return adjusted memory for communicating address of paged read/writes to programmer static unsigned int jtagmkII_memaddr(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr) { - /* - * Xmega devices handled by V7+ firmware don't want to be told their - * m->offset within the write memory command. - */ + // Xmega flash memories need adjusting as boot has its own region for the programmers + if(is_pdi(p) && mem_is_flash(m) && addr >= my.boot_start) + addr -= my.boot_start; + // Xmega devices handled by V7+ firmware don't want to be told their m->offset if(my.fwver >= 0x700 && (p->prog_modes & (PM_PDI | PM_UPDI))) { - if(addr >= my.boot_start) - /* - * All memories but "flash" are smaller than boot_start anyway, so no - * need for an extra check we are operating on "flash" - */ - return addr - my.boot_start; - else - // Normal flash, or anything else - return addr; + if(is_pdi(p) && mem_is_in_flash(m) && !mem_is_boot(m)) // Apptable, application and flash + addr += avr_flash_offset(p, m, addr); + return addr; } - /* - * Old firmware, or non-Xmega device. Non-Xmega (and non-AVR32) devices - * always have an m->offset of 0, so we don't have to distinguish them here. - */ + // Old firmware, or non-Xmega/non-UPDI device (which have offset 0) return addr + m->offset; }