at91samd: add erase/secure commands, minor fix
[openocd.git] / src / flash / nor / at91samd.c
index 7d25b4c5148853ce45cdac30fd584d612379b553..9eec0d0ead86b0a0aba89e831067f2a4f508485f 100644 (file)
@@ -27,6 +27,7 @@
 #define SAMD_NUM_SECTORS       16
 
 #define SAMD_FLASH                     ((uint32_t)0x00000000)  /* physical Flash memory */
+#define SAMD_PAC1                      0x41000000      /* Peripheral Access Control 1 */
 #define SAMD_DSU                       0x41002000      /* Device Service Unit */
 #define SAMD_NVMCTRL           0x41004000      /* Non-volatile memory controller */
 
@@ -295,47 +296,13 @@ static int samd_probe(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-static int samd_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       int res;
-       struct samd_info *chip = (struct samd_info *)bank->driver_priv;
-
-       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) */
-                       res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
-                                              s * chip->sector_size);
-                       if (res != ERROR_OK)
-                               goto exit;
-
-                       /* Tell the controller to lock that sector */
-
-                       uint16_t cmd = (set) ?
-                               SAMD_NVM_CMD(SAMD_NVM_CMD_LR) :
-                               SAMD_NVM_CMD(SAMD_NVM_CMD_UR);
-
-                       res = target_write_u16(bank->target,
-                                              SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA,
-                                              cmd);
-                       if (res != ERROR_OK)
-                               goto exit;
-               }
-       }
-exit:
-       samd_protect_check(bank);
-
-       return res;
-}
-
-static bool samd_check_error(struct flash_bank *bank)
+static bool samd_check_error(struct target *target)
 {
        int ret;
        bool error;
        uint16_t status;
 
-       ret = target_read_u16(bank->target,
+       ret = target_read_u16(target,
                        SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status);
        if (ret != ERROR_OK) {
                LOG_ERROR("Can't read NVM status");
@@ -356,7 +323,7 @@ static bool samd_check_error(struct flash_bank *bank)
        }
 
        /* Clear the error conditions by writing a one to them */
-       ret = target_write_u16(bank->target,
+       ret = target_write_u16(target,
                        SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, status);
        if (ret != ERROR_OK)
                LOG_ERROR("Can't clear NVM error conditions");
@@ -364,25 +331,88 @@ static bool samd_check_error(struct flash_bank *bank)
        return error;
 }
 
+static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
+{
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Read current configuration. */
+       uint16_t tmp = 0;
+       int res = target_read_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB,
+                       &tmp);
+       if (res != ERROR_OK)
+               return res;
+
+       /* Set cache disable. */
+       res = target_write_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB,
+                       tmp | (1<<18));
+       if (res != ERROR_OK)
+               return res;
+
+       /* Issue the NVM command */
+       int res_cmd = target_write_u16(target,
+                       SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, SAMD_NVM_CMD(cmd));
+
+       /* Try to restore configuration, regardless of NVM command write
+        * status. */
+       res = target_write_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, tmp);
+
+       if (res_cmd != ERROR_OK)
+               return res_cmd;
+
+       if (res != ERROR_OK)
+               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;
+}
+
+static int samd_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       int res;
+       struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+
+       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) */
+                       res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
+                                              s * chip->sector_size);
+                       if (res != ERROR_OK)
+                               goto exit;
+
+                       /* Tell the controller to lock that sector */
+                       res = samd_issue_nvmctrl_command(bank->target,
+                                       set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
+                       if (res != ERROR_OK)
+                               goto exit;
+               }
+       }
+exit:
+       samd_protect_check(bank);
+
+       return res;
+}
+
 static int samd_erase_row(struct flash_bank *bank, uint32_t address)
 {
        int res;
-       bool error = false;
 
        /* Set an address contained in the row to be erased */
        res = target_write_u32(bank->target,
                        SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, address >> 1);
-       if (res == ERROR_OK) {
-               /* Issue the Erase Row command to erase that row */
-               res = target_write_u16(bank->target,
-                               SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA,
-                               SAMD_NVM_CMD(SAMD_NVM_CMD_ER));
 
-               /* Check (and clear) error conditions */
-               error = samd_check_error(bank);
-       }
+       /* Issue the Erase Row command to erase that row */
+       if (res == ERROR_OK)
+               res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_ER);
 
-       if (res != ERROR_OK || error)  {
+       if (res != ERROR_OK)  {
                LOG_ERROR("Failed to erase row containing %08" PRIx32, address);
                return ERROR_FAIL;
        }
@@ -488,7 +518,7 @@ static int samd_write_row(struct flash_bank *bank, uint32_t address,
                        return res;
                }
 
-               error = samd_check_error(bank);
+               error = samd_check_error(bank->target);
                if (error)
                        return ERROR_FAIL;
 
@@ -652,6 +682,51 @@ COMMAND_HANDLER(samd_handle_info_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(samd_handle_chip_erase_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+
+       if (target) {
+               /* Enable access to the DSU by disabling the write protect bit */
+               target_write_u32(target, SAMD_PAC1, (1<<1));
+               /* Tell the DSU to perform a full chip erase.  It takes about 240ms to
+                * perform the erase. */
+               target_write_u8(target, SAMD_DSU, (1<<4));
+
+               command_print(CMD_CTX, "chip erased");
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(samd_handle_set_security_command)
+{
+       int res = ERROR_OK;
+       struct target *target = get_current_target(CMD_CTX);
+
+       if (CMD_ARGC < 1 || (CMD_ARGC >= 1 && (strcmp(CMD_ARGV[0], "enable")))) {
+               command_print(CMD_CTX, "supply the \"enable\" argument to proceed.");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (target) {
+               if (target->state != TARGET_HALTED) {
+                       LOG_ERROR("Target not halted");
+                       return ERROR_TARGET_NOT_HALTED;
+               }
+
+               res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_SSB);
+
+               /* Check (and clear) error conditions */
+               if (res == ERROR_OK)
+                       command_print(CMD_CTX, "chip secured on next power-cycle");
+               else
+                       command_print(CMD_CTX, "failed to secure chip");
+       }
+
+       return res;
+}
+
 static const struct command_registration at91samd_exec_command_handlers[] = {
        {
                .name = "info",
@@ -660,6 +735,22 @@ static const struct command_registration at91samd_exec_command_handlers[] = {
                .help = "Print information about the current at91samd chip"
                        "and its flash configuration.",
        },
+       {
+               .name = "chip-erase",
+               .handler = samd_handle_chip_erase_command,
+               .mode = COMMAND_EXEC,
+               .help = "Erase the entire Flash by using the Chip"
+                       "Erase feature in the Device Service Unit (DSU).",
+       },
+       {
+               .name = "set-security",
+               .handler = samd_handle_set_security_command,
+               .mode = COMMAND_EXEC,
+               .help = "Secure the chip's Flash by setting the Security Bit."
+                       "This makes it impossible to read the Flash contents."
+                       "The only way to undo this is to issue the chip-erase"
+                       "command.",
+       },
        COMMAND_REGISTRATION_DONE
 };
 

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)