kinetis : improve kinetis flash driver.
[fw/openocd] / src / flash / nor / kinetis.c
index 51e7676fa26e66115db3b4efedf817a01752666b..c2ea1d8cbe19c3b02605ea8e505337a0755d7fe6 100644 (file)
  * and FlexNVM/FlexRAM, so flash command arguments may differ between
  * blocks in the same chip.
  *
- * Although not documented as such by Freescale, it appears that bits
- * 8:7 of the read-only SIM_SDID register reflect the granularity
- * settings 0..3, so sector sizes and block counts are applicable
- * according to the following table.
  */
 
 const struct {
@@ -120,6 +116,67 @@ const struct {
 #define FTFx_CMD_SETFLEXRAM 0x81
 #define FTFx_CMD_MASSERASE  0x44
 
+/* The Kinetis K series uses the following SDID layout :
+ * Bit 31-16 : 0
+ * Bit 15-12 : REVID
+ * Bit 11-7  : DIEID
+ * Bit 6-4   : FAMID
+ * Bit 3-0   : PINID
+ *
+ * The Kinetis KL series uses the following SDID layout :
+ * Bit 31-28 : FAMID
+ * Bit 27-24 : SUBFAMID
+ * Bit 23-20 : SERIESID
+ * Bit 19-16 : SRAMSIZE
+ * Bit 15-12 : REVID
+ * Bit 6-4   : Reserved (0)
+ * Bit 3-0   : PINID
+ *
+ * SERIESID should be 1 for the KL-series so we assume that if
+ * bits 31-16 are 0 then it's a K-series MCU.
+ */
+
+#define KINETIS_SDID_K_SERIES_MASK  0x0000FFFF
+
+#define KINETIS_SDID_DIEID_MASK 0x00000F80
+#define KINETIS_SDID_DIEID_K_A 0x00000100
+#define KINETIS_SDID_DIEID_K_B 0x00000200
+#define KINETIS_SDID_DIEID_KL  0x00000000
+
+/* We can't rely solely on the FAMID field to determine the MCU
+ * type since some FAMID values identify multiple MCUs with
+ * different flash sector sizes (K20 and K22 for instance).
+ * Therefore we combine it with the DIEID bits which may possibly
+ * break if Freescale bumps the DIEID for a particular MCU. */
+#define KINETIS_K_SDID_TYPE_MASK 0x00000FF0
+#define KINETIS_K_SDID_K10_M50  0x00000000
+#define KINETIS_K_SDID_K10_M72  0x00000080
+#define KINETIS_K_SDID_K10_M100         0x00000100
+#define KINETIS_K_SDID_K10_M120         0x00000180
+#define KINETIS_K_SDID_K11              0x00000220
+#define KINETIS_K_SDID_K12              0x00000200
+#define KINETIS_K_SDID_K20_M50  0x00000010
+#define KINETIS_K_SDID_K20_M72  0x00000090
+#define KINETIS_K_SDID_K20_M100         0x00000110
+#define KINETIS_K_SDID_K20_M120         0x00000190
+#define KINETIS_K_SDID_K21_M50   0x00000230
+#define KINETIS_K_SDID_K21_M120         0x00000330
+#define KINETIS_K_SDID_K22_M50   0x00000210
+#define KINETIS_K_SDID_K22_M120         0x00000310
+#define KINETIS_K_SDID_K30_M72   0x000000A0
+#define KINETIS_K_SDID_K30_M100  0x00000120
+#define KINETIS_K_SDID_K40_M72   0x000000B0
+#define KINETIS_K_SDID_K40_M100  0x00000130
+#define KINETIS_K_SDID_K50_M72   0x000000E0
+#define KINETIS_K_SDID_K51_M72  0x000000F0
+#define KINETIS_K_SDID_K53              0x00000170
+#define KINETIS_K_SDID_K60_M100  0x00000140
+#define KINETIS_K_SDID_K60_M150  0x000001C0
+#define KINETIS_K_SDID_K70_M150  0x000001D0
+
+#define KINETIS_KL_SDID_SERIESID_MASK 0x00F00000
+#define KINETIS_KL_SDID_SERIESID_KL   0x00100000
+
 struct kinetis_flash_bank {
        unsigned granularity;
        unsigned bank_ordinal;
@@ -292,11 +349,6 @@ static int kinetis_write_block(struct flash_bank *bank, uint8_t *buffer,
        while (wcount > 0) {
                uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
 
-               retval = target_write_buffer(target, write_algorithm->address, 8,
-                               kinetis_flash_write_code);
-               if (retval != ERROR_OK)
-                       break;
-
                retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer);
                if (retval != ERROR_OK)
                        break;
@@ -437,7 +489,7 @@ static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t
                return result;
 
        /* wait for done */
-       for (i = 0; i < 240; i++) { /* Need Entire Erase Nemui Changed */
+       for (i = 0; i < 240; i++) { /* Need longtime for "Mass Erase" Command Nemui Changed */
                result =
                        target_read_memory(bank->target, FTFx_FSTAT, 1, 1, ftfx_fstat);
 
@@ -471,15 +523,15 @@ static int kinetis_mass_erase(struct flash_bank *bank)
        }
 
        /* check if whole bank is blank */
-       LOG_INFO("Kinetis L Series Erase All Blocks");
+       LOG_INFO("Execute Erase All Blocks");
        /* set command and sector address */
        result = kinetis_ftfx_command(bank, FTFx_CMD_MASSERASE, 0,
-                       0, 0, 0, 0,  0, 0, 0, 0,  &ftfx_fstat);
-       /* Anyway Result, write unsecure byte */
+                                           0, 0, 0, 0,  0, 0, 0, 0,  &ftfx_fstat);
+       /* Anyway Result, write FSEC to unsecure forcely */
        /*      if (result != ERROR_OK)
                return result;*/
 
-       /* Write to MCU security status unsecure in Flash security byte(Work around) */
+       /* Write to MCU security status unsecure in Flash security byte(for Kinetis-L need) */
        LOG_INFO("Write to MCU security status unsecure Anyway!");
        uint8_t padding[4] = {0xFE, 0xFF, 0xFF, 0xFF}; /* Write 0xFFFFFFFE */
 
@@ -495,7 +547,6 @@ static int kinetis_mass_erase(struct flash_bank *bank)
 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");
@@ -505,7 +556,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
        if ((first > bank->num_sectors) || (last > bank->num_sectors))
                return ERROR_FLASH_OPERATION_FAILED;
 
-       if ((first == 0) && (last == (bank->num_sectors - 1)) && (kinfo->klxx))
+       if ((first == 0) && (last == (bank->num_sectors - 1)))
                return kinetis_mass_erase(bank);
 
        /*
@@ -553,12 +604,12 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
                /* fallback to longword write */
                fallback = 1;
                LOG_WARNING("Kinetis L Series supports Program Longword execution only.");
-               LOG_DEBUG("flash write into PFLASH @08%X", offset);
+               LOG_DEBUG("flash write into PFLASH @08%" PRIX32, offset);
 
        } else if (kinfo->flash_class == FC_FLEX_NVM) {
                uint8_t ftfx_fstat;
 
-               LOG_DEBUG("flash write into FlexNVM @%08X", offset);
+               LOG_DEBUG("flash write into FlexNVM @%08" PRIX32, offset);
 
                /* make flex ram available */
                result = kinetis_ftfx_command(bank, FTFx_CMD_SETFLEXRAM, 0x00ff0000, 0, 0, 0, 0,  0, 0, 0, 0,  &ftfx_fstat);
@@ -579,7 +630,7 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
                        LOG_WARNING("ram not ready, fallback to slow longword write (FCNFG: %02X)", buf[0]);
                }
        } else {
-               LOG_DEBUG("flash write into PFLASH @08%X", offset);
+               LOG_DEBUG("flash write into PFLASH @08%" PRIX32, offset);
        }
 
 
@@ -632,8 +683,8 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
                                (void) memcpy(residual_buffer, &buffer[i+4*wc], residual_bc);
                        }
 
-                       LOG_DEBUG("write section @ %08X with length %d bytes",
-                                 offset + i, wc*4);
+                       LOG_DEBUG("write section @ %08" PRIX32 " with length %" PRIu32 " bytes",
+                                 offset + i, (uint32_t)wc*4);
 
                        /* write data to flexram as whole-words */
                        result = target_write_memory(bank->target, FLEXRAM, 4, wc,
@@ -678,7 +729,7 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
                                        "for padding buffer");
                                return ERROR_FAIL;
                        }
-                       LOG_INFO("odd number of bytes to write (%d), extending to %d "
+                       LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " "
                                "and padding with 0xff", old_count, count);
                        memset(buffer, 0xff, count);
                        buffer = memcpy(new_buffer, buffer, old_count);
@@ -698,7 +749,7 @@ static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
                        for (i = 0; i < count; i += 4) {
                                uint8_t ftfx_fstat;
 
-                               LOG_DEBUG("write longword @ %08X", offset + i);
+                               LOG_DEBUG("write longword @ %08" PRIX32, (uint32_t)(offset + i));
 
                                uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
                                memcpy(padding, buffer + i, MIN(4, count-i));
@@ -735,14 +786,62 @@ static int kinetis_read_part_info(struct flash_bank *bank)
        if (result != ERROR_OK)
                return result;
 
-       /* Kinetis L Series SubFamily Check */
        kinfo->klxx = 0;
-       i = (kinfo->sim_sdid >> 20) & 0x0F;
-       if (i == 1) {
+
+       /* K-series MCU? */
+       if ((kinfo->sim_sdid & (~KINETIS_SDID_K_SERIES_MASK)) == 0) {
+               uint32_t mcu_type = kinfo->sim_sdid & KINETIS_K_SDID_TYPE_MASK;
+
+               switch (mcu_type) {
+               case KINETIS_K_SDID_K10_M50:
+               case KINETIS_K_SDID_K20_M50:
+                       /* 1kB sectors */
+                       granularity = 0;
+                       break;
+               case KINETIS_K_SDID_K10_M72:
+               case KINETIS_K_SDID_K20_M72:
+               case KINETIS_K_SDID_K30_M72:
+               case KINETIS_K_SDID_K30_M100:
+               case KINETIS_K_SDID_K40_M72:
+               case KINETIS_K_SDID_K40_M100:
+               case KINETIS_K_SDID_K50_M72:
+                       /* 2kB sectors, 1kB FlexNVM sectors */
+                       granularity = 1;
+                       break;
+               case KINETIS_K_SDID_K10_M100:
+               case KINETIS_K_SDID_K20_M100:
+               case KINETIS_K_SDID_K11:
+               case KINETIS_K_SDID_K12:
+               case KINETIS_K_SDID_K21_M50:
+               case KINETIS_K_SDID_K22_M50:
+               case KINETIS_K_SDID_K51_M72:
+               case KINETIS_K_SDID_K53:
+               case KINETIS_K_SDID_K60_M100:
+                       /* 2kB sectors */
+                       granularity = 2;
+                       break;
+               case KINETIS_K_SDID_K10_M120:
+               case KINETIS_K_SDID_K20_M120:
+               case KINETIS_K_SDID_K21_M120:
+               case KINETIS_K_SDID_K22_M120:
+               case KINETIS_K_SDID_K60_M150:
+               case KINETIS_K_SDID_K70_M150:
+                       /* 4kB sectors */
+                       granularity = 3;
+                       break;
+               default:
+                       LOG_ERROR("Unsupported K-family FAMID");
+                       return ERROR_FLASH_OPER_UNSUPPORTED;
+               }
+       }
+       /* KL-series? */
+       else if ((kinfo->sim_sdid & KINETIS_KL_SDID_SERIESID_MASK) == KINETIS_KL_SDID_SERIESID_KL) {
                kinfo->klxx = 1;
                granularity = 0;
-       } else
-               granularity = (kinfo->sim_sdid >> 7) & 0x03;
+       } else {
+               LOG_ERROR("MCU is unsupported");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
 
        result = target_read_u32(target, SIM_FCFG1, &kinfo->sim_fcfg1);
        if (result != ERROR_OK)
@@ -753,7 +852,7 @@ static int kinetis_read_part_info(struct flash_bank *bank)
                return result;
        fcfg2_pflsh = (kinfo->sim_fcfg2 >> 23) & 0x01;
 
-       LOG_DEBUG("SDID: 0x%08X FCFG1: 0x%08X FCFG2: 0x%08X", kinfo->sim_sdid,
+       LOG_DEBUG("SDID: 0x%08" PRIX32 " FCFG1: 0x%08" PRIX32 " FCFG2: 0x%08" PRIX32, kinfo->sim_sdid,
                        kinfo->sim_fcfg1, kinfo->sim_fcfg2);
 
        fcfg1_nvmsize = (uint8_t)((kinfo->sim_fcfg1 >> 28) & 0x0f);
@@ -821,7 +920,7 @@ static int kinetis_read_part_info(struct flash_bank *bank)
                break;
        }
 
-       LOG_DEBUG("FlexNVM: %d PFlash: %d FlexRAM: %d PFLSH: %d",
+       LOG_DEBUG("FlexNVM: %" PRIu32 " PFlash: %" PRIu32 " FlexRAM: %" PRIu32 " PFLSH: %d",
                  nvm_size, pf_size, ee_size, fcfg2_pflsh);
        if (kinfo->klxx)
                num_blocks = 1;
@@ -1051,26 +1150,13 @@ static int kinetis_blank_check(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-static int kinetis_flash_read(struct flash_bank *bank,
-               uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       LOG_WARNING("kinetis_flash_read not supported yet");
-
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       return ERROR_FLASH_OPERATION_FAILED;
-}
-
 struct flash_driver kinetis_flash = {
        .name = "kinetis",
        .flash_bank_command = kinetis_flash_bank_command,
        .erase = kinetis_erase,
        .protect = kinetis_protect,
        .write = kinetis_write,
-       .read = kinetis_flash_read,
+       .read = default_flash_read,
        .probe = kinetis_probe,
        .auto_probe = kinetis_auto_probe,
        .erase_check = kinetis_blank_check,