Commit 278f6317 authored by Tomas Vanek's avatar Tomas Vanek Committed by Freddie Chopin
Browse files

flash/nor: at91samd modified to use real erase sector size



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: default avatarTomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3546


Tested-by: jenkins
Reviewed-by: default avatarStian Skjelstad <stian@nixia.no>
Reviewed-by: default avatarFreddie Chopin <freddie.chopin@gmail.com>
parent 24c30275
......@@ -25,7 +25,7 @@
#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 */
......@@ -286,6 +286,7 @@ struct samd_info {
uint32_t page_size;
int num_pages;
int sector_size;
int prot_block_size;
bool probed;
struct target *target;
......@@ -319,7 +320,7 @@ static const struct samd_part *samd_find_part(uint32_t id)
static int samd_protect_check(struct flash_bank *bank)
{
int res;
int res, prot_block;
uint16_t lock;
res = target_read_u16(bank->target,
......@@ -328,8 +329,8 @@ static int samd_protect_check(struct flash_bank *bank)
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));
return ERROR_OK;
}
......@@ -380,8 +381,6 @@ static int samd_probe(struct flash_bank *bank)
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) {
......@@ -397,21 +396,23 @@ static int samd_probe(struct flash_bank *bank)
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 */
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;
/* 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);
......@@ -606,9 +607,10 @@ out_user_row:
return res;
}
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
......@@ -618,18 +620,16 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last)
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,
((s * chip->sector_size) >> 1));
bank->prot_blocks[prot_block].offset >> 1);
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)
......@@ -644,7 +644,7 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last)
* 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!");
......@@ -656,10 +656,9 @@ exit:
return res;
}
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;
int res, s;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
......@@ -673,26 +672,12 @@ static int samd_erase(struct flash_bank *bank, int first, int last)
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 (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;
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment