X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fat91samd.c;h=bfd2c6ab0510d3025a90b37d813c6473f0aef8dc;hp=8b0f14dd173d010a844fdfadf77bed37bd20fed9;hb=dba153bbce59985b0d8a23fc8d01c3b51d7e8528;hpb=0b263763f5dfa9e26c14bdb920be281a9bd4f468 diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 8b0f14dd17..bfd2c6ab05 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -254,24 +254,33 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last) int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; + res = ERROR_OK; + for (int s = first; s <= last; s++) { - /* Load an address that is within this sector (we use offset 0) */ - res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, - s * chip->sector_size); - if (res != ERROR_OK) - return res; + if (set != bank->sectors[s].is_protected) { + /* Load an address that is within this sector (we use offset 0) */ + res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, + s * chip->sector_size); + if (res != ERROR_OK) + goto exit; - /* Tell the controller to lock that sector */ - res = target_write_u16(bank->target, - SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, - SAMD_NVM_CMD(SAMD_NVM_CMD_LR)); - if (res != ERROR_OK) - return res; - } + /* Tell the controller to lock that sector */ + + uint16_t cmd = (set) ? + SAMD_NVM_CMD(SAMD_NVM_CMD_LR) : + SAMD_NVM_CMD(SAMD_NVM_CMD_UR); + res = target_write_u16(bank->target, + SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, + cmd); + if (res != ERROR_OK) + goto exit; + } + } +exit: samd_protect_check(bank); - return ERROR_OK; + return res; } static bool samd_check_error(struct flash_bank *bank) @@ -352,13 +361,6 @@ static int samd_erase(struct flash_bank *bank, int first, int last) return ERROR_FLASH_BANK_NOT_PROBED; } - /* Make sure the sectors make sense. */ - if (first >= bank->num_sectors || last >= bank->num_sectors) { - LOG_ERROR("Erase range %d - %d not valid (%d sectors total)", - first, last, bank->num_sectors); - return ERROR_FAIL; - } - /* The SAMD NVM has row erase granularity. There are four pages in a row * and the number of rows in a sector depends on the sector size, which in * turn depends on the Flash capacity as there is a fixed number of @@ -367,29 +369,60 @@ static int samd_erase(struct flash_bank *bank, int first, int last) /* For each sector to be erased */ for (int s = first; s <= last; s++) { - /* For each row in that sector */ - for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) { - res = samd_erase_row(bank, r * chip->page_size * 4); - if (res != ERROR_OK) { - LOG_ERROR("SAMD: failed to erase sector %d", s); - return res; - } + if (bank->sectors[s].is_protected) { + LOG_ERROR("SAMD: failed to erase sector %d. That sector is write-protected", s); + return ERROR_FLASH_OPERATION_FAILED; } - bank->sectors[s].is_erased = 1; + if (!bank->sectors[s].is_erased) { + /* For each row in that sector */ + for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) { + res = samd_erase_row(bank, r * chip->page_size * 4); + if (res != ERROR_OK) { + LOG_ERROR("SAMD: failed to erase sector %d", s); + return res; + } + } + + bank->sectors[s].is_erased = 1; + } } return ERROR_OK; } +static struct flash_sector *samd_find_sector_by_address(struct flash_bank *bank, uint32_t address) +{ + struct samd_info *chip = (struct samd_info *)bank->driver_priv; + + for (int i = 0; i < bank->num_sectors; i++) { + if (bank->sectors[i].offset <= address && + address < bank->sectors[i].offset + chip->sector_size) + return &bank->sectors[i]; + } + return NULL; +} + /* Write an entire row (four pages) from host buffer 'buf' to row-aligned * 'address' in the Flash. */ static int samd_write_row(struct flash_bank *bank, uint32_t address, - uint8_t *buf) + const uint8_t *buf) { int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; + struct flash_sector *sector = samd_find_sector_by_address(bank, address); + + if (!sector) { + LOG_ERROR("Can't find sector corresponding to address 0x%08" PRIx32, address); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (sector->is_protected) { + LOG_ERROR("Trying to write to a protected sector at 0x%08" PRIx32, address); + return ERROR_FLASH_OPERATION_FAILED; + } + /* Erase the row that we'll be writing to */ res = samd_erase_row(bank, address); if (res != ERROR_OK) @@ -418,13 +451,15 @@ static int samd_write_row(struct flash_bank *bank, uint32_t address, buf += chip->page_size; } + sector->is_erased = 0; + return res; } /* Write partial contents into row-aligned 'address' on the Flash from host * buffer 'buf' by writing 'nb' of 'buf' at 'row_offset' into the Flash row. */ static int samd_write_row_partial(struct flash_bank *bank, uint32_t address, - uint8_t *buf, uint32_t row_offset, uint32_t nb) + const uint8_t *buf, uint32_t row_offset, uint32_t nb) { int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; @@ -453,7 +488,7 @@ static int samd_write_row_partial(struct flash_bank *bank, uint32_t address, return res; } -static int samd_write(struct flash_bank *bank, uint8_t *buffer, +static int samd_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res;