+/*
+ * This command can be used to break a watchdog reset loop when
+ * connecting to an unsecured target. Unlike other commands, halt will
+ * automatically retry as it does not know how far into the boot process
+ * it is when the command is called.
+ */
+COMMAND_HANDLER(kinetis_mdm_halt)
+{
+ 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;
+ int retval;
+ int tries = 0;
+ uint32_t stat;
+
+ if (!dap) {
+ LOG_ERROR("Cannot perform halt with a high-level adapter");
+ return ERROR_FAIL;
+ }
+
+ while (true) {
+ tries++;
+
+ kinetis_mdm_write_register(dap, MDM_REG_CTRL, MDM_CTRL_CORE_HOLD_RES);
+
+ alive_sleep(1);
+
+ retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &stat);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("MDM: failed to read MDM_REG_STAT");
+ continue;
+ }
+
+ /* Repeat setting MDM_CTRL_CORE_HOLD_RES until system is out of
+ * reset with flash ready and without security
+ */
+ if ((stat & (MDM_STAT_FREADY | MDM_STAT_SYSSEC | MDM_STAT_SYSRES))
+ == (MDM_STAT_FREADY | MDM_STAT_SYSRES))
+ break;
+
+ if (tries > MDM_ACCESS_TIMEOUT) {
+ LOG_ERROR("MDM: halt timed out");
+ return ERROR_FAIL;
+ }
+ }
+
+ LOG_DEBUG("MDM: halt succeded after %d attempts.", tries);
+
+ target_poll(target);
+ /* enable polling in case kinetis_check_flash_security_status disabled it */
+ jtag_poll_set_enabled(true);
+
+ alive_sleep(100);
+
+ target->reset_halt = true;
+ target->type->assert_reset(target);
+
+ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("MDM: failed to clear MDM_REG_CTRL");
+ return retval;
+ }
+
+ target->type->deassert_reset(target);
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(kinetis_mdm_reset)
+{
+ 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;
+ int retval;
+
+ if (!dap) {
+ LOG_ERROR("Cannot perform reset with a high-level adapter");
+ return ERROR_FAIL;
+ }
+
+ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MDM_CTRL_SYS_RES_REQ);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("MDM: failed to write MDM_REG_CTRL");
+ return retval;
+ }
+
+ retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT, MDM_STAT_SYSRES, 0);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("MDM: failed to assert reset");
+ return retval;
+ }
+
+ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("MDM: failed to clear MDM_REG_CTRL");
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+