From e6dac739cffdecc0c65254eb7b3f2942cfff0f68 Mon Sep 17 00:00:00 2001 From: oharboe Date: Mon, 10 Mar 2008 14:07:28 +0000 Subject: - the jtag chain is examined and validated after GDB & telnet servers are up and running. The examination and validation is actually "optional" from the point of view of GDB + telnet servers. Multiple targets should work fine with this. - jtag_speed is dropped(divisor is increased), if jtag examination and validation fails. - the chain is validated 10x to catch the worst jtag_speed offences - added LOG_SILENT that can be used to shut up log. Feeble ersatz for try+catch. - GDB register packets are now always replied in order to make sure that GDB connect works. If the target is not halted, then these packets contain dummy values. git-svn-id: svn://svn.berlios.de/openocd/trunk@483 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- src/jtag/Makefile.am | 2 +- src/jtag/jtag.c | 112 +++++++++++++++++++++++++++++++++++++++++++-------- src/target/arm11.c | 6 --- src/target/armv4_5.c | 6 --- src/target/armv7m.c | 6 --- src/target/target.h | 10 ++++- 6 files changed, 105 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index a35e3f3f..04e50ffd 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -9,7 +9,7 @@ else FTD2XXINC = endif -INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes) +INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes) -I$(top_srcdir)/src/target METASOURCES = AUTO noinst_LIBRARIES = libjtag.a diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c index 430a6ff8..48cd0595 100644 --- a/src/jtag/jtag.c +++ b/src/jtag/jtag.c @@ -28,6 +28,7 @@ #include "command.h" #include "log.h" #include "interpreter.h" +#include "target.h" #include "stdlib.h" #include "string.h" @@ -1327,11 +1328,10 @@ void jtag_sleep(u32 us) /* Try to examine chain layout according to IEEE 1149.1 ยง12 */ -int jtag_examine_chain() +int jtag_examine_chain(u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4] ) { jtag_device_t *device = jtag_devices; scan_field_t field; - u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; int i; int bit_count; int device_count = 0; @@ -1533,9 +1533,36 @@ int jtag_interface_init(struct command_context_s *cmd_ctx) return ERROR_OK; } +extern int jtag_init_chain(struct command_context_s *cmd_ctx); + +static int jtag_sense_handler(void *priv) +{ + struct command_context_s *cmd_ctx; + cmd_ctx=(struct command_context_s *)priv; + + static int scan_complete = 0; + if (!scan_complete) + { + if (jtag_init_chain(cmd_ctx)==ERROR_OK) + { + scan_complete = 1; + } + return ERROR_OK; + } + + return ERROR_OK; +} + +/* OpenOCD will start telnet/gdb servers before the JTAG chain has + * been enumerated. This is to allow e.g. GDB init script to + * run monitor commands to initialize the target so jtag_init_chain() + * will succeed. + * + * A timer callback is added where sensing is retried once every second + * until it succeeds. + */ int jtag_init(struct command_context_s *cmd_ctx) { - int validate_tries = 0; jtag_device_t *device; DEBUG("-"); @@ -1556,24 +1583,76 @@ int jtag_init(struct command_context_s *cmd_ctx) jtag_add_statemove(TAP_TLR); jtag_execute_queue(); + target_register_timer_callback(jtag_sense_handler, 1000, 1, cmd_ctx); + + return ERROR_OK; + } + +static int jtag_test_chain(u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]) +{ + jtag_add_statemove(TAP_TLR); + jtag_execute_queue(); + /* examine chain first, as this could discover the real chain layout */ - if (jtag_examine_chain() != ERROR_OK) + if (jtag_examine_chain(idcode_buffer)!=ERROR_OK) { - ERROR("trying to validate configured JTAG chain anyway..."); + WARNING("trying to validate configured JTAG chain anyway..."); } - while (jtag_validate_chain() != ERROR_OK) - { - validate_tries++; - if (validate_tries > 5) + return jtag_validate_chain(); +} + +/* Unless we can do this successfully 10 times, we're not + * satisfied with the quality of the JTAG communication. + * + * Since we're continously repeating this operation, be a bit + * wary of filling the log with megabytes of data. + * + * Keep increasing the jtag_divisor until we've got a solid + * result. + */ +int jtag_init_chain(struct command_context_s *cmd_ctx) +{ + int i, j; + int retval; + for (i=jtag_speed; i<64; i++) + { + u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; + jtag_speed=i; + if ((retval=jtag->speed(jtag_speed))!=ERROR_OK) + continue; + for (j=0; j<10; j++) { - ERROR("Could not validate JTAG chain, exit"); - return ERROR_JTAG_INVALID_INTERFACE; + u8 idcode_current[JTAG_MAX_CHAIN_SIZE * 4]; + enum log_levels save_log_level=debug_level; + /* avoid spamming log */ + debug_level=LOG_SILENT; + retval=jtag_test_chain(idcode_current); + if (retval==ERROR_OK) + { + if (j==0) + { + memcpy(idcode_buffer, idcode_current, sizeof(idcode_buffer)); + } else + { + retval=(memcmp(idcode_buffer, idcode_current, sizeof(idcode_buffer))==0)?ERROR_OK:ERROR_JTAG_INIT_FAILED; + } + } + debug_level = save_log_level; + if (retval!=ERROR_OK) + { + break; + } } - usleep(10000); + if (retval==ERROR_OK) + { + /* Print out result */ + INFO("Succeeded jtag chain test jtag_speed=%d", jtag_speed); + return jtag_test_chain(idcode_buffer); + } + DEBUG("Failed jtag chain test, dropping clock rate. Trying jtag_speed=%d\n", i+1); } - - return ERROR_OK; + return retval; } int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) @@ -1778,12 +1857,11 @@ int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char if (argc > 0) { + jtag_speed = strtoul(args[0], NULL, 0); /* this command can be called during CONFIG, * in which case jtag isn't initialized */ if (jtag) - jtag->speed(strtoul(args[0], NULL, 0)); - else - jtag_speed = strtoul(args[0], NULL, 0); + jtag->speed(jtag_speed); } return ERROR_OK; diff --git a/src/target/arm11.c b/src/target/arm11.c index a197945f..890b836b 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1040,12 +1040,6 @@ int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], i arm11_common_t * arm11 = target->arch_info; - if (target->state != TARGET_HALTED) - { - WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - *reg_list_size = ARM11_GDB_REGISTER_COUNT; *reg_list = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT); diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 82e65c78..ff5f4735 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -474,12 +474,6 @@ int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list armv4_5_common_t *armv4_5 = target->arch_info; int i; - if (target->state != TARGET_HALTED) - { - ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - *reg_list_size = 26; *reg_list = malloc(sizeof(reg_t*) * (*reg_list_size)); diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 6ee5903a..f1f0ac96 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -321,12 +321,6 @@ int armv7m_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_ armv7m_common_t *armv7m = target->arch_info; int i; - if (target->state != TARGET_HALTED) - { - ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - *reg_list_size = 26; *reg_list = malloc(sizeof(reg_t*) * (*reg_list_size)); diff --git a/src/target/target.h b/src/target/target.h index 8d70e77e..e0286650 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -127,7 +127,15 @@ typedef struct target_type_s int (*soft_reset_halt)(struct target_s *target); int (*prepare_reset_halt)(struct target_s *target); - /* target register access for gdb */ + /* target register access for gdb. + * + * Danger! this function will succeed even if the target is running + * and return a register list with dummy values. + * + * The reason is that GDB connection will fail without a valid register + * list, however it is after GDB is connected that monitor commands can + * be run to properly initialize the target + */ int (*get_gdb_reg_list)(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size); /* target memory access -- cgit v1.2.3