Kinetis: check/switch run mode before flash operation
authorTomas Vanek <vanekt@fbl.cz>
Mon, 12 Oct 2015 22:15:16 +0000 (00:15 +0200)
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>
Mon, 15 Feb 2016 19:46:51 +0000 (19:46 +0000)
FTFx flash controller requires MCU in normal RUN mode.
Flash cannot be erased, programmed or blank checked in VLPR or HSRUN
modes.

VLPR mode is switched to RUN mode as it does not require any changes
in clock generator setting. VLPR can be active from reset on some
KLx devices (with some FOPT setting) so 'reset init' might not be
sufficient to get device to normal RUN.

Any other mode than RUN or VLPR is reported as an error.

Change-Id: I60f494ce0d534b04870c6219d9b05f66f7244433
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3012
Tested-by: jenkins
src/flash/nor/kinetis.c

index db098bbb27872b593721ed828ec4e548ac34588a..7907b8c386ad2f81d8f6a3ce946046d038fde36a 100644 (file)
 #define SIM_FCFG1      0x4004804c
 #define SIM_FCFG2      0x40048050
 #define WDOG_STCTRH    0x40052000
+#define SMC_PMCTRL     0x4007E001
+#define SMC_PMSTAT     0x4007E003
+
+/* Values */
+#define PM_STAT_RUN            0x01
+#define PM_STAT_VLPR           0x04
+#define PM_CTRL_RUNM_RUN       0x00
 
 /* Commands */
 #define FTFx_CMD_BLOCKSTAT  0x00
@@ -951,6 +958,47 @@ static int kinetis_ftfx_command(struct target *target, uint8_t fcmd, uint32_t fa
 }
 
 
+static int kinetis_check_run_mode(struct target *target)
+{
+       int result, i;
+       uint8_t pmctrl, pmstat;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       result = target_read_u8(target, SMC_PMSTAT, &pmstat);
+       if (result != ERROR_OK)
+               return result;
+
+       if (pmstat == PM_STAT_RUN)
+               return ERROR_OK;
+
+       if (pmstat == PM_STAT_VLPR) {
+               /* It is safe to switch from VLPR to RUN mode without changing clock */
+               LOG_INFO("Switching from VLPR to RUN mode.");
+               pmctrl = PM_CTRL_RUNM_RUN;
+               result = target_write_u8(target, SMC_PMCTRL, pmctrl);
+               if (result != ERROR_OK)
+                       return result;
+
+               for (i = 100; i; i--) {
+                       result = target_read_u8(target, SMC_PMSTAT, &pmstat);
+                       if (result != ERROR_OK)
+                               return result;
+
+                       if (pmstat == PM_STAT_RUN)
+                               return ERROR_OK;
+               }
+       }
+
+       LOG_ERROR("Flash operation not possible in current run mode: SMC_PMSTAT: 0x%x", pmstat);
+       LOG_ERROR("Issue a 'reset init' command.");
+       return ERROR_TARGET_NOT_HALTED;
+}
+
+
 static void kinetis_invalidate_flash_cache(struct flash_bank *bank)
 {
        struct kinetis_flash_bank *kinfo = bank->driver_priv;
@@ -969,10 +1017,9 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
        int result, i;
        struct kinetis_flash_bank *kinfo = bank->driver_priv;
 
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       result = kinetis_check_run_mode(bank->target);
+       if (result != ERROR_OK)
+               return result;
 
        if ((first > bank->num_sectors) || (last > bank->num_sectors))
                return ERROR_FLASH_OPERATION_FAILED;
@@ -1045,10 +1092,9 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
        struct kinetis_flash_bank *kinfo = bank->driver_priv;
        uint8_t *new_buffer = NULL;
 
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       result = kinetis_check_run_mode(bank->target);
+       if (result != ERROR_OK)
+               return result;
 
        if (!(kinfo->flash_support & FS_PROGRAM_SECTOR)) {
                /* fallback to longword write */
@@ -1662,14 +1708,14 @@ static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size)
 static int kinetis_blank_check(struct flash_bank *bank)
 {
        struct kinetis_flash_bank *kinfo = bank->driver_priv;
+       int result;
 
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       /* suprisingly blank check does not work in VLPR and HSRUN modes */
+       result = kinetis_check_run_mode(bank->target);
+       if (result != ERROR_OK)
+               return result;
 
        if (kinfo->flash_class == FC_PFLASH || kinfo->flash_class == FC_FLEX_NVM) {
-               int result;
                bool block_dirty = false;
                uint8_t ftfx_fstat;
 
@@ -1831,10 +1877,9 @@ COMMAND_HANDLER(kinetis_nvm_partition)
        LOG_INFO("DEPART 0x%" PRIx8 ", EEPROM size code 0x%" PRIx8,
                 flex_nvm_partition_code, ee_size_code);
 
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       result = kinetis_check_run_mode(target);
+       if (result != ERROR_OK)
+               return result;
 
        result = kinetis_ftfx_command(target, FTFx_CMD_PGMPART, load_flex_ram,
                                      ee_size_code, flex_nvm_partition_code, 0, 0,