flash/nor/atsame5: Fix a timeout when erasing
authorMichael Hope <mlhx@google.com>
Fri, 29 May 2020 20:30:44 +0000 (22:30 +0200)
committerTomas Vanek <vanekt@fbl.cz>
Tue, 7 Jul 2020 04:18:14 +0000 (05:18 +0100)
According to the datasheet, erasing a block can take up to 200 ms.
When using a Segger J-Link with a 2 MHz clock the current loop
finishes after < 50 ms, ignores the timeout, and then fails when
erasing the next block.

Switch to a time based check, add an explicit yield, and report an
error on timeout.

Change-Id: I8255401d1e59f427a08d2cccb8a66143dcdbb324
Signed-off-by: Michael Hope <mlhx@google.com>
Reviewed-on: http://openocd.zylin.com/5706
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
src/flash/nor/atsame5.c

index eac7847dca807d911ade60e0f88a56250565e761..baa86acd09eaeae278e66b451d336d1203d0484c 100644 (file)
@@ -27,6 +27,7 @@
 #include "imp.h"
 #include "helper/binarybuffer.h"
 
+#include <helper/time_support.h>
 #include <target/cortex_m.h>
 
 /* A note to prefixing.
@@ -338,19 +339,28 @@ static int same5_probe(struct flash_bank *bank)
 static int same5_wait_and_check_error(struct target *target)
 {
        int ret, ret2;
-       int rep_cnt = 100;
+       /* Table 54-40 lists the maximum erase block time as 200 ms.
+        * Include some margin.
+        */
+       int timeout_ms = 200 * 5;
+       int64_t ts_start = timeval_ms();
        uint16_t intflag;
 
        do {
                ret = target_read_u16(target,
                        SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, &intflag);
-               if (ret == ERROR_OK && intflag & SAME5_NVMCTRL_INTFLAG_DONE)
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("SAM: error reading the NVMCTRL_INTFLAG register");
+                       return ret;
+               }
+               if (intflag & SAME5_NVMCTRL_INTFLAG_DONE)
                        break;
-       } while (--rep_cnt);
+               keep_alive();
+       } while (timeval_ms() - ts_start < timeout_ms);
 
-       if (ret != ERROR_OK) {
-               LOG_ERROR("Can't read NVM INTFLAG");
-               return ret;
+       if (!(intflag & SAME5_NVMCTRL_INTFLAG_DONE)) {
+               LOG_ERROR("SAM: NVM programming timed out");
+               ret = ERROR_FLASH_OPERATION_FAILED;
        }
 #if 0
        if (intflag & SAME5_NVMCTRL_INTFLAG_ECCSE)