static const char *jtag_event_strings[] =
{
- [JTAG_TRST_ASSERTED] = "JTAG controller reset (RESET or TRST)",
+ [JTAG_TRST_ASSERTED] = "JTAG controller reset (TLR or TRST)",
[JTAG_TAP_EVENT_ENABLE] = "TAP enabled",
[JTAG_TAP_EVENT_DISABLE] = "TAP disabled",
};
+/*
+ * JTAG adapters must initialize with TRST and SRST de-asserted
+ * (they're negative logic, so that means *high*)
+ */
static int jtag_trst = 0;
static int jtag_srst = 0;
/* speed in kHz*/
static int speed_khz = 0;
-/* flag if the kHz speed was defined */
-static bool hasKHz = false;
+/* speed to fallback to when RCLK is requested but not supported */
+static int rclk_fallback_speed_khz = 0;
+static enum {CLOCK_MODE_SPEED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
static int jtag_speed = 0;
static struct jtag_interface_s *jtag = NULL;
void jtag_add_reset(int req_tlr_or_trst, int req_srst)
{
int trst_with_tlr = 0;
+ int new_srst = 0;
+ int new_trst = 0;
- /* FIX!!! there are *many* different cases here. A better
- * approach is needed for legal combinations of transitions...
+ /* Without SRST, we must use target-specific JTAG operations
+ * on each target; callers should not be requesting SRST when
+ * that signal doesn't exist.
+ *
+ * RESET_SRST_PULLS_TRST is a board or chip level quirk, which
+ * can kick in even if the JTAG adapter can't drive TRST.
*/
- if ((jtag_reset_config & RESET_HAS_SRST)&&
- (jtag_reset_config & RESET_HAS_TRST)&&
- ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0))
- {
- if (((req_tlr_or_trst&&!jtag_trst)||
- (!req_tlr_or_trst && jtag_trst))&&
- ((req_srst&&!jtag_srst)||
- (!req_srst && jtag_srst)))
- {
- /* FIX!!! srst_pulls_trst allows 1,1 => 0,0 transition.... */
- //LOG_ERROR("BUG: transition of req_tlr_or_trst and req_srst in the same jtag_add_reset() call is undefined");
+ if (req_srst) {
+ if (!(jtag_reset_config & RESET_HAS_SRST)) {
+ LOG_ERROR("BUG: can't assert SRST");
+ jtag_set_error(ERROR_FAIL);
+ return;
+ }
+ if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0
+ && !req_tlr_or_trst) {
+ LOG_ERROR("BUG: can't assert only SRST");
+ jtag_set_error(ERROR_FAIL);
+ return;
}
+ new_srst = 1;
}
- /* Make sure that jtag_reset_config allows the requested reset */
- /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */
- if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (!req_tlr_or_trst))
- {
- LOG_ERROR("BUG: requested reset would assert trst");
- jtag_set_error(ERROR_FAIL);
- return;
+ /* JTAG reset (entry to TAP_RESET state) can always be achieved
+ * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE
+ * state first. TRST accelerates it, and bypasses those states.
+ *
+ * RESET_TRST_PULLS_SRST is a board or chip level quirk, which
+ * can kick in even if the JTAG adapter can't drive SRST.
+ */
+ if (req_tlr_or_trst) {
+ if (!(jtag_reset_config & RESET_HAS_TRST))
+ trst_with_tlr = 1;
+ else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0
+ && !req_srst)
+ trst_with_tlr = 1;
+ else
+ new_trst = 1;
}
- /* if TRST pulls SRST, we reset with TAP T-L-R */
- if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_tlr_or_trst)) && (req_srst == 0))
- {
- trst_with_tlr = 1;
- }
+ /* Maybe change TRST and/or SRST signal state */
+ if (jtag_srst != new_srst || jtag_trst != new_trst) {
+ int retval;
- if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
- {
- LOG_ERROR("BUG: requested SRST assertion, but the current configuration doesn't support this");
- jtag_set_error(ERROR_FAIL);
- return;
- }
+ retval = interface_jtag_add_reset(new_trst, new_srst);
+ if (retval != ERROR_OK)
+ jtag_set_error(retval);
+ else
+ retval = jtag_execute_queue();
- if (req_tlr_or_trst)
- {
- if (!trst_with_tlr && (jtag_reset_config & RESET_HAS_TRST))
- {
- jtag_trst = 1;
- } else
- {
- trst_with_tlr = 1;
+ if (retval != ERROR_OK) {
+ LOG_ERROR("TRST/SRST error %d", retval);
+ return;
}
- } else
- {
- jtag_trst = 0;
- }
-
- jtag_srst = req_srst;
-
- int retval = interface_jtag_add_reset(jtag_trst, jtag_srst);
- if (retval != ERROR_OK)
- {
- jtag_set_error(retval);
- return;
}
- jtag_execute_queue();
- if (jtag_srst)
- {
- LOG_DEBUG("SRST line asserted");
- }
- else
- {
- LOG_DEBUG("SRST line released");
- if (jtag_nsrst_delay)
- jtag_add_sleep(jtag_nsrst_delay * 1000);
+ /* SRST resets everything hooked up to that signal */
+ if (jtag_srst != new_srst) {
+ jtag_srst = new_srst;
+ if (jtag_srst)
+ LOG_DEBUG("SRST line asserted");
+ else {
+ LOG_DEBUG("SRST line released");
+ if (jtag_nsrst_delay)
+ jtag_add_sleep(jtag_nsrst_delay * 1000);
+ }
}
- if (trst_with_tlr)
- {
- LOG_DEBUG("JTAG reset with RESET instead of TRST");
+ /* Maybe enter the JTAG TAP_RESET state ...
+ * - using only TMS, TCK, and the JTAG state machine
+ * - or else more directly, using TRST
+ *
+ * TAP_RESET should be invisible to non-debug parts of the system.
+ */
+ if (trst_with_tlr) {
+ LOG_DEBUG("JTAG reset with TLR instead of TRST");
jtag_set_end_state(TAP_RESET);
jtag_add_tlr();
- return;
- }
- if (jtag_trst)
- {
- /* we just asserted nTRST, so we're now in Test-Logic-Reset,
- * and inform possible listeners about this
- */
- LOG_DEBUG("TRST line asserted");
- tap_set_state(TAP_RESET);
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
- }
- else
- {
- if (jtag_ntrst_delay)
- jtag_add_sleep(jtag_ntrst_delay * 1000);
+ } else if (jtag_trst != new_trst) {
+ jtag_trst = new_trst;
+ if (jtag_trst) {
+ /* we just asserted nTRST, so we're now in TAP_RESET;
+ * inform possible listeners about this
+ *
+ * REVISIT asserting TRST is less significant than
+ * being in TAP_RESET ... both entries (TRST, TLR)
+ * should trigger a callback.
+ */
+ LOG_DEBUG("TRST line asserted");
+ tap_set_state(TAP_RESET);
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+ } else {
+ LOG_DEBUG("TRST line released");
+ if (jtag_ntrst_delay)
+ jtag_add_sleep(jtag_ntrst_delay * 1000);
+ }
}
}
{
tap->enabled = !tap->disabled_after_reset;
+ /* current instruction is either BYPASS or IDCODE */
buf_set_ones(tap->cur_instr, tap->ir_length);
tap->bypass = 1;
}
LOG_ERROR("JTAG interface has to be specified, see \"interface\" command");
return ERROR_JTAG_INVALID_INTERFACE;
}
- if (hasKHz)
- {
- jtag_interface->khz(jtag_get_speed_khz(), &jtag_speed);
- hasKHz = false;
- }
+ jtag = jtag_interface;
if (jtag_interface->init() != ERROR_OK)
+ {
+ jtag = NULL;
return ERROR_JTAG_INIT_FAILED;
+ }
+
+ int requested_khz = jtag_get_speed_khz();
+ int actual_khz = requested_khz;
+ int retval = jtag_get_speed_readable(&actual_khz);
+ if (ERROR_OK != retval)
+ LOG_INFO("interface specific clock speed value %d", jtag_get_speed());
+ else if (actual_khz)
+ {
+ if ((CLOCK_MODE_RCLK == clock_mode)
+ || ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz))
+ {
+ LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz"
+ , actual_khz);
+ }
+ else
+ LOG_INFO("clock speed %d kHz", actual_khz);
+ }
+ else
+ LOG_INFO("RCLK (adaptive clock speed)");
- jtag = jtag_interface;
return ERROR_OK;
}
if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK)
return retval;
- LOG_DEBUG("Trying to bring the JTAG controller to life by asserting TRST / RESET");
+ LOG_DEBUG("Trying to bring the JTAG controller to life by asserting TRST / TLR");
/* Reset can happen after a power cycle.
*
- * Ideally we would only assert TRST or run RESET before the target reset.
+ * Ideally we would only assert TRST or run TLR before the target reset.
*
* However w/srst_pulls_trst, trst is asserted together with the target
* reset whether we want it or not.
* NB! order matters!!!! srst *can* disconnect JTAG circuitry
*
*/
- jtag_add_reset(1, 0); /* RESET or TRST */
+ jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
if (jtag_reset_config & RESET_HAS_SRST)
{
jtag_add_reset(1, 1);
return jtag_init_reset(cmd_ctx);
}
-void jtag_set_speed_khz(unsigned khz)
-{
- speed_khz = khz;
-}
unsigned jtag_get_speed_khz(void)
{
return speed_khz;
}
-int jtag_config_khz(unsigned khz)
-{
- LOG_DEBUG("handle jtag khz");
- jtag_set_speed_khz(khz);
- int cur_speed = 0;
+static int jtag_khz_to_speed(unsigned khz, int* speed)
+{
+ LOG_DEBUG("convert khz to interface specific speed value");
+ speed_khz = khz;
if (jtag != NULL)
{
LOG_DEBUG("have interface set up");
int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
if (ERROR_OK != retval)
{
- jtag_set_speed_khz(0);
return retval;
}
- cur_speed = speed_div1;
+ *speed = speed_div1;
}
- return jtag_set_speed(cur_speed);
+ return ERROR_OK;
}
-int jtag_get_speed(void)
+static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int* speed)
{
- return jtag_speed;
+ int retval = jtag_khz_to_speed(0, speed);
+ if ((ERROR_OK != retval) && fallback_speed_khz)
+ {
+ LOG_DEBUG("trying fallback speed...");
+ retval = jtag_khz_to_speed(fallback_speed_khz, speed);
+ }
+ return retval;
}
-int jtag_set_speed(int speed)
+static int jtag_set_speed(int speed)
{
jtag_speed = speed;
/* this command can be called during CONFIG,
* in which case jtag isn't initialized */
- hasKHz = !jtag;
return jtag ? jtag->speed(speed) : ERROR_OK;
}
-int jtag_get_speed_readable(int *speed)
+int jtag_config_speed(int speed)
+{
+ LOG_DEBUG("handle jtag speed");
+ clock_mode = CLOCK_MODE_SPEED;
+ return jtag_set_speed(speed);
+}
+
+int jtag_config_khz(unsigned khz)
+{
+ LOG_DEBUG("handle jtag khz");
+ clock_mode = CLOCK_MODE_KHZ;
+ int speed = 0;
+ int retval = jtag_khz_to_speed(khz, &speed);
+ return (ERROR_OK != retval) ? retval : jtag_set_speed(speed);
+}
+
+int jtag_config_rclk(unsigned fallback_speed_khz)
{
- return jtag ? jtag->speed_div(jtag_get_speed(), speed) : ERROR_OK;
+ LOG_DEBUG("handle jtag rclk");
+ clock_mode = CLOCK_MODE_RCLK;
+ rclk_fallback_speed_khz = fallback_speed_khz;
+ int speed = 0;
+ int retval = jtag_rclk_to_speed(fallback_speed_khz, &speed);
+ return (ERROR_OK != retval) ? retval : jtag_set_speed(speed);
}
+int jtag_get_speed(void)
+{
+ int speed;
+ switch(clock_mode)
+ {
+ case CLOCK_MODE_SPEED:
+ speed = jtag_speed;
+ break;
+ case CLOCK_MODE_KHZ:
+ jtag_khz_to_speed(jtag_get_speed_khz(), &speed);
+ break;
+ case CLOCK_MODE_RCLK:
+ jtag_rclk_to_speed(rclk_fallback_speed_khz, &speed);
+ break;
+ default:
+ LOG_ERROR("BUG: unknown jtag clock mode");
+ speed = 0;
+ break;
+ }
+ return speed;
+}
+
+int jtag_get_speed_readable(int *khz)
+{
+ return jtag ? jtag->speed_div(jtag_get_speed(), khz) : ERROR_OK;
+}
void jtag_set_verify(bool enable)
{