* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "swd.h"
#include "interface.h"
#include <transport/transport.h>
+#include <helper/jep106.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
* List all TAPs that have been created.
*/
static struct jtag_tap *__jtag_all_taps;
-/**
- * The number of TAPs in the __jtag_all_taps list, used to track the
- * assigned chain position to new TAPs
- */
-static unsigned jtag_num_taps;
static enum reset_types jtag_reset_config = RESET_NONE;
tap_state_t cmd_queue_cur_state = TAP_RESET;
unsigned jtag_tap_count(void)
{
- return jtag_num_taps;
+ struct jtag_tap *t = jtag_all_taps();
+ unsigned n = 0;
+ while (t) {
+ n++;
+ t = t->next_tap;
+ }
+ return n;
}
unsigned jtag_tap_count_enabled(void)
/** Append a new TAP to the chain of all taps. */
void jtag_tap_add(struct jtag_tap *t)
{
- t->abs_chain_position = jtag_num_taps++;
+ unsigned jtag_num_taps = 0;
struct jtag_tap **tap = &__jtag_all_taps;
- while (*tap != NULL)
+ while (*tap != NULL) {
+ jtag_num_taps++;
tap = &(*tap)->next_tap;
+ }
*tap = t;
+ t->abs_chain_position = jtag_num_taps;
}
/* returns a pointer to the n-th device in the scan chain */
if (adapter_nsrst_delay)
jtag_add_sleep(adapter_nsrst_delay * 1000);
}
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ LOG_ERROR("SRST timings error");
+ return;
+ }
}
}
alive_sleep((us+999)/1000);
}
-/* Maximum number of enabled JTAG devices we expect in the scan chain,
- * plus one (to detect garbage at the end). Devices that don't support
- * IDCODE take up fewer bits, possibly allowing a few more devices.
- */
-#define JTAG_MAX_CHAIN_SIZE 20
+#define JTAG_MAX_AUTO_TAPS 20
+#define EXTRACT_JEP106_BANK(X) (((X) & 0xf00) >> 8)
+#define EXTRACT_JEP106_ID(X) (((X) & 0xfe) >> 1)
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
#define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28)
};
/* initialize to the end of chain ID value */
- for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
+ for (unsigned i = 0; i < num_idcode; i++)
buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG);
jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE);
{
log_printf_lf(level, __FILE__, __LINE__, __func__,
"JTAG tap: %s %16.16s: 0x%08x "
- "(mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)",
+ "(mfg: 0x%3.3x (%s), part: 0x%4.4x, ver: 0x%1.1x)",
name, msg,
(unsigned int)idcode,
(unsigned int)EXTRACT_MFG(idcode),
+ jep106_manufacturer(EXTRACT_JEP106_BANK(idcode), EXTRACT_JEP106_ID(idcode)),
(unsigned int)EXTRACT_PART(idcode),
(unsigned int)EXTRACT_VER(idcode));
}
static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
{
- uint32_t idcode = tap->idcode;
- /* ignore expected BYPASS codes; warn otherwise */
- if (0 == tap->expected_ids_cnt && !idcode)
+ if (tap->expected_ids_cnt == 0 || !tap->hasidcode)
return true;
/* optionally ignore the JTAG version field - bits 28-31 of IDCODE */
uint32_t mask = tap->ignore_version ? ~(0xf << 28) : ~0;
-
- idcode &= mask;
+ uint32_t idcode = tap->idcode & mask;
/* Loop over the expected identification codes and test for a match */
- unsigned ii, limit = tap->expected_ids_cnt;
-
- for (ii = 0; ii < limit; ii++) {
+ for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) {
uint32_t expected = tap->expected_ids[ii] & mask;
if (idcode == expected)
/* If none of the expected ids matched, warn */
jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED",
tap->dotted_name, tap->idcode);
- for (ii = 0; ii < limit; ii++) {
+ for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) {
char msg[32];
- snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, limit);
+ snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, tap->expected_ids_cnt);
jtag_examine_chain_display(LOG_LVL_ERROR, msg,
tap->dotted_name, tap->expected_ids[ii]);
}
*/
static int jtag_examine_chain(void)
{
- uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
- unsigned bit_count;
int retval;
- int tapcount = 0;
- bool autoprobe = false;
+ unsigned max_taps = jtag_tap_count();
+
+ /* Autoprobe up to this many. */
+ if (max_taps < JTAG_MAX_AUTO_TAPS)
+ max_taps = JTAG_MAX_AUTO_TAPS;
+
+ /* Add room for end-of-chain marker. */
+ max_taps++;
+
+ uint8_t *idcode_buffer = malloc(max_taps * 4);
+ if (idcode_buffer == NULL)
+ return ERROR_JTAG_INIT_FAILED;
/* DR scan to collect BYPASS or IDCODE register contents.
* Then make sure the scan data has both ones and zeroes.
*/
LOG_DEBUG("DR scan interrogation for IDCODE/BYPASS");
- retval = jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
+ retval = jtag_examine_chain_execute(idcode_buffer, max_taps);
if (retval != ERROR_OK)
- return retval;
- if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE))
- return ERROR_JTAG_INIT_FAILED;
+ goto out;
+ if (!jtag_examine_chain_check(idcode_buffer, max_taps)) {
+ retval = ERROR_JTAG_INIT_FAILED;
+ goto out;
+ }
- /* point at the 1st tap */
+ /* Point at the 1st predefined tap, if any */
struct jtag_tap *tap = jtag_tap_next_enabled(NULL);
- if (!tap)
- autoprobe = true;
-
- for (bit_count = 0;
- tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
- tap = jtag_tap_next_enabled(tap)) {
+ unsigned bit_count = 0;
+ unsigned autocount = 0;
+ for (unsigned i = 0; i < max_taps; i++) {
+ assert(bit_count < max_taps * 32);
uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32);
+ /* No predefined TAP? Auto-probe. */
+ if (tap == NULL) {
+ /* Is there another TAP? */
+ if (jtag_idcode_is_final(idcode))
+ break;
+
+ /* Default everything in this TAP except IR length.
+ *
+ * REVISIT create a jtag_alloc(chip, tap) routine, and
+ * share it with jim_newtap_cmd().
+ */
+ tap = calloc(1, sizeof *tap);
+ if (!tap) {
+ retval = ERROR_FAIL;
+ goto out;
+ }
+
+ tap->chip = alloc_printf("auto%u", autocount++);
+ tap->tapname = strdup("tap");
+ tap->dotted_name = alloc_printf("%s.%s", tap->chip, tap->tapname);
+
+ tap->ir_length = 0; /* ... signifying irlen autoprobe */
+ tap->ir_capture_mask = 0x03;
+ tap->ir_capture_value = 0x01;
+
+ tap->enabled = true;
+
+ jtag_tap_init(tap);
+ }
+
if ((idcode & 1) == 0) {
/* Zero for LSB indicates a device in bypass */
- LOG_INFO("TAP %s does not have IDCODE",
- tap->dotted_name);
- idcode = 0;
+ LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name);
tap->hasidcode = false;
+ tap->idcode = 0;
bit_count += 1;
} else {
/* Friendly devices support IDCODE */
tap->hasidcode = true;
- jtag_examine_chain_display(LOG_LVL_INFO,
- "tap/device found",
- tap->dotted_name, idcode);
+ tap->idcode = idcode;
+ jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", tap->dotted_name, idcode);
bit_count += 32;
}
- tap->idcode = idcode;
/* ensure the TAP ID matches what was expected */
if (!jtag_examine_chain_match_tap(tap))
retval = ERROR_JTAG_INIT_SOFT_FAIL;
- }
-
- /* Fail if too many TAPs were enabled for us to verify them all. */
- if (tap) {
- LOG_ERROR("Too many TAPs enabled; '%s' ignored.",
- tap->dotted_name);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- /* if autoprobing, the tap list is still empty ... populate it! */
- while (autoprobe && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31) {
- uint32_t idcode;
- char buf[12];
-
- /* Is there another TAP? */
- idcode = buf_get_u32(idcode_buffer, bit_count, 32);
- if (jtag_idcode_is_final(idcode))
- break;
-
- /* Default everything in this TAP except IR length.
- *
- * REVISIT create a jtag_alloc(chip, tap) routine, and
- * share it with jim_newtap_cmd().
- */
- tap = calloc(1, sizeof *tap);
- if (!tap)
- return ERROR_FAIL;
-
- sprintf(buf, "auto%d", tapcount++);
- tap->chip = strdup(buf);
- tap->tapname = strdup("tap");
-
- sprintf(buf, "%s.%s", tap->chip, tap->tapname);
- tap->dotted_name = strdup(buf);
-
- /* tap->ir_length == 0 ... signifying irlen autoprobe */
- tap->ir_capture_mask = 0x03;
- tap->ir_capture_value = 0x01;
-
- tap->enabled = true;
-
- if ((idcode & 1) == 0) {
- bit_count += 1;
- tap->hasidcode = false;
- } else {
- bit_count += 32;
- tap->hasidcode = true;
- tap->idcode = idcode;
-
- tap->expected_ids_cnt = 1;
- tap->expected_ids = malloc(sizeof(uint32_t));
- tap->expected_ids[0] = idcode;
- }
-
- LOG_WARNING("AUTO %s - use \"jtag newtap "
- "%s %s -expected-id 0x%8.8" PRIx32 " ...\"",
- tap->dotted_name, tap->chip, tap->tapname,
- tap->idcode);
- jtag_tap_init(tap);
+ tap = jtag_tap_next_enabled(tap);
}
/* After those IDCODE or BYPASS register values should be
* only the data we fed into the scan chain.
*/
- if (jtag_examine_chain_end(idcode_buffer, bit_count,
- 8 * sizeof(idcode_buffer))) {
- LOG_ERROR("double-check your JTAG setup (interface, "
- "speed, missing TAPs, ...)");
- return ERROR_JTAG_INIT_FAILED;
+ if (jtag_examine_chain_end(idcode_buffer, bit_count, max_taps * 32)) {
+ LOG_ERROR("double-check your JTAG setup (interface, speed, ...)");
+ retval = ERROR_JTAG_INIT_FAILED;
+ goto out;
}
/* Return success or, for backwards compatibility if only
* some IDCODE values mismatched, a soft/continuable fault.
*/
+out:
+ free(idcode_buffer);
return retval;
}
* least two bits. Guessing will fail if (a) any TAP does
* not conform to the JTAG spec; or (b) when the upper bits
* captured from some conforming TAP are nonzero. Or if
- * (c) an IR length is longer than 32 bits -- which is only
+ * (c) an IR length is longer than JTAG_IRLEN_MAX bits,
* an implementation limit, which could someday be raised.
*
* REVISIT optimization: if there's a *single* TAP we can
if (tap->ir_length == 0) {
tap->ir_length = 2;
while ((val = buf_get_u64(ir_test, chain_pos, tap->ir_length + 1)) == 1
- && tap->ir_length <= 64) {
+ && tap->ir_length < JTAG_IRLEN_MAX) {
tap->ir_length++;
}
- LOG_WARNING("AUTO %s - use \"... -irlen %d\"",
- jtag_tap_name(tap), tap->ir_length);
+ LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -irlen %d "
+ "-expected-id 0x%08" PRIx32 "\"",
+ tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode);
}
/* Validate the two LSBs, which must be 01 per JTAG spec.
{
jtag_unregister_event_callback(&jtag_reset_callback, tap);
- /** @todo is anything missing? no memory leaks please */
+ struct jtag_tap_event_action *jteap = tap->event_action;
+ while (jteap) {
+ struct jtag_tap_event_action *next = jteap->next;
+ Jim_DecrRefCount(jteap->interp, jteap->body);
+ free(jteap);
+ jteap = next;
+ }
+
free(tap->expected);
+ free(tap->expected_mask);
free(tap->expected_ids);
+ free(tap->cur_instr);
free(tap->chip);
free(tap->tapname);
free(tap->dotted_name);
int adapter_quit(void)
{
- if (!jtag || !jtag->quit)
- return ERROR_OK;
+ if (jtag && jtag->quit) {
+ /* close the JTAG interface */
+ int result = jtag->quit();
+ if (ERROR_OK != result)
+ LOG_ERROR("failed: %d", result);
+ }
- /* close the JTAG interface */
- int result = jtag->quit();
- if (ERROR_OK != result)
- LOG_ERROR("failed: %d", result);
+ struct jtag_tap *t = jtag_all_taps();
+ while (t) {
+ struct jtag_tap *n = t->next_tap;
+ jtag_tap_free(t);
+ t = n;
+ }
return ERROR_OK;
}
* REVISIT once Tcl code can read the reset_config modes, this won't
* need to be a C routine at all...
*/
- jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
if (jtag_reset_config & RESET_HAS_SRST) {
jtag_add_reset(1, 1);
if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0)
jtag_add_reset(0, 1);
+ } else {
+ jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
}
/* some targets enable us to connect with srst asserted */
int jtag_get_trst(void)
{
- return jtag_trst;
+ return jtag_trst == 1;
}
int jtag_get_srst(void)
{
- return jtag_srst;
+ return jtag_srst == 1;
}
void jtag_set_nsrst_delay(unsigned delay)
jtag_add_reset(0, 1);
} else if (transport_is_swd())
swd_add_reset(1);
- else if (transport_is_cmsis_dap())
- swd_add_reset(1); /* FIXME */
else if (get_current_transport() != NULL)
LOG_ERROR("reset is not supported on %s",
get_current_transport()->name);
jtag_add_reset(0, 0);
else if (transport_is_swd())
swd_add_reset(0);
- else if (transport_is_cmsis_dap())
- swd_add_reset(0); /* FIXME */
else if (get_current_transport() != NULL)
LOG_ERROR("reset is not supported on %s",
get_current_transport()->name);
else
LOG_ERROR("transport is not selected");
}
+
+int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
+ uint32_t port_size, unsigned int *trace_freq)
+{
+ if (jtag->config_trace)
+ return jtag->config_trace(enabled, pin_protocol, port_size,
+ trace_freq);
+ else if (enabled) {
+ LOG_ERROR("The selected interface does not support tracing");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+int adapter_poll_trace(uint8_t *buf, size_t *size)
+{
+ if (jtag->poll_trace)
+ return jtag->poll_trace(buf, size);
+
+ return ERROR_FAIL;
+}