+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/cortex_m.h>
+
+/*
+ * Implementation Notes
+ *
+ * The persistent memories in the Kinetis chip families K10 through
+ * K70 are all manipulated with the Flash Memory Module. Some
+ * variants call this module the FTFE, others call it the FTFL. To
+ * indicate that both are considered here, we use FTFX.
+ *
+ * Within the module, according to the chip variant, the persistent
+ * memory is divided into what Freescale terms Program Flash, FlexNVM,
+ * and FlexRAM. All chip variants have Program Flash. Some chip
+ * variants also have FlexNVM and FlexRAM, which always appear
+ * together.
+ *
+ * A given Kinetis chip may have 1, 2 or 4 blocks of flash. Here we map
+ * each block to a separate bank. Each block size varies by chip and
+ * may be determined by the read-only SIM_FCFG1 register. The sector
+ * size within each bank/block varies by chip, and may be 1, 2 or 4k.
+ * The sector size may be different for flash and FlexNVM.
+ *
+ * The first half of the flash (1 or 2 blocks) is always Program Flash
+ * and always starts at address 0x00000000. The "PFLSH" flag, bit 23
+ * of the read-only SIM_FCFG2 register, determines whether the second
+ * half of the flash is also Program Flash or FlexNVM+FlexRAM. When
+ * PFLSH is set, the second from the first half. When PFLSH is clear,
+ * the second half of flash is FlexNVM and always starts at address
+ * 0x10000000. FlexRAM, which is also present when PFLSH is clear,
+ * always starts at address 0x14000000.
+ *
+ * The Flash Memory Module provides a register set where flash
+ * commands are loaded to perform flash operations like erase and
+ * program. Different commands are available depending on whether
+ * Program Flash or FlexNVM/FlexRAM is being manipulated. Although
+ * the commands used are quite consistent between flash blocks, the
+ * parameters they accept differ according to the flash sector size.
+ *
+ */
+
+/* Addressess */
+#define FLEXRAM 0x14000000
+#define FTFx_FSTAT 0x40020000
+#define FTFx_FCNFG 0x40020001
+#define FTFx_FCCOB3 0x40020004
+#define FTFx_FPROT3 0x40020010
+#define SIM_SDID 0x40048024
+#define SIM_SOPT1 0x40047000
+#define SIM_FCFG1 0x4004804c
+#define SIM_FCFG2 0x40048050
+
+/* Commands */
+#define FTFx_CMD_BLOCKSTAT 0x00
+#define FTFx_CMD_SECTSTAT 0x01
+#define FTFx_CMD_LWORDPROG 0x06
+#define FTFx_CMD_SECTERASE 0x09
+#define FTFx_CMD_SECTWRITE 0x0b
+#define FTFx_CMD_SETFLEXRAM 0x81
+#define FTFx_CMD_MASSERASE 0x44
+
+/* The older 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 newer Kinetis 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
+ *
+ * We assume that if bits 31-16 are 0 then it's an older
+ * K-series MCU.
+ */
+
+#define KINETIS_SOPT1_RAMSIZE_MASK 0x0000F000
+#define KINETIS_SOPT1_RAMSIZE_K24FN1M 0x0000B000
+
+#define KINETIS_SDID_K_SERIES_MASK 0x0000FFFF
+
+#define KINETIS_SDID_DIEID_MASK 0x00000F80
+
+#define KINETIS_SDID_DIEID_K22FN128 0x00000680 /* smaller pflash with FTFA */
+#define KINETIS_SDID_DIEID_K22FN256 0x00000A80
+#define KINETIS_SDID_DIEID_K22FN512 0x00000E80
+#define KINETIS_SDID_DIEID_K24FN256 0x00000700
+
+#define KINETIS_SDID_DIEID_K24FN1M 0x00000300 /* Detect Errata 7534 */
+
+/* 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_SDID_SERIESID_MASK 0x00F00000
+#define KINETIS_SDID_SERIESID_K 0x00000000
+#define KINETIS_SDID_SERIESID_KL 0x00100000
+#define KINETIS_SDID_SERIESID_KW 0x00500000
+#define KINETIS_SDID_SERIESID_KV 0x00600000
+
+#define KINETIS_SDID_SUBFAMID_MASK 0x0F000000
+#define KINETIS_SDID_SUBFAMID_KX0 0x00000000
+#define KINETIS_SDID_SUBFAMID_KX1 0x01000000
+#define KINETIS_SDID_SUBFAMID_KX2 0x02000000
+#define KINETIS_SDID_SUBFAMID_KX3 0x03000000
+#define KINETIS_SDID_SUBFAMID_KX4 0x04000000
+#define KINETIS_SDID_SUBFAMID_KX5 0x05000000
+#define KINETIS_SDID_SUBFAMID_KX6 0x06000000
+
+#define KINETIS_SDID_FAMILYID_MASK 0xF0000000
+#define KINETIS_SDID_FAMILYID_K0X 0x00000000
+#define KINETIS_SDID_FAMILYID_K1X 0x10000000
+#define KINETIS_SDID_FAMILYID_K2X 0x20000000
+#define KINETIS_SDID_FAMILYID_K3X 0x30000000
+#define KINETIS_SDID_FAMILYID_K4X 0x40000000
+#define KINETIS_SDID_FAMILYID_K6X 0x60000000
+#define KINETIS_SDID_FAMILYID_K7X 0x70000000