Before this change SAMD driver defined "sector" equal to a flash
protection block. Oversize sectors (16kB for the biggest flash size)
made problems for flashing firmware split to two or more parts.
Removed superfluous test of sector protection before erase.
Change-Id: I8e6a6bda6ccd91eda2df67ec48270c69faa1bdd1
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3546
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
#include <target/cortex_m.h>
#include <target/cortex_m.h>
-#define SAMD_NUM_SECTORS 16
+#define SAMD_NUM_PROT_BLOCKS 16
#define SAMD_PAGE_SIZE_MAX 1024
#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */
#define SAMD_PAGE_SIZE_MAX 1024
#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */
uint32_t page_size;
int num_pages;
int sector_size;
uint32_t page_size;
int num_pages;
int sector_size;
bool probed;
struct target *target;
bool probed;
struct target *target;
static int samd_protect_check(struct flash_bank *bank)
{
static int samd_protect_check(struct flash_bank *bank)
{
uint16_t lock;
res = target_read_u16(bank->target,
uint16_t lock;
res = target_read_u16(bank->target,
return res;
/* Lock bits are active-low */
return res;
/* Lock bits are active-low */
- for (int i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_protected = !(lock & (1<<i));
+ for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++)
+ bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block));
bank->size = part->flash_kb * 1024;
bank->size = part->flash_kb * 1024;
- chip->sector_size = bank->size / SAMD_NUM_SECTORS;
-
res = samd_get_flash_page_info(bank->target, &chip->page_size,
&chip->num_pages);
if (res != ERROR_OK) {
res = samd_get_flash_page_info(bank->target, &chip->page_size,
&chip->num_pages);
if (res != ERROR_OK) {
part->flash_kb, chip->num_pages, chip->page_size);
}
part->flash_kb, chip->num_pages, chip->page_size);
}
+ /* Erase granularity = 1 row = 4 pages */
+ chip->sector_size = chip->page_size * 4;
+
/* Allocate the sector table */
/* Allocate the sector table */
- bank->num_sectors = SAMD_NUM_SECTORS;
- bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0]));
+ bank->num_sectors = chip->num_pages / 4;
+ bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors);
if (!bank->sectors)
return ERROR_FAIL;
if (!bank->sectors)
return ERROR_FAIL;
- /* Fill out the sector information: all SAMD sectors are the same size and
- * there is always a fixed number of them. */
- for (int i = 0; i < bank->num_sectors; i++) {
- bank->sectors[i].size = chip->sector_size;
- bank->sectors[i].offset = i * chip->sector_size;
- /* mark as unknown */
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = -1;
- }
+ /* 16 protection blocks per device */
+ chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS;
+
+ /* Allocate the table of protection blocks */
+ bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS;
+ bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks);
+ if (!bank->prot_blocks)
+ return ERROR_FAIL;
samd_protect_check(bank);
samd_protect_check(bank);
-static int samd_protect(struct flash_bank *bank, int set, int first, int last)
+static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl)
- struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+ int res = ERROR_OK;
+ int prot_block;
/* We can issue lock/unlock region commands with the target running but
* the settings won't persist unless we're able to modify the LOCK regions
/* We can issue lock/unlock region commands with the target running but
* the settings won't persist unless we're able to modify the LOCK regions
return ERROR_TARGET_NOT_HALTED;
}
return ERROR_TARGET_NOT_HALTED;
}
- int res = ERROR_OK;
-
- for (int s = first; s <= last; s++) {
- if (set != bank->sectors[s].is_protected) {
- /* Load an address that is within this sector (we use offset 0) */
+ for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) {
+ if (set != bank->prot_blocks[prot_block].is_protected) {
+ /* Load an address that is within this protection block (we use offset 0) */
res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
- ((s * chip->sector_size) >> 1));
+ bank->prot_blocks[prot_block].offset >> 1);
if (res != ERROR_OK)
goto exit;
if (res != ERROR_OK)
goto exit;
- /* Tell the controller to lock that sector */
+ /* Tell the controller to lock that block */
res = samd_issue_nvmctrl_command(bank->target,
set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
if (res != ERROR_OK)
res = samd_issue_nvmctrl_command(bank->target,
set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
if (res != ERROR_OK)
* locked. See Table 9-3 in the SAMD20 datasheet for more details. */
res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF,
* locked. See Table 9-3 in the SAMD20 datasheet for more details. */
res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF,
- 48 + first, 48 + last);
+ 48 + first_prot_bl, 48 + last_prot_bl);
if (res != ERROR_OK)
LOG_WARNING("SAMD: protect settings were not made persistent!");
if (res != ERROR_OK)
LOG_WARNING("SAMD: protect settings were not made persistent!");
-static int samd_erase(struct flash_bank *bank, int first, int last)
+static int samd_erase(struct flash_bank *bank, int first_sect, int last_sect)
- int res;
- int rows_in_sector;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
return ERROR_FLASH_BANK_NOT_PROBED;
}
return ERROR_FLASH_BANK_NOT_PROBED;
}
- /* 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
- * sectors. */
- rows_in_sector = chip->sector_size / (chip->page_size * 4);
-
/* For each sector to be erased */
/* For each sector to be erased */
- for (int s = first; s <= last; s++) {
- 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;
- }
-
- /* 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->target, r * chip->page_size * 4);
- if (res != ERROR_OK) {
- LOG_ERROR("SAMD: failed to erase sector %d", s);
- return res;
- }
+ for (s = first_sect; s <= last_sect; s++) {
+ res = samd_erase_row(bank->target, bank->sectors[s].offset);
+ if (res != ERROR_OK) {
+ LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset);
+ return res;