flash/nor: at91samd protection bits write fix 50/3550/2
authorTomas Vanek <vanekt@fbl.cz>
Mon, 18 Jul 2016 20:59:17 +0000 (22:59 +0200)
committerPaul Fertser <fercerpav@gmail.com>
Thu, 8 Dec 2016 12:19:19 +0000 (12:19 +0000)
Flash protection set on a device with MANW=1 was lost after reset.
Since #2903 the driver honored MANW bit and issued Write Page command just
for main flash write. This change adds similar technique to
samd_modify_user_row().

Minor code improvements:
samd_check_error() returns error code corresponding to error type
instead of bool.

samd_check_error() does not clear STATUS register if no error bit is set.

Eliminated double error check in call sequence samd_issue_nvmctrl_command()
folowed by samd_check_error().

Missing error code ERROR_FLASH_PROTECTED added to src/flash/common.h.

Change-Id: Icf59ab8803305d0cb3170c8a5089b8f9828b99f8
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3550
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
src/flash/common.h
src/flash/nor/at91samd.c

index ce26fccd75b39632e9d457ec42128b562a05e221..4244f1360647c684aae958ee17c45213c53127b8 100644 (file)
@@ -44,5 +44,6 @@ bool flash_driver_name_matches(const char *name, const char *expected);
 #define ERROR_FLASH_SECTOR_NOT_ERASED          (-906)
 #define ERROR_FLASH_BANK_NOT_PROBED                    (-907)
 #define ERROR_FLASH_OPER_UNSUPPORTED           (-908)
+#define ERROR_FLASH_PROTECTED                  (-909)
 
 #endif /* OPENOCD_FLASH_COMMON_H */
index cdc43b8b3edd4edadd287a08e88a023abd95cd8d..2673b0eecadd858e1065557919106f4b2726f99f 100644 (file)
@@ -423,39 +423,43 @@ static int samd_probe(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-static bool samd_check_error(struct target *target)
+static int samd_check_error(struct target *target)
 {
-       int ret;
-       bool error;
+       int ret, ret2;
        uint16_t status;
 
        ret = target_read_u16(target,
                        SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status);
        if (ret != ERROR_OK) {
                LOG_ERROR("Can't read NVM status");
-               return true;
+               return ret;
        }
 
-       if (status & 0x001C) {
-               if (status & (1 << 4)) /* NVME */
-                       LOG_ERROR("SAMD: NVM Error");
-               if (status & (1 << 3)) /* LOCKE */
-                       LOG_ERROR("SAMD: NVM lock error");
-               if (status & (1 << 2)) /* PROGE */
-                       LOG_ERROR("SAMD: NVM programming error");
+       if ((status & 0x001C) == 0)
+               return ERROR_OK;
 
-               error = true;
-       } else {
-               error = false;
+       if (status & (1 << 4)) { /* NVME */
+               LOG_ERROR("SAMD: NVM Error");
+               ret = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (status & (1 << 3)) { /* LOCKE */
+               LOG_ERROR("SAMD: NVM lock error");
+               ret = ERROR_FLASH_PROTECTED;
+       }
+
+       if (status & (1 << 2)) { /* PROGE */
+               LOG_ERROR("SAMD: NVM programming error");
+               ret = ERROR_FLASH_OPER_UNSUPPORTED;
        }
 
        /* Clear the error conditions by writing a one to them */
-       ret = target_write_u16(target,
+       ret2 = target_write_u16(target,
                        SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, status);
-       if (ret != ERROR_OK)
+       if (ret2 != ERROR_OK)
                LOG_ERROR("Can't clear NVM error conditions");
 
-       return error;
+       return ret;
 }
 
 static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
@@ -474,10 +478,7 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
                return res;
 
        /* Check to see if the NVM command resulted in an error condition. */
-       if (samd_check_error(target))
-               return ERROR_FAIL;
-
-       return ERROR_OK;
+       return samd_check_error(target);
 }
 
 static int samd_erase_row(struct target *target, uint32_t address)
@@ -531,12 +532,19 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
                uint8_t startb, uint8_t endb)
 {
        int res;
+       uint32_t nvm_ctrlb;
+       bool manual_wp = true;
 
        if (is_user_row_reserved_bit(startb) || is_user_row_reserved_bit(endb)) {
                LOG_ERROR("Can't modify bits in the requested range");
                return ERROR_FAIL;
        }
 
+       /* Check if we need to do manual page write commands */
+       res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb);
+       if (res == ERROR_OK)
+               manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0;
+
        /* Retrieve the MCU's page size, in bytes. This is also the size of the
         * entire User Row. */
        uint32_t page_size;
@@ -559,8 +567,8 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
        if (!buf)
                return ERROR_FAIL;
 
-       /* Read the user row (comprising one page) by half-words. */
-       res = target_read_memory(target, SAMD_USER_ROW, 2, page_size / 2, buf);
+       /* Read the user row (comprising one page) by words. */
+       res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
        if (res != ERROR_OK)
                goto out_user_row;
 
@@ -579,20 +587,18 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
        /* Modify */
        buf_set_u32(buf, startb, endb - startb + 1, value);
 
-       /* Write the page buffer back out to the target.  A Flash write will be
-        * triggered automatically. */
+       /* Write the page buffer back out to the target. */
        res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
        if (res != ERROR_OK)
                goto out_user_row;
 
-       if (samd_check_error(target)) {
-               res = ERROR_FAIL;
-               goto out_user_row;
+       if (manual_wp) {
+               /* Trigger flash write */
+               res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_WAP);
+       } else {
+               res = samd_check_error(target);
        }
 
-       /* Success */
-       res = ERROR_OK;
-
 out_user_row:
        free(buf);
 
@@ -784,18 +790,15 @@ static int samd_write(struct flash_bank *bank, const uint8_t *buffer,
                 * then issue CMD_WP always */
                if (manual_wp || pg_offset + 4 * nw < chip->page_size) {
                        res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_WP);
-                       if (res != ERROR_OK) {
-                               LOG_ERROR("%s: %d", __func__, __LINE__);
-                               goto free_pb;
-                       }
-               }
+               } else {
+                       /* Access through AHB is stalled while flash is being programmed */
+                       usleep(200);
 
-               /* Access through AHB is stalled while flash is being programmed */
-               usleep(200);
+                       res = samd_check_error(bank->target);
+               }
 
-               if (samd_check_error(bank->target)) {
+               if (res != ERROR_OK) {
                        LOG_ERROR("%s: write failed at address 0x%08" PRIx32, __func__, address);
-                       res = ERROR_FAIL;
                        goto free_pb;
                }
 

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)