From a3245bd7cdd2d8c3740c5e8f31efcd78de67837a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 27 Feb 2010 00:12:38 -0800 Subject: [PATCH] interface: define TMS sequence command For support of SWD we need to be able to clock out special bit sequences over TMS or SWDIO. Create this as a generic operation, not yet called by anything, which is split as usual into: - upper level abstraction ... here, jtag_add_tms_seq(); - midlayer implementation logic hooking that to the lowlevel code; - lowlevel minidriver operation ... here, interface_add_tms_seq(); - message type for request queue, here JTAG_TMS. This is done slightly differently than other operations: there's a flag saying whether the interface driver supports this request. (In fact a flag *word* so upper layers can learn about other capabilities too ... for example, supporting SWD operations.) That approach (flag) lets this method *eventually* be used to eliminate pathmove() and statemove() support from most adapter drivers, by moving all that logic into the mid-layer and increasing uniformity between the various drivers. (Which will in turn reduce subtle bugginess.) Signed-off-by: David Brownell --- src/jtag/commands.h | 39 ++++++++++++++++++++++++++-------- src/jtag/core.c | 29 +++++++++++++++++++++++++ src/jtag/drivers/driver.c | 25 ++++++++++++++++++++++ src/jtag/interface.h | 18 ++++++++++++++++ src/jtag/jtag.h | 4 +++- src/jtag/minidriver.h | 2 ++ src/jtag/minidummy/minidummy.c | 7 ++++++ src/jtag/zy1000/zy1000.c | 11 +++++++++- 8 files changed, 124 insertions(+), 11 deletions(-) diff --git a/src/jtag/commands.h b/src/jtag/commands.h index b10b545369..692eee430f 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -98,19 +98,39 @@ struct sleep_command { uint32_t us; }; +/** + * Encapsulates a series of bits to be clocked out, affecting state + * and mode of the interface. + * + * In JTAG mode these are clocked out on TMS, using TCK. They may be + * used for link resets, transitioning between JTAG and SWD modes, or + * to implement JTAG state machine transitions (implementing pathmove + * or statemove operations). + * + * In SWD mode these are clocked out on SWDIO, using SWCLK, and are + * used for link resets and transitioning between SWD and JTAG modes. + */ +struct tms_command { + /** How many bits should be clocked out. */ + unsigned num_bits; + /** The bits to clock out; the LSB is bit 0 of bits[0]. */ + const uint8_t *bits; +}; + /** * Defines a container type that hold a pointer to a JTAG command * structure of any defined type. */ union jtag_command_container { - struct scan_command* scan; - struct statemove_command* statemove; - struct pathmove_command* pathmove; - struct runtest_command* runtest; - struct stableclocks_command* stableclocks; - struct reset_command* reset; - struct end_state_command* end_state; - struct sleep_command* sleep; + struct scan_command *scan; + struct statemove_command *statemove; + struct pathmove_command *pathmove; + struct runtest_command *runtest; + struct stableclocks_command *stableclocks; + struct reset_command *reset; + struct end_state_command *end_state; + struct sleep_command *sleep; + struct tms_command *tms; }; /** @@ -124,7 +144,8 @@ enum jtag_command_type { JTAG_RESET = 4, JTAG_PATHMOVE = 6, JTAG_SLEEP = 7, - JTAG_STABLECLOCKS = 8 + JTAG_STABLECLOCKS = 8, + JTAG_TMS = 9, }; struct jtag_command { diff --git a/src/jtag/core.c b/src/jtag/core.c index 4f517c098e..7f417b737c 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -488,6 +488,35 @@ void jtag_add_tlr(void) jtag_notify_event(JTAG_TRST_ASSERTED); } +/** + * If supported by the underlying adapter, this clocks a raw bit sequence + * onto TMS for switching betwen JTAG and SWD modes. + * + * DO NOT use this to bypass the integrity checks and logging provided + * by the jtag_add_pathmove() and jtag_add_statemove() calls. + * + * @param nbits How many bits to clock out. + * @param seq The bit sequence. The LSB is bit 0 of seq[0]. + * @param state The JTAG tap state to record on completion. Use + * TAP_INVALID to represent being in in SWD mode. + * + * @todo Update naming conventions to stop assuming everything is JTAG. + */ +int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) +{ + int retval; + + if (!(jtag->supported & DEBUG_CAP_TMS_SEQ)) + return ERROR_JTAG_NOT_IMPLEMENTED; + + jtag_checks(); + cmd_queue_cur_state = state; + + retval = interface_add_tms_seq(nbits, seq); + jtag_set_error(retval); + return retval; +} + void jtag_add_pathmove(int num_states, const tap_state_t *path) { tap_state_t cur_state = cmd_queue_cur_state; diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c index 45c5d10afa..14efe965e7 100644 --- a/src/jtag/drivers/driver.c +++ b/src/jtag/drivers/driver.c @@ -388,6 +388,31 @@ int interface_jtag_add_tlr(void) return ERROR_OK; } +int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq) +{ + struct jtag_command *cmd; + + cmd = cmd_queue_alloc(sizeof(struct jtag_command)); + if (cmd == NULL) + return ERROR_FAIL; + + cmd->type = JTAG_TMS; + cmd->cmd.tms = cmd_queue_alloc(sizeof(*cmd->cmd.tms)); + if (!cmd->cmd.tms) + return ERROR_FAIL; + + /* copy the bits; our caller doesn't guarantee they'll persist */ + cmd->cmd.tms->num_bits = num_bits; + cmd->cmd.tms->bits = buf_cpy(seq, + cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits); + if (!cmd->cmd.tms->bits) + return ERROR_FAIL; + + jtag_queue_command(cmd); + + return ERROR_OK; +} + int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) { /* allocate memory for a new list member */ diff --git a/src/jtag/interface.h b/src/jtag/interface.h index a264d69f27..0d474049e4 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -184,10 +184,28 @@ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf, } #endif // _DEBUG_JTAG_IO_ +/** + * Represents a driver for a debugging interface. + * + * @todo Rename; perhaps "debug_driver". This isn't an interface, + * it's a driver! Also, not all drivers support JTAG. + * + * @todo We need a per-instance structure too, and changes to pass + * that structure to the driver. Instances can for example be in + * either SWD or JTAG modes. This will help remove globals, and + * eventually to cope with systems which have more than one such + * debugging interface. + */ struct jtag_interface { /// The name of the JTAG interface driver. char* name; + /** + * Bit vector listing capabilities exposed by this driver. + */ + unsigned supported; +#define DEBUG_CAP_TMS_SEQ (1 << 0) + /** * Execute queued commands. * @returns ERROR_OK on success, or an error code on failure. diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 055575407a..7e5dc102b7 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -575,6 +575,8 @@ tap_state_t jtag_get_end_state(void); void jtag_add_sleep(uint32_t us); +int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state t); + /** * Function jtag_add_clocks * first checks that the state in which the clocks are to be issued is @@ -693,7 +695,7 @@ int jtag_error_clear(void); /** * Return true if it's safe for a background polling task to access the * JTAG scan chain. Polling may be explicitly disallowed, and is also - * unsafe while nTRST is active or the JTAG clock is gated off., + * unsafe while nTRST is active or the JTAG clock is gated off. */ bool is_jtag_poll_safe(void); diff --git a/src/jtag/minidriver.h b/src/jtag/minidriver.h index 2109c75f69..5caec58b13 100644 --- a/src/jtag/minidriver.h +++ b/src/jtag/minidriver.h @@ -67,6 +67,8 @@ int interface_jtag_add_tlr(void); int interface_jtag_add_pathmove(int num_states, const tap_state_t* path); int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate); +int interface_add_tms_seq(unsigned num_bits, const uint8_t *bits); + /** * This drives the actual srst and trst pins. srst will always be 0 * if jtag_reset_config & RESET_SRST_PULLS_TRST != 0 and ditto for diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c index 9c608cdbb4..6410c2d2be 100644 --- a/src/jtag/minidummy/minidummy.c +++ b/src/jtag/minidummy/minidummy.c @@ -147,6 +147,13 @@ int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) return ERROR_OK; } +int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq) +{ + /* synchronously do the operation here */ + + return ERROR_OK; +} + void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, uint8_t *buffer, int little, int count) { int i; diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c index d920c30b29..e21104c7f4 100644 --- a/src/jtag/zy1000/zy1000.c +++ b/src/jtag/zy1000/zy1000.c @@ -804,7 +804,16 @@ int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) return ERROR_OK; } - +int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq) +{ + /* FIXME just implement this, like pathmove but without + * JTAG-specific state transition checking. Then update + * zy1000_interface to report that it's supported. + * + * Eventually interface_jtag_add_pathmove() could vanish. + */ + return ERROR_JTAG_NOT_IMPLEMENTED; +} void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, uint8_t *buffer, int little, int count) { -- 2.30.2