From 640bf85b12c6fb938ab27ed3f8939dc16a98630c Mon Sep 17 00:00:00 2001 From: Dawid Buchwald Date: Fri, 5 Jul 2024 10:23:11 +0200 Subject: [PATCH 1/2] Alternative fix proposal for #1832 --- src/serialupdi.c | 10 ++++++++++ src/updi_nvm.c | 19 +++++++++++++++++++ src/updi_nvm.h | 1 + src/updi_nvm_v0.c | 7 +++++++ src/updi_nvm_v0.h | 1 + src/updi_nvm_v2.c | 11 +++++++++++ src/updi_nvm_v2.h | 1 + src/updi_nvm_v3.c | 7 +++++++ src/updi_nvm_v3.h | 1 + src/updi_nvm_v4.c | 11 +++++++++++ src/updi_nvm_v4.h | 1 + src/updi_nvm_v5.c | 7 +++++++ src/updi_nvm_v5.h | 1 + 13 files changed, 78 insertions(+) diff --git a/src/serialupdi.c b/src/serialupdi.c index d9f58eb80..6c46007d6 100644 --- a/src/serialupdi.c +++ b/src/serialupdi.c @@ -769,6 +769,11 @@ static int serialupdi_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const buffer[0]=value; return updi_nvm_write_flash(pgm, p, mem->offset + addr, buffer, 1); } + if (mem_is_bootrow(mem)) { + unsigned char buffer[1]; + buffer[0]=value; + return updi_nvm_write_boot_row(pgm, p, mem->offset + addr, buffer, 1); + } // Read-only memories if(mem_is_readonly(mem)) { unsigned char is; @@ -841,6 +846,9 @@ static int serialupdi_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const } else if (mem_is_userrow(m)) { rc = serialupdi_write_userrow(pgm, p, m, page_size, write_offset, remaining_bytes > m->page_size ? m->page_size : remaining_bytes); + } else if (mem_is_bootrow(m)) { + rc = updi_nvm_write_boot_row(pgm, p, m->offset + write_offset, m->buf + write_offset, + remaining_bytes > m->page_size ? m->page_size : remaining_bytes); } else if (mem_is_fuses(m)) { pmsg_debug("page write operation requested for fuses, falling back to byte-level write\n"); return -1; @@ -866,6 +874,8 @@ static int serialupdi_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const rc = updi_nvm_write_flash(pgm, p, m->offset+addr, m->buf+addr, n_bytes); } else if (mem_is_userrow(m)) { rc = serialupdi_write_userrow(pgm, p, m, page_size, addr, n_bytes); + } else if (mem_is_bootrow(m)) { + rc = updi_nvm_write_boot_row(pgm, p, m->offset+addr, m->buf+addr, n_bytes); } else if (mem_is_fuses(m)) { pmsg_debug("page write operation requested for fuses, falling back to byte-level write\n"); rc = -1; diff --git a/src/updi_nvm.c b/src/updi_nvm.c index 89bb2fe93..441432b39 100644 --- a/src/updi_nvm.c +++ b/src/updi_nvm.c @@ -157,6 +157,25 @@ int updi_nvm_write_user_row(const PROGRAMMER *pgm, const AVRPART *p, uint32_t ad } } +int updi_nvm_write_boot_row(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { + switch(updi_get_nvm_mode(pgm)) + { + case UPDI_NVM_MODE_V0: + return updi_nvm_write_boot_row_V0(pgm, p, address, buffer, size); + case UPDI_NVM_MODE_V2: + return updi_nvm_write_boot_row_V2(pgm, p, address, buffer, size); + case UPDI_NVM_MODE_V3: + return updi_nvm_write_boot_row_V3(pgm, p, address, buffer, size); + case UPDI_NVM_MODE_V4: + return updi_nvm_write_boot_row_V4(pgm, p, address, buffer, size); + case UPDI_NVM_MODE_V5: + return updi_nvm_write_boot_row_V5(pgm, p, address, buffer, size); + default: + pmsg_error("invalid NVM Mode %d\n", updi_get_nvm_mode(pgm)); + return -1; + } +} + int updi_nvm_write_eeprom(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { switch(updi_get_nvm_mode(pgm)) { diff --git a/src/updi_nvm.h b/src/updi_nvm.h index cc5e6e5a3..50df8f187 100644 --- a/src/updi_nvm.h +++ b/src/updi_nvm.h @@ -39,6 +39,7 @@ int updi_nvm_erase_eeprom(const PROGRAMMER *pgm, const AVRPART *p); int updi_nvm_erase_user_row(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint16_t size); int updi_nvm_write_flash(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_user_row(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); +int updi_nvm_write_boot_row(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_eeprom(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_fuse(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint8_t value); int updi_nvm_wait_ready(const PROGRAMMER *pgm, const AVRPART *p); diff --git a/src/updi_nvm_v0.c b/src/updi_nvm_v0.c index ece24f678..7e048477c 100644 --- a/src/updi_nvm_v0.c +++ b/src/updi_nvm_v0.c @@ -282,6 +282,13 @@ int updi_nvm_write_user_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t return updi_nvm_write_eeprom_V0(pgm, p, address, buffer, size); } +int updi_nvm_write_boot_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { +/* + Perform write operation as if it was regular flash memory, but ensure page erase/page write command +*/ + return nvm_write_V0(pgm, p, address, buffer, size, USE_WORD_ACCESS, UPDI_V0_NVMCTRL_CTRLA_ERASE_WRITE_PAGE); +} + int updi_nvm_write_eeprom_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* def write_eeprom(self, address, data): diff --git a/src/updi_nvm_v0.h b/src/updi_nvm_v0.h index 40d9e3f16..fbf4421d3 100644 --- a/src/updi_nvm_v0.h +++ b/src/updi_nvm_v0.h @@ -39,6 +39,7 @@ int updi_nvm_erase_eeprom_V0(const PROGRAMMER *pgm, const AVRPART *p); int updi_nvm_erase_user_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint16_t size); int updi_nvm_write_flash_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_user_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); +int updi_nvm_write_boot_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_eeprom_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_fuse_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint8_t value); int updi_nvm_wait_ready_V0(const PROGRAMMER *pgm, const AVRPART *p); diff --git a/src/updi_nvm_v2.c b/src/updi_nvm_v2.c index bff8e7993..c6670916a 100644 --- a/src/updi_nvm_v2.c +++ b/src/updi_nvm_v2.c @@ -282,6 +282,17 @@ int updi_nvm_write_user_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t return nvm_write_V2(pgm, p, address, buffer, size, DONT_USE_WORD_ACCESS); } +int updi_nvm_write_boot_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { +/* + Perform write operation as if it was regular flash memory, but perform erase operation first +*/ + if (updi_nvm_erase_flash_page_V2(pgm, p, address) <0) { + pmsg_error("Flash page erase failed for bootrow\n"); + return -1; + } + return updi_nvm_write_flash_V2(pgm, p, address, buffer, size); +} + int updi_nvm_write_eeprom_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* def write_eeprom(self, address, data): diff --git a/src/updi_nvm_v2.h b/src/updi_nvm_v2.h index 21d97d0c5..59ff5eb5b 100644 --- a/src/updi_nvm_v2.h +++ b/src/updi_nvm_v2.h @@ -39,6 +39,7 @@ int updi_nvm_erase_eeprom_V2(const PROGRAMMER *pgm, const AVRPART *p); int updi_nvm_erase_user_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint16_t size); int updi_nvm_write_flash_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_user_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); +int updi_nvm_write_boot_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_eeprom_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_fuse_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint8_t value); int updi_nvm_wait_ready_V2(const PROGRAMMER *pgm, const AVRPART *p); diff --git a/src/updi_nvm_v3.c b/src/updi_nvm_v3.c index 51aab6b5d..99989ddd4 100644 --- a/src/updi_nvm_v3.c +++ b/src/updi_nvm_v3.c @@ -297,6 +297,13 @@ int updi_nvm_write_user_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t return nvm_write_V3(pgm, p, address, buffer, size, USE_WORD_ACCESS, USE_DEFAULT_COMMAND); } +int updi_nvm_write_boot_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { +/* + Perform the operation as the regular flash write, but with page erase/page write command +*/ + return nvm_write_V3(pgm, p, address, buffer, size, USE_WORD_ACCESS, UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_ERASE_WRITE); +} + int updi_nvm_write_eeprom_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* def write_eeprom(self, address, data): diff --git a/src/updi_nvm_v3.h b/src/updi_nvm_v3.h index b0bd293e2..929474005 100644 --- a/src/updi_nvm_v3.h +++ b/src/updi_nvm_v3.h @@ -39,6 +39,7 @@ int updi_nvm_erase_eeprom_V3(const PROGRAMMER *pgm, const AVRPART *p); int updi_nvm_erase_user_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint16_t size); int updi_nvm_write_flash_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_user_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); +int updi_nvm_write_boot_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_eeprom_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_fuse_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint8_t value); int updi_nvm_wait_ready_V3(const PROGRAMMER *pgm, const AVRPART *p); diff --git a/src/updi_nvm_v4.c b/src/updi_nvm_v4.c index 154edb5af..5d3b0cd6a 100644 --- a/src/updi_nvm_v4.c +++ b/src/updi_nvm_v4.c @@ -283,6 +283,17 @@ int updi_nvm_write_user_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t return nvm_write_V4(pgm, p, address, buffer, size, DONT_USE_WORD_ACCESS); } +int updi_nvm_write_boot_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { +/* + Write it as a regular flash page, but perform page erase first +*/ + if (updi_nvm_erase_flash_page_V4(pgm, p, address) <0) { + pmsg_error("Flash page erase failed for bootrow\n"); + return -1; + } + return updi_nvm_write_flash_V4(pgm, p, address, buffer, size); +} + int updi_nvm_write_eeprom_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* def write_eeprom(self, address, data): diff --git a/src/updi_nvm_v4.h b/src/updi_nvm_v4.h index aa8a61353..14a16353a 100644 --- a/src/updi_nvm_v4.h +++ b/src/updi_nvm_v4.h @@ -39,6 +39,7 @@ int updi_nvm_erase_eeprom_V4(const PROGRAMMER *pgm, const AVRPART *p); int updi_nvm_erase_user_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint16_t size); int updi_nvm_write_flash_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_user_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); +int updi_nvm_write_boot_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_eeprom_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_fuse_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint8_t value); int updi_nvm_wait_ready_V4(const PROGRAMMER *pgm, const AVRPART *p); diff --git a/src/updi_nvm_v5.c b/src/updi_nvm_v5.c index 24002c45c..bc11708e1 100644 --- a/src/updi_nvm_v5.c +++ b/src/updi_nvm_v5.c @@ -298,6 +298,13 @@ int updi_nvm_write_user_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t return nvm_write_V5(pgm, p, address, buffer, size, USE_WORD_ACCESS, USE_DEFAULT_COMMAND); } +int updi_nvm_write_boot_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { +/* + Perform the operation as the regular flash write, but with page erase/page write command +*/ + return nvm_write_V5(pgm, p, address, buffer, size, USE_WORD_ACCESS, UPDI_V5_NVMCTRL_CTRLA_FLASH_PAGE_ERASE_WRITE); +} + int updi_nvm_write_eeprom_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* def write_eeprom(self, address, data): diff --git a/src/updi_nvm_v5.h b/src/updi_nvm_v5.h index 0cb1259c3..c1102236c 100644 --- a/src/updi_nvm_v5.h +++ b/src/updi_nvm_v5.h @@ -39,6 +39,7 @@ int updi_nvm_erase_eeprom_V5(const PROGRAMMER *pgm, const AVRPART *p); int updi_nvm_erase_user_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint16_t size); int updi_nvm_write_flash_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_user_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); +int updi_nvm_write_boot_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_eeprom_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size); int updi_nvm_write_fuse_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, uint8_t value); int updi_nvm_wait_ready_V5(const PROGRAMMER *pgm, const AVRPART *p); From e7f7691367fc4a0d6edba8c686e1d5f56478711e Mon Sep 17 00:00:00 2001 From: Dawid Buchwald Date: Sun, 7 Jul 2024 17:21:12 +0200 Subject: [PATCH 2/2] Rolled back page erase feature as not needed anymore --- src/updi_nvm_v0.c | 4 ++-- src/updi_nvm_v2.c | 8 ++------ src/updi_nvm_v3.c | 4 ++-- src/updi_nvm_v4.c | 8 ++------ src/updi_nvm_v5.c | 4 ++-- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/updi_nvm_v0.c b/src/updi_nvm_v0.c index 7e048477c..f3f1be647 100644 --- a/src/updi_nvm_v0.c +++ b/src/updi_nvm_v0.c @@ -284,9 +284,9 @@ int updi_nvm_write_user_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t int updi_nvm_write_boot_row_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* - Perform write operation as if it was regular flash memory, but ensure page erase/page write command + Perform write operation as if it was regular flash memory */ - return nvm_write_V0(pgm, p, address, buffer, size, USE_WORD_ACCESS, UPDI_V0_NVMCTRL_CTRLA_ERASE_WRITE_PAGE); + return nvm_write_V0(pgm, p, address, buffer, size, USE_WORD_ACCESS, USE_DEFAULT_COMMAND); } int updi_nvm_write_eeprom_V0(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { diff --git a/src/updi_nvm_v2.c b/src/updi_nvm_v2.c index c6670916a..ebf5382bb 100644 --- a/src/updi_nvm_v2.c +++ b/src/updi_nvm_v2.c @@ -284,13 +284,9 @@ int updi_nvm_write_user_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t int updi_nvm_write_boot_row_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* - Perform write operation as if it was regular flash memory, but perform erase operation first + Perform write operation as if it was regular flash memory */ - if (updi_nvm_erase_flash_page_V2(pgm, p, address) <0) { - pmsg_error("Flash page erase failed for bootrow\n"); - return -1; - } - return updi_nvm_write_flash_V2(pgm, p, address, buffer, size); + return nvm_write_V2(pgm, p, address, buffer, size, USE_WORD_ACCESS); } int updi_nvm_write_eeprom_V2(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { diff --git a/src/updi_nvm_v3.c b/src/updi_nvm_v3.c index 99989ddd4..73c62bc36 100644 --- a/src/updi_nvm_v3.c +++ b/src/updi_nvm_v3.c @@ -299,9 +299,9 @@ int updi_nvm_write_user_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t int updi_nvm_write_boot_row_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* - Perform the operation as the regular flash write, but with page erase/page write command + Perform the operation as the regular flash write */ - return nvm_write_V3(pgm, p, address, buffer, size, USE_WORD_ACCESS, UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_ERASE_WRITE); + return nvm_write_V3(pgm, p, address, buffer, size, USE_WORD_ACCESS, USE_DEFAULT_COMMAND); } int updi_nvm_write_eeprom_V3(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { diff --git a/src/updi_nvm_v4.c b/src/updi_nvm_v4.c index 5d3b0cd6a..0773983a8 100644 --- a/src/updi_nvm_v4.c +++ b/src/updi_nvm_v4.c @@ -285,13 +285,9 @@ int updi_nvm_write_user_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t int updi_nvm_write_boot_row_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* - Write it as a regular flash page, but perform page erase first + Write it as a regular flash page */ - if (updi_nvm_erase_flash_page_V4(pgm, p, address) <0) { - pmsg_error("Flash page erase failed for bootrow\n"); - return -1; - } - return updi_nvm_write_flash_V4(pgm, p, address, buffer, size); + return nvm_write_V4(pgm, p, address, buffer, size, USE_WORD_ACCESS); } int updi_nvm_write_eeprom_V4(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { diff --git a/src/updi_nvm_v5.c b/src/updi_nvm_v5.c index bc11708e1..a337678c9 100644 --- a/src/updi_nvm_v5.c +++ b/src/updi_nvm_v5.c @@ -300,9 +300,9 @@ int updi_nvm_write_user_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t int updi_nvm_write_boot_row_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) { /* - Perform the operation as the regular flash write, but with page erase/page write command + Perform the operation as the regular flash write */ - return nvm_write_V5(pgm, p, address, buffer, size, USE_WORD_ACCESS, UPDI_V5_NVMCTRL_CTRLA_FLASH_PAGE_ERASE_WRITE); + return nvm_write_V5(pgm, p, address, buffer, size, USE_WORD_ACCESS, USE_DEFAULT_COMMAND); } int updi_nvm_write_eeprom_V5(const PROGRAMMER *pgm, const AVRPART *p, uint32_t address, unsigned char *buffer, uint16_t size) {