]> git.sur5r.net Git - openocd/blobdiff - src/flash/nor/at91samd.c
flash/nor: at91samd modified to use real erase sector size
[openocd] / src / flash / nor / at91samd.c
index f018e893d5da0366f77af54c97393059f49e6cab..ad88c5143dbe8e544187224cf475dc0c5790a133 100644 (file)
@@ -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;
                }
        }