diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2010-02-27 00:12:38 -0800 |
---|---|---|
committer | David Brownell <dbrownell@users.sourceforge.net> | 2010-02-27 00:12:38 -0800 |
commit | a3245bd7cdd2d8c3740c5e8f31efcd78de67837a (patch) | |
tree | 37448ab9163c86ea221c821b956be11ebd06ebe8 | |
parent | 4a64820f230a267b1f2e36d4be567074e5b8cb76 (diff) | |
download | riscv-openocd-a3245bd7cdd2d8c3740c5e8f31efcd78de67837a.zip riscv-openocd-a3245bd7cdd2d8c3740c5e8f31efcd78de67837a.tar.gz riscv-openocd-a3245bd7cdd2d8c3740c5e8f31efcd78de67837a.tar.bz2 |
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 <dbrownell@users.sourceforge.net>
-rw-r--r-- | src/jtag/commands.h | 39 | ||||
-rw-r--r-- | src/jtag/core.c | 29 | ||||
-rw-r--r-- | src/jtag/drivers/driver.c | 25 | ||||
-rw-r--r-- | src/jtag/interface.h | 18 | ||||
-rw-r--r-- | src/jtag/jtag.h | 4 | ||||
-rw-r--r-- | src/jtag/minidriver.h | 2 | ||||
-rw-r--r-- | src/jtag/minidummy/minidummy.c | 7 | ||||
-rw-r--r-- | 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 b10b545..692eee4 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -99,18 +99,38 @@ struct sleep_command { }; /** + * 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 4f517c0..7f417b7 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 45c5d10..14efe96 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 a264d69..0d47404 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -184,11 +184,29 @@ 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 0555754..7e5dc10 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 2109c75..5caec58 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 9c608cd..6410c2d 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 d920c30..e21104c 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) { |