+
+ enum {
+ FS_PROGRAM_SECTOR = 1,
+ FS_PROGRAM_LONGWORD = 2,
+ FS_PROGRAM_PHRASE = 4, /* Unsupported */
+ } flash_support;
+};
+
+#define MDM_REG_STAT 0x00
+#define MDM_REG_CTRL 0x04
+#define MDM_REG_ID 0xfc
+
+#define MDM_STAT_FMEACK (1<<0)
+#define MDM_STAT_FREADY (1<<1)
+#define MDM_STAT_SYSSEC (1<<2)
+#define MDM_STAT_SYSRES (1<<3)
+#define MDM_STAT_FMEEN (1<<5)
+#define MDM_STAT_BACKDOOREN (1<<6)
+#define MDM_STAT_LPEN (1<<7)
+#define MDM_STAT_VLPEN (1<<8)
+#define MDM_STAT_LLSMODEXIT (1<<9)
+#define MDM_STAT_VLLSXMODEXIT (1<<10)
+#define MDM_STAT_CORE_HALTED (1<<16)
+#define MDM_STAT_CORE_SLEEPDEEP (1<<17)
+#define MDM_STAT_CORESLEEPING (1<<18)
+
+#define MEM_CTRL_FMEIP (1<<0)
+#define MEM_CTRL_DBG_DIS (1<<1)
+#define MEM_CTRL_DBG_REQ (1<<2)
+#define MEM_CTRL_SYS_RES_REQ (1<<3)
+#define MEM_CTRL_CORE_HOLD_RES (1<<4)
+#define MEM_CTRL_VLLSX_DBG_REQ (1<<5)
+#define MEM_CTRL_VLLSX_DBG_ACK (1<<6)
+#define MEM_CTRL_VLLSX_STAT_ACK (1<<7)
+
+#define MDM_ACCESS_TIMEOUT 3000 /* iterations */
+
+static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value)
+{
+ int retval;
+ LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value);
+
+ retval = dap_queue_ap_write(dap, reg, value);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("MDM: failed to queue a write request");
+ return retval;
+ }
+
+ retval = dap_run(dap);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("MDM: dap_run failed");
+ return retval;
+ }
+
+
+ return ERROR_OK;
+}
+
+static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result)
+{
+ int retval;
+ retval = dap_queue_ap_read(dap, reg, result);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("MDM: failed to queue a read request");
+ return retval;
+ }
+
+ retval = dap_run(dap);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("MDM: dap_run failed");
+ return retval;
+ }
+
+ LOG_DEBUG("MDM_REG[0x%02x]: %08" PRIX32, reg, *result);
+ return ERROR_OK;
+}
+
+static int kinetis_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value)
+{
+ uint32_t val;
+ int retval;
+ int timeout = MDM_ACCESS_TIMEOUT;
+
+ do {
+ retval = kinetis_mdm_read_register(dap, reg, &val);
+ if (retval != ERROR_OK || (val & mask) == value)
+ return retval;
+
+ alive_sleep(1);
+ } while (timeout--);
+
+ LOG_DEBUG("MDM: polling timed out");
+ return ERROR_FAIL;
+}
+
+/*
+ * This function implements the procedure to mass erase the flash via
+ * SWD/JTAG on Kinetis K and L series of devices as it is described in
+ * AN4835 "Production Flash Programming Best Practices for Kinetis K-
+ * and L-series MCUs" Section 4.2.1
+ */
+COMMAND_HANDLER(kinetis_mdm_mass_erase)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct cortex_m_common *cortex_m = target_to_cm(target);
+ struct adiv5_dap *dap = cortex_m->armv7m.arm.dap;
+
+ if (!dap) {
+ LOG_ERROR("Cannot perform mass erase with a high-level adapter");
+ return ERROR_FAIL;
+ }
+
+ int retval;
+ const uint8_t original_ap = dap->ap_current;
+
+ /*
+ * ... Power on the processor, or if power has already been
+ * applied, assert the RESET pin to reset the processor. For
+ * devices that do not have a RESET pin, write the System
+ * Reset Request bit in the MDM-AP control register after
+ * establishing communication...
+ */
+
+ /* assert SRST */
+ if (jtag_get_reset_config() & RESET_HAS_SRST)
+ adapter_assert_reset();
+ else
+ LOG_WARNING("Attempting mass erase without hardware reset. This is not reliable; "
+ "it's recommended you connect SRST and use ``reset_config srst_only''.");
+
+ dap_ap_select(dap, 1);
+
+ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MEM_CTRL_SYS_RES_REQ);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /*
+ * ... Read the MDM-AP status register until the Flash Ready bit sets...
+ */
+ retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT,
+ MDM_STAT_FREADY | MDM_STAT_SYSRES,
+ MDM_STAT_FREADY);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("MDM : flash ready timeout");
+ return retval;
+ }
+
+ /*
+ * ... Write the MDM-AP control register to set the Flash Mass
+ * Erase in Progress bit. This will start the mass erase
+ * process...
+ */
+ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL,
+ MEM_CTRL_SYS_RES_REQ | MEM_CTRL_FMEIP);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* As a sanity check make sure that device started mass erase procedure */
+ retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT,
+ MDM_STAT_FMEACK, MDM_STAT_FMEACK);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /*
+ * ... Read the MDM-AP control register until the Flash Mass
+ * Erase in Progress bit clears...
+ */
+ retval = kinetis_mdm_poll_register(dap, MDM_REG_CTRL,
+ MEM_CTRL_FMEIP,
+ 0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /*
+ * ... Negate the RESET signal or clear the System Reset Request
+ * bit in the MDM-AP control register...
+ */
+ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (jtag_get_reset_config() & RESET_HAS_SRST)
+ adapter_deassert_reset();
+
+ dap_ap_select(dap, original_ap);
+ return ERROR_OK;
+}
+
+static const uint32_t kinetis_known_mdm_ids[] = {
+ 0x001C0000, /* Kinetis-K Series */
+ 0x001C0020, /* Kinetis-L/M/V/E Series */