flash/nor: at91samd modified to use real erase sector size 46/3546/5
authorTomas Vanek <vanekt@fbl.cz>
Thu, 14 Jul 2016 18:52:13 +0000 (20:52 +0200)
committerFreddie Chopin <freddie.chopin@gmail.com>
Sat, 17 Jun 2017 10:58:26 +0000 (11:58 +0100)
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>
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;
                }
        }
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)