diff --git a/testjig/production/arm_kinetis_debug.cpp b/testjig/production/arm_kinetis_debug.cpp index c3f1ae3399fa976c6cb4fdd1ea1e670c60d774c1..74a5904b5d4959b51cc95a80dc799ca48d1fdf40 100644 --- a/testjig/production/arm_kinetis_debug.cpp +++ b/testjig/production/arm_kinetis_debug.cpp @@ -29,13 +29,13 @@ bool ARMKinetisDebug::startup() { - uint32_t idr; - uint32_t status; - - // System resets can be slow, give them more time than the default. - const unsigned resetRetries = 2000; + return detect() && resetHalt() && peripheralInit(); +} +bool ARMKinetisDebug::detect() +{ // Make sure we're on a compatible chip. The MDM-AP peripheral is Freescale-specific. + uint32_t idr; if (!apRead(REG_MDM_IDR, idr)) return false; if (idr != 0x001C0000) { @@ -43,51 +43,72 @@ bool ARMKinetisDebug::startup() return false; } - // Put the control register in a known state, and make sure we aren't already in the middle of a reset - if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_CORE_HOLD_RESET)) - return false; - if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, -1, resetRetries)) - return false; - - // System reset - if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_SYS_RESET_REQ)) - return false; - if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, 0)) - return false; - if (!apWrite(REG_MDM_CONTROL, 0)) - return false; - - // Re-initialize the AHB-AP after reset - if (!initMemPort()) - return false; + return true; +} - // Wait until the flash controller is ready & system is out of reset - if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY, -1, resetRetries)) - return false; +bool ARMKinetisDebug::resetHalt() +{ + uint32_t status, dhcsr; - // Enable debugging - if (!memStore(REG_SCB_DHCSR, 0xA05F0001)) - return false; + // System resets can be slow, give them more time than the default. + const unsigned resetRetries = 2000; - // Halt the CPU core. Keep trying, in case we're fighting with watchdog reset :( - unsigned retries = 50; - uint32_t dhcsr; - do { - retries--; - - // Request a halt, and read back status - if (!memStore(REG_SCB_DHCSR, 0xA05F0003)) - return false; - if (!memLoad(REG_SCB_DHCSR, dhcsr)) - return false; - - // Wait for S_HALT acknowledgment bit - } while (!(dhcsr & (1 << 17)) && retries); - if (!retries) { - log(LOG_ERROR, "ARMKinetisDebug: Failed to put CPU in debug halt state. (DHCSR: %08x)", dhcsr); - return false; + // Keep trying to reset/halt, in case we're fighting with watchdog timer :( + unsigned outerRetries = 50; + + while (outerRetries--) { + + // Put the control register in a known state, and make sure we aren't already in the middle of a reset + if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_CORE_HOLD_RESET)) + continue; + if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, -1, resetRetries)) + continue; + + // System reset + if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_SYS_RESET_REQ)) + continue; + if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, 0)) + continue; + if (!apWrite(REG_MDM_CONTROL, 0)) + continue; + + // Wait until the flash controller is ready & system is out of reset. + // Also wait for security bit to be cleared. Early in reset, the chip is determining + // its security status. When the security bit is set, AHB-AP is disabled. + if (!apReadPoll(REG_MDM_STATUS, status, + REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY | REG_MDM_STATUS_SYS_SECURITY, + REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY, + resetRetries)) + continue; + + // Re-initialize the AHB-AP after reset + if (!initMemPort()) + continue; + + // Enable debugging + if (!memStore(REG_SCB_DHCSR, 0xA05F0001)) + continue; + + unsigned haltRetries = 50; + while (haltRetries--) { + // Request a halt, and read back status + if (!memStore(REG_SCB_DHCSR, 0xA05F0003)) + break; + if (!memLoad(REG_SCB_DHCSR, dhcsr)) + break; + if (dhcsr & (1 << 17)) { + // Halted! + return true; + } + } } + log(LOG_ERROR, "ARMKinetisDebug: Failed to put CPU in debug halt state. (DHCSR: %08x)", dhcsr); + return false; +} + +bool ARMKinetisDebug::peripheralInit() +{ // Enable peripheral clocks if (!memStore(REG_SIM_SCGC5, 0x00043F82)) return false; @@ -100,7 +121,6 @@ bool ARMKinetisDebug::startup() if (!memStoreAndVerify(0x20000000, 0x76543210)) return false; - // Good to go! return true; } diff --git a/testjig/production/arm_kinetis_debug.h b/testjig/production/arm_kinetis_debug.h index c7bb402f5b13bcab1003153069db1e2aa3c4eeae..bbd7fac304e8afdba40b7a502b2ffe018f5fcd0d 100644 --- a/testjig/production/arm_kinetis_debug.h +++ b/testjig/production/arm_kinetis_debug.h @@ -28,9 +28,14 @@ class ARMKinetisDebug : public ARMDebug { public: - // Hold the processor core in reset, and initialize peripherals + // First-time initialization, resetting into system halt state. bool startup(); + // Individual parts of startup(): + bool detect(); // Detect supported Kinetis hardware + bool resetHalt(); // Reset into system halt state + bool peripheralInit(); // Initialize peripherals into default state + // Flash mass-erase operation. Works even on protected devices. bool flashMassErase(); };