This is an automated email from Gerrit. Jörg Fischer ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/1137
-- gerrit commit 25aa9c0c1b4ffb2ecca93e0e31e1faf5bbfd3175 Author: Joerg Fischer <[email protected]> Date: Sun Feb 10 21:45:30 2013 +0100 Add SWD mode for versaloon This patch makes SWD mode work for the versaloon interface. It massacrates adi_v5_swd.c and touches some other things it probably shouldn't. Includes config files for an example board - the CCC r0ket - which uses the SWD only LPC1343 as MCU. Change-Id: Idd8b22ff6d012bca3d833b3b4236d936ffbe2daa Signed-off-by: Joerg Fischer <[email protected]> diff --git a/src/jtag/commands.h b/src/jtag/commands.h index da563e9..8348a24 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -118,6 +118,17 @@ struct tms_command { const uint8_t *bits; }; +struct swd_seq_command { + uint16_t num_bits; + uint8_t *bits; +}; + +struct swd_transact_command { + uint8_t request; + uint32_t *data; + uint8_t *ack; +}; + /** * Defines a container type that hold a pointer to a JTAG command * structure of any defined type. @@ -132,6 +143,8 @@ union jtag_command_container { struct end_state_command *end_state; struct sleep_command *sleep; struct tms_command *tms; + struct swd_seq_command *swd_seq; + struct swd_transact_command *swd_transact; }; /** @@ -154,6 +167,8 @@ enum jtag_command_type { JTAG_SLEEP = 7, JTAG_STABLECLOCKS = 8, JTAG_TMS = 9, + SWD_SEQ = 10, + SWD_TRANSACT = 11, }; struct jtag_command { diff --git a/src/jtag/core.c b/src/jtag/core.c index 86ba706..1851018 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1845,3 +1845,24 @@ void adapter_deassert_reset(void) else LOG_ERROR("transport is not selected"); } + +void swd_add_sequence(uint8_t *seq, uint16_t len) +{ + int retval; + retval = interface_swd_add_sequence(seq, len); + jtag_set_error(retval); +} + +void swd_add_transact_out(uint8_t apndp, uint8_t rnw, uint8_t reg, uint32_t out_value, uint8_t *ack) +{ + int retval; + retval = interface_swd_add_transact_out(apndp, rnw, reg, out_value, ack); + jtag_set_error(retval); +} + +void swd_add_transact_in(uint8_t apndp, uint8_t rnw, uint8_t reg, uint32_t *in_value, uint8_t *ack) +{ + int retval; + retval = interface_swd_add_transact_in(apndp, rnw, reg, in_value, ack); + jtag_set_error(retval); +} diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c index 87ed6ca..fac6950 100644 --- a/src/jtag/drivers/driver.c +++ b/src/jtag/drivers/driver.c @@ -496,6 +496,88 @@ void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0); } +/** + * see swd_add_sequence() + * + */ +int interface_swd_add_sequence(uint8_t *seq, uint16_t len) +{ + struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); + struct swd_seq_command *s = cmd_queue_alloc(sizeof(struct scan_command)); + + jtag_queue_command(cmd); + cmd->type = SWD_SEQ; + cmd->cmd.swd_seq = s; + s->num_bits = len; + s->bits = buf_cpy(seq, cmd_queue_alloc(DIV_ROUND_UP(len, 8)), len); + + return ERROR_OK; +} + +/** + * see swd_add_transact_out() + * + */ +int interface_swd_add_transact_out(uint8_t apndp, uint8_t rnw, uint8_t reg, uint32_t out_value, uint8_t *ack) +{ + uint8_t parity = 0, request; + struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); + struct swd_transact_command *t = cmd_queue_alloc(sizeof(struct scan_command)); + + request = ((apndp & 1) << 1) | ((rnw & 1) << 2) | ((reg & 0x0C) << 1); + + if (request & 0x02) + parity++; + if (request & 0x04) + parity++; + if (request & 0x08) + parity++; + if (request & 0x10) + parity++; + request |= 0x81 | ((parity & 0x01) << 5); + + jtag_queue_command(cmd); + cmd->type = SWD_TRANSACT; + cmd->cmd.swd_transact = t; + t->request = request; + t->data = (uint32_t *)buf_cpy((uint8_t*)&out_value, cmd_queue_alloc(4), 32); + t->ack = ack; + + return ERROR_OK; +} + +/** + * see swd_add_transact_in() + * + */ +int interface_swd_add_transact_in(uint8_t apndp, uint8_t rnw, uint8_t reg, uint32_t *in_value, uint8_t *ack) +{ + uint8_t parity = 0, request; + struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); + struct swd_transact_command *t = cmd_queue_alloc(sizeof(struct scan_command)); + + request = ((apndp & 1) << 1) | ((rnw & 1) << 2) | ((reg & 0x0C) << 1); + + if (request & 0x02) + parity++; + if (request & 0x04) + parity++; + if (request & 0x08) + parity++; + if (request & 0x10) + parity++; + request |= 0x81 | ((parity & 0x01) << 5); + + jtag_queue_command(cmd); + cmd->type = SWD_TRANSACT; + cmd->cmd.swd_transact = t; + t->request = request; + t->data = in_value; + t->ack = ack; + + return ERROR_OK; +} + /* A minidriver can use use an inline versions of this API level fn */ void jtag_add_dr_out(struct jtag_tap *tap, int num_fields, const int *num_bits, const uint32_t *value, diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index 1c0c3e1..062b287 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -34,6 +34,7 @@ #include "versaloon/versaloon.h" static int vsllink_tms_offset; +static uint8_t swd_delay; struct pending_scan_result { int src_offset; @@ -52,6 +53,9 @@ static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; /* Queue command functions */ +static void vsllink_swd_seq(uint8_t *seq, uint16_t len); +static void vsllink_swd_transact(uint8_t request, uint32_t *value, + uint8_t *ack); static void vsllink_end_state(tap_state_t state); static void vsllink_state_move(void); static void vsllink_path_move(int num_states, tap_state_t *path); @@ -66,6 +70,7 @@ static void vsllink_reset(int trst, int srst); static void vsllink_tap_append_step(int tms, int tdi); static void vsllink_tap_init(void); static int vsllink_tap_execute(void); +static int vsllink_swd_execute(void); static void vsllink_tap_ensure_pending(int scans); static void vsllink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); @@ -108,6 +113,9 @@ static int vsllink_execute_queue(void) cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); + if (transport_is_swd()) + return ERROR_FAIL; + vsllink_end_state(cmd->cmd.runtest->end_state); vsllink_runtest(cmd->cmd.runtest->num_cycles); break; @@ -116,6 +124,9 @@ static int vsllink_execute_queue(void) DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); + if (transport_is_swd()) + return ERROR_FAIL; + vsllink_end_state(cmd->cmd.statemove->end_state); vsllink_state_move(); break; @@ -125,11 +136,16 @@ static int vsllink_execute_queue(void) cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + if (transport_is_swd()) + return ERROR_FAIL; + vsllink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: DEBUG_JTAG_IO("JTAG Scan..."); + if (transport_is_swd()) + return ERROR_FAIL; vsllink_end_state(cmd->cmd.scan->end_state); @@ -186,6 +202,9 @@ static int vsllink_execute_queue(void) DEBUG_JTAG_IO("add %d clocks", cmd->cmd.stableclocks->num_cycles); + if (transport_is_swd()) + return ERROR_FAIL; + switch (tap_get_state()) { case TAP_RESET: /* tms must be '1' to stay @@ -212,12 +231,44 @@ static int vsllink_execute_queue(void) vsllink_stableclocks(cmd->cmd.stableclocks->num_cycles, scan_size); break; - case JTAG_TMS: - DEBUG_JTAG_IO("add %d jtag tms", - cmd->cmd.tms->num_bits); + case JTAG_TMS: + DEBUG_JTAG_IO("add %d jtag tms", + cmd->cmd.tms->num_bits); - vsllink_tms(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); - break; + if (transport_is_swd()) + return ERROR_FAIL; + + vsllink_tms(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); + break; + + case SWD_SEQ: + DEBUG_JTAG_IO("add %d swd sequence", + cmd->cmd.swd_seq->num_bits); +#ifdef _DEBUG_JTAG_IO_ + vsllink_debug_buffer(cmd->cmd.swd_seq->bits, + (cmd->cmd.swd_seq->num_bits + 7) >> 3); +#endif + + vsllink_swd_seq(cmd->cmd.swd_seq->bits, + cmd->cmd.swd_seq->num_bits); + break; + + case SWD_TRANSACT: + if (cmd->cmd.swd_transact->request & 0x04) { + DEBUG_JTAG_IO("add swd in transact, request=0x%02X", + cmd->cmd.swd_transact->request); + } else { + DEBUG_JTAG_IO("add swd out transact, " + "request=0x%02X, data=0x%08X", + cmd->cmd.swd_transact->request, + *cmd->cmd.swd_transact->data); + } + + vsllink_swd_transact(cmd->cmd.swd_transact->request, + cmd->cmd.swd_transact->data, + cmd->cmd.swd_transact->ack); + + break; default: LOG_ERROR("BUG: unknown JTAG command type " @@ -232,14 +283,22 @@ static int vsllink_execute_queue(void) static int vsllink_speed(int speed) { - versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed); - return versaloon_interface.adaptors.peripheral_commit(); + if (!transport_is_swd()) { + versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed); + return versaloon_interface.adaptors.peripheral_commit(); + } else { + uint8_t swd_trn = ((swd_wcr_register >> 8)&3)+1; + if (speed) + swd_delay = (500 / speed); + versaloon_interface.adaptors.swd.config(0, swd_trn, 0, (uint16_t) swd_delay); + return versaloon_interface.adaptors.peripheral_commit(); + } + return ERROR_OK; } static int vsllink_khz(int khz, int *jtag_speed) { *jtag_speed = khz; - return ERROR_OK; } @@ -271,7 +330,11 @@ static int vsllink_quit(void) versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, 0, 0, GPIO_SRST | GPIO_TRST); versaloon_interface.adaptors.gpio.fini(0); - versaloon_interface.adaptors.jtag_raw.fini(0); + if (transport_is_swd()) + versaloon_interface.adaptors.swd.fini(0); + else + versaloon_interface.adaptors.jtag_raw.fini(0); + versaloon_interface.adaptors.peripheral_commit(); versaloon_interface.fini(); @@ -302,21 +365,30 @@ static int vsllink_init(void) } /* malloc buffer size for tap */ - tap_buffer_size = versaloon_interface.usb_setting.buf_size - 32; - vsllink_free_buffer(); - tdi_buffer = (uint8_t *)malloc(tap_buffer_size); - tdo_buffer = (uint8_t *)malloc(tap_buffer_size); - tms_buffer = (uint8_t *)malloc(tap_buffer_size); - if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) { - vsllink_quit(); - return ERROR_FAIL; + if (transport_is_swd()) { + uint8_t swd_trn = ((swd_wcr_register >> 8)&3)+1; + versaloon_interface.adaptors.swd.init(0); + versaloon_interface.adaptors.swd.config(0, swd_trn, 0, swd_delay); + versaloon_interface.adaptors.gpio.init(0); + versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, 0, GPIO_SRST, GPIO_SRST); + } else { + tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32; + vsllink_free_buffer(); + tdi_buffer = (uint8_t *)malloc(tap_buffer_size); + tdo_buffer = (uint8_t *)malloc(tap_buffer_size); + tms_buffer = (uint8_t *)malloc(tap_buffer_size); + if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) { + vsllink_quit(); + return ERROR_FAIL; + } + + versaloon_interface.adaptors.jtag_raw.init(0); + versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz()); + versaloon_interface.adaptors.gpio.init(0); + versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, + GPIO_TRST, GPIO_SRST, GPIO_SRST); } - versaloon_interface.adaptors.jtag_raw.init(0); - versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz()); - versaloon_interface.adaptors.gpio.init(0); - versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, - GPIO_TRST, GPIO_SRST, GPIO_SRST); if (ERROR_OK != versaloon_interface.adaptors.peripheral_commit()) return ERROR_FAIL; @@ -328,6 +400,22 @@ static int vsllink_init(void) /************************************************************************** * Queue command implementations */ +static void vsllink_swd_seq(uint8_t *seq, uint16_t len) +{ + if ((NULL == seq) || (0 == len)) { + LOG_ERROR("invalid parameter for swd_sequence"); + return; + } + + versaloon_interface.adaptors.swd.seqout(0, seq, len); +} + +static void vsllink_swd_transact(uint8_t request, uint32_t *value, + uint8_t *ack) +{ + versaloon_interface.adaptors.swd.transact(0, request, value, ack); +} + static void vsllink_end_state(tap_state_t state) { if (tap_is_state_stable(state)) @@ -442,13 +530,38 @@ static void vsllink_reset(int trst, int srst) else versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, GPIO_SRST, 0, 0); - if (!trst) - versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST); - else - versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0); + if (!transport_is_swd()) { + if (!trst) + versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST); + else + versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0); + } versaloon_interface.adaptors.peripheral_commit(); } +COMMAND_HANDLER(vsllink_handle_swd_delay_command) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("parameter error, " + "should be one parameter for mode"); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], swd_delay); + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_handle_mode_command) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("parameter error, " + "should be one parameter for mode"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + COMMAND_HANDLER(vsllink_handle_usb_vid_command) { if (CMD_ARGC != 1) @@ -586,6 +699,22 @@ static void vsllink_tap_append_scan(int length, uint8_t *buffer, } } +static int vsllink_swd_execute(void) +{ + int result; + + result = versaloon_interface.adaptors.peripheral_commit(); + + if (result != ERROR_OK) { + LOG_ERROR("vsllink_swd_execute failure"); + return ERROR_JTAG_QUEUE_FAILED; + } + + vsllink_tap_init(); + + return ERROR_OK; +} + static int vsllink_jtag_execute(void) { int i; @@ -645,7 +774,10 @@ static int vsllink_jtag_execute(void) static int vsllink_tap_execute(void) { - return vsllink_jtag_execute(); + if (transport_is_swd()) + return vsllink_swd_execute(); + else + return vsllink_jtag_execute(); } /**************************************************************************** @@ -829,6 +961,16 @@ static const struct command_registration vsllink_command_handlers[] = { .handler = &vsllink_handle_usb_interface_command, .mode = COMMAND_CONFIG, }, + { + .name = "swd_delay", + .handler = &vsllink_handle_swd_delay_command, + .mode = COMMAND_CONFIG, + }, + { + .name = "vsllink_mode", + .handler = &vsllink_handle_mode_command, + .mode = COMMAND_CONFIG, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 72af2fe..dc26095 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -28,6 +28,7 @@ #define OPENOCD_JTAG_INTERFACE_H #include <jtag/jtag.h> +#include <jtag/swd.h> /* @file * The "Cable Helper API" is what the cable drivers can use to help diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 3d2146c..1803e10 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -666,6 +666,13 @@ bool jtag_poll_get_enabled(void); */ void jtag_poll_set_enabled(bool value); +/** + * swd + */ +void swd_add_sequence(uint8_t *seq, uint16_t len); +void swd_add_transact_out(uint8_t apndp, uint8_t rnw, uint8_t reg, uint32_t out_value, uint8_t *ack); +void swd_add_transact_in(uint8_t apndp, uint8_t rnw, uint8_t reg, uint32_t *in_value, uint8_t *ack); + /* The minidriver may have inline versions of some of the low * level APIs that are used in inner loops. */ diff --git a/src/jtag/minidriver.h b/src/jtag/minidriver.h index b13ef72..7dc317e 100644 --- a/src/jtag/minidriver.h +++ b/src/jtag/minidriver.h @@ -71,6 +71,13 @@ int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate); int interface_add_tms_seq(unsigned num_bits, const uint8_t *bits, enum tap_state state); + +int interface_swd_add_sequence(uint8_t *seq, uint16_t len); +int interface_swd_add_transact_out(uint8_t apndp, uint8_t rnw, + uint8_t reg, uint32_t out_value, uint8_t *ack); +int interface_swd_add_transact_in(uint8_t apndp, uint8_t rnw, + uint8_t reg, uint32_t *in_value, uint8_t *ack); + /** * 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/swd.h b/src/jtag/swd.h index 9041ce0..1b1e13a 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -136,4 +136,6 @@ void swd_add_reset(int req_srst); bool transport_is_swd(void); +extern uint32_t swd_wcr_register; + #endif /* SWD_H */ diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 6af7748..8d99ff9 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -50,81 +50,356 @@ #include "arm_adi_v5.h" #include <helper/time_support.h> -#include <transport/transport.h> -#include <jtag/interface.h> -#include <jtag/swd.h> -static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, - uint32_t *data) + +/*************************************************************************** + * + * DPACC and APACC scanchain access through JTAG-DP (or SWJ-DP) + * +***************************************************************************/ + +/** + * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness + * conversions are performed. See section 4.4.3 of the ADIv5 spec, which + * discusses operations which access these registers. + * + * Note that only one scan is performed. If RnW is set, a separate scan + * will be needed to collect the data which was read; the "invalue" collects + * the posted result of a preceding operation, not the current one. + * + * @param dap the DAP + * @param instr SWD_DP_APACC (AP access) or SWD_DP_DPACC (DP access) + * @param reg_addr two significant bits; A[3:2]; for APACC access, the + * SELECT register has more addressing bits. + * @param RnW false iff outvalue will be written to the DP or AP + * @param outvalue points to a 32-bit (little-endian) integer + * @param invalue NULL, or points to a 32-bit (little-endian) integer + * @param ack points to where the three bit SWD_ACK_* code will be stored + */ + +/* FIXME don't export ... this is a temporary workaround for the + * mem_ap_read_buf_u32() mess, until it's no longer JTAG-specific. + */ +int adi_swd_dp_scan(struct adiv5_dap *dap, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint8_t *outvalue, uint8_t *invalue, uint8_t *ack) { - /* REVISIT status return vs ack ... */ - return swd->read_reg(swd_cmd(true, false, reg), data); + if (RnW == DPAP_READ) + swd_add_transact_in(instr, 1, reg_addr, (uint32_t *)invalue, ack); + else + swd_add_transact_out(instr, 0, reg_addr, *(uint32_t *)outvalue, ack); + + return ERROR_OK; } -static int swd_queue_idcode_read(struct adiv5_dap *dap, - uint8_t *ack, uint32_t *data) +/** + * Scan DPACC or APACC out and in from host ordered uint32_t buffers. + * This is exactly like adi_swd_dp_scan(), except that endianness + * conversions are performed (so the types of invalue and outvalue + * must be different). + */ +static int adi_swd_dp_scan_u32(struct adiv5_dap *dap, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint32_t outvalue, uint32_t *invalue, uint8_t *ack) { - int status = swd_queue_dp_read(dap, DP_IDCODE, data); - if (status < 0) - return status; - *ack = status; - /* ?? */ + uint8_t out_value_buf[4]; + int retval; + + buf_set_u32(out_value_buf, 0, 32, outvalue); + + retval = adi_swd_dp_scan(dap, instr, reg_addr, RnW, + out_value_buf, (uint8_t *)invalue, ack); + if (retval != ERROR_OK) + return retval; + + if (invalue) + jtag_add_callback(arm_le_to_h_u32, + (jtag_callback_data_t) invalue); + + return retval; +} + +/** + * Utility to write AP registers. + */ +static inline int adi_swd_ap_write_check(struct adiv5_dap *dap, + uint8_t reg_addr, uint8_t *outvalue) +{ + return adi_swd_dp_scan(dap, SWD_DP_APACC, reg_addr, DPAP_WRITE, + outvalue, NULL, NULL); +} + +static int adi_swd_scan_inout_check_u32(struct adiv5_dap *dap, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint32_t outvalue, uint32_t *invalue) +{ + int retval; + + /* Issue the read or write */ + + retval = adi_swd_dp_scan_u32(dap, instr, reg_addr, + RnW, outvalue, invalue, NULL); + if (retval != ERROR_OK) + return retval; + + /* For reads, collect posted value; RDBUFF has no other effect. + * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK". + */ + + if ((RnW == DPAP_READ) && (invalue != NULL) && (instr == SWD_DP_APACC)) + retval = adi_swd_dp_scan_u32(dap, SWD_DP_DPACC, + DP_RDBUFF, DPAP_READ, 0, invalue, &dap->ack); + return retval; +} + +static int swddp_transaction_endcheck(struct adiv5_dap *dap) +{ + int retval; + uint32_t ctrlstat; + + /* too expensive to call keep_alive() here */ + + /* Here be dragons! + * + * It is easy to be in a JTAG clock range where the target + * is not operating in a stable fashion. This happens + * for a few reasons: + * + * - the user may construct a simple test case to try to see + * if a higher JTAG clock works to eke out more performance. + * This simple case may pass, but more complex situations can + * fail. + * + * - The mostly works JTAG clock rate and the complete failure + * JTAG clock rate may be as much as 2-4x apart. This seems + * to be especially true on RC oscillator driven parts. + * + * So: even if calling adi_jtag_scan_inout_check_u32() multiple + * times here seems to "make things better here", it is just + * hiding problems with too high a JTAG clock. + * + * Note that even if some parts have RCLK/RTCK, that doesn't + * mean that RCLK/RTCK is the *correct* rate to run the JTAG + * interface at, i.e. RCLK/RTCK rates can be "too high", especially + * before the RC oscillator phase is not yet complete. + */ + + /* Post CTRL/STAT read; discard any previous posted read value + * but collect its ACK status. + */ + retval = adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + dap->ack = dap->ack & 0x7; + + /* common code path avoids calling timeval_ms() */ + if (dap->ack != SWD_ACK_OK) { + long long then = timeval_ms(); + + while (dap->ack != SWD_ACK_OK) { + if (dap->ack == SWD_ACK_WAIT) { + if ((timeval_ms()-then) > 1000) { + /* NOTE: this would be a good spot + * to use JTAG_DP_ABORT. + */ + LOG_WARNING("Timeout (1000ms) waiting " + "for ACK=OK/FAULT " + "in swd-DP transaction"); + return ERROR_JTAG_DEVICE_ERROR; + } + } else { + LOG_WARNING("Invalid ACK %#x " + "in swd-DP transaction", + dap->ack); + return ERROR_JTAG_DEVICE_ERROR; + } + + retval = adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if (retval != ERROR_OK) + return retval; + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + dap->ack = dap->ack & 0x7; + } + } + + /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */ + + /* Check for STICKYERR and STICKYORUN */ + if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) { + LOG_DEBUG("swd-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat); + /* Check power to debug regions */ + if ((ctrlstat & 0xf0000000) != 0xf0000000) { + retval = ahbap_debugport_init(dap); + if (retval != ERROR_OK) + return retval; + } else { + uint32_t mem_ap_csw, mem_ap_tar; + + /* Maybe print information about last intended + * MEM-AP access; but not if autoincrementing. + * *Real* CSW and TAR values are always shown. + */ + if (dap->ap_tar_value != (uint32_t) -1) + LOG_DEBUG("MEM-AP Cached values: " + "ap_bank 0x%" PRIx32 + ", ap_csw 0x%" PRIx32 + ", ap_tar 0x%" PRIx32, + dap->ap_bank_value, + dap->ap_csw_value, + dap->ap_tar_value); + + if (ctrlstat & SSTICKYORUN) + LOG_ERROR("SWD-DP OVERRUN - check clock, " + "memaccess, or reduce swd speed"); + + if (ctrlstat & SSTICKYERR) + LOG_ERROR("SWD-DP STICKY ERROR"); + + /* Clear Sticky Error Bits */ + + retval = adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + DP_ABORT, DPAP_WRITE, + dap->dp_ctrl_stat | ORUNERRCLR + | STKERRCLR, NULL); + if (retval != ERROR_OK) + return retval; + retval = adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if (retval != ERROR_OK) + return retval; + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("swd-dp: CTRL/STAT 0x%" PRIx32, ctrlstat); + + retval = dap_queue_ap_read(dap, + AP_REG_CSW, &mem_ap_csw); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_ap_read(dap, + AP_REG_TAR, &mem_ap_tar); + if (retval != ERROR_OK) + return retval; + + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%" + PRIx32, mem_ap_csw, mem_ap_tar); + + } + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + return ERROR_JTAG_DEVICE_ERROR; + } + return ERROR_OK; } -static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, +/*--------------------------------------------------------------------------*/ + + + +static int swd_idcode_q_read(struct adiv5_dap *dap, + uint8_t *ack, uint32_t *data) +{ + return adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + DP_IDCODE, DPAP_READ, 0, data); +} + +static int swd_dp_q_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + return adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + reg, DPAP_READ, 0, data); +} + +static int swd_dp_q_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - /* REVISIT status return vs ack ... */ - return swd->write_reg(swd_cmd(false, false, reg), data); + return adi_swd_scan_inout_check_u32(dap, SWD_DP_DPACC, + reg, DPAP_WRITE, data, NULL); } +/** Select the AP register bank matching bits 7:4 of reg. */ +static int swd_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select_ap_bank = reg & 0x000000F0; -static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, + if (select_ap_bank == dap->ap_bank_value) + return ERROR_OK; + dap->ap_bank_value = select_ap_bank; + + select_ap_bank |= dap->ap_current; + + return swd_dp_q_write(dap, DP_SELECT, select_ap_bank); +} + +static int swd_ap_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - /* REVISIT APSEL ... */ - /* REVISIT status return ... */ - return swd->read_reg(swd_cmd(true, true, reg), data); + int retval = swd_ap_q_bankselect(dap, reg); + + if (retval != ERROR_OK) + return retval; + + return adi_swd_scan_inout_check_u32(dap, SWD_DP_APACC, reg, + DPAP_READ, 0, data); } -static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, +static int swd_ap_q_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - /* REVISIT APSEL ... */ - /* REVISIT status return ... */ - return swd->write_reg(swd_cmd(false, true, reg), data); + uint8_t out_value_buf[4]; + + int retval = swd_ap_q_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + buf_set_u32(out_value_buf, 0, 32, data); + + return adi_swd_ap_write_check(dap, reg, out_value_buf); } -static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack) + +static int swd_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack) { - return ERROR_FAIL; + return ERROR_OK; } -/** Executes all queued DAP operations. */ -static int swd_run(struct adiv5_dap *dap) +static int swd_dp_run(struct adiv5_dap *dap) { - /* for now the SWD interface hard-wires a zero-size queue. */ - /* FIXME but we still need to check and scrub - * any hardware errors ... - */ - return ERROR_OK; + dap->ack = SWD_ACK_OK; + return swddp_transaction_endcheck(dap); } -const struct dap_ops swd_dap_ops = { +const struct dap_ops swd_dp_ops = { .is_swd = true, - .queue_idcode_read = swd_queue_idcode_read, - .queue_dp_read = swd_queue_dp_read, - .queue_dp_write = swd_queue_dp_write, - .queue_ap_read = swd_queue_ap_read, - .queue_ap_write = swd_queue_ap_write, - .queue_ap_abort = swd_queue_ap_abort, - .run = swd_run, + .queue_idcode_read = swd_idcode_q_read, + .queue_dp_read = swd_dp_q_read, + .queue_dp_write = swd_dp_q_write, + .queue_ap_read = swd_ap_q_read, + .queue_ap_write = swd_ap_q_write, + .queue_ap_abort = swd_ap_q_abort, + .queue_dp_scan = adi_swd_dp_scan, + .run = swd_dp_run, }; + /* * This represents the bits which must be sent out on TMS/SWDIO to * switch a DAP implemented using an SWJ-DP module into SWD mode. @@ -147,7 +422,7 @@ static const uint8_t jtag2swd_bitseq[] = { /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, * putting both JTAG and SWD logic into reset state. */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, }; /** @@ -165,7 +440,7 @@ static const uint8_t jtag2swd_bitseq[] = { */ int dap_to_swd(struct target *target) { - struct arm *arm = target_to_arm(target); + /* struct arm *arm = target_to_arm(target); */ int retval; LOG_DEBUG("Enter SWD mode"); @@ -174,18 +449,22 @@ int dap_to_swd(struct target *target) * subsystem if the link may not be in JTAG mode... */ - retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq), - jtag2swd_bitseq, TAP_INVALID); - if (retval == ERROR_OK) - retval = jtag_execute_queue(); + swd_add_sequence((uint8_t *)jtag2swd_bitseq, sizeof(jtag2swd_bitseq) * 8); + retval = jtag_execute_queue(); /* set up the DAP's ops vector for SWD mode. */ - arm->dap->ops = &swd_dap_ops; + /* arm->dap->ops = &swd_dap_ops; */ return retval; } +#include <transport/transport.h> +#include <jtag/interface.h> + +#include <jtag/swd.h> + +uint32_t swd_wcr_register = (1<<8)|(1<<6); COMMAND_HANDLER(handle_swd_wcr) { @@ -234,8 +513,9 @@ COMMAND_HANDLER(handle_swd_wcr) * write WCR ... * then, re-init adapter with new TRN */ - LOG_ERROR("can't yet modify WCR"); - return ERROR_FAIL; + swd_wcr_register = wcr; + LOG_INFO("can't yet modify WCR"); + return ERROR_OK; default: /* too many arguments */ return ERROR_COMMAND_SYNTAX_ERROR; @@ -280,7 +560,7 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { - struct target *target = get_current_target(ctx); + /* struct target *target = get_current_target(ctx); */ int retval; retval = register_commands(ctx, NULL, swd_handlers); @@ -288,6 +568,11 @@ static int swd_select(struct command_context *ctx) if (retval != ERROR_OK) return retval; + retval = jtag_register_commands(ctx); + + if (retval != ERROR_OK) + return retval; +#if 0 /* be sure driver is in SWD mode; start * with hardware default TRN (1), it can be changed later */ @@ -304,12 +589,13 @@ static int swd_select(struct command_context *ctx) /* force DAP into SWD mode (not JTAG) */ retval = dap_to_swd(target); - +#endif return retval; } static int swd_init(struct command_context *ctx) { +#if 0 struct target *target = get_current_target(ctx); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; @@ -333,7 +619,14 @@ static int swd_init(struct command_context *ctx) LOG_INFO("SWD IDCODE %#8.8x", idcode); return status; - +#else + int retval; + jtag_add_reset(0, 0); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +#endif } static struct transport swd_transport = { diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index a0fd4cb..5fd2832 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1074,6 +1074,7 @@ int dap_syssec(struct adiv5_dap *dap) * part of DAP transport setup */ extern const struct dap_ops jtag_dp_ops; +extern const struct dap_ops swd_dp_ops; /*--------------------------------------------------------------------------*/ @@ -1097,12 +1098,26 @@ int ahbap_debugport_init(struct adiv5_dap *dap) LOG_DEBUG(" "); + /* test for initialized low level jtag hardware + * this always fails for stlink hardware + */ + if (!dap->jtag_info) { + LOG_DEBUG("No low level jtag hardware found"); + return ERROR_OK; + } + /* JTAG-DP or SWJ-DP, in JTAG mode * ... for SWD mode this is patched as part * of link switchover */ - if (!dap->ops) + if (transport_is_swd()) { + dap->ops = &swd_dp_ops; + + dap_to_swd(NULL); + dap_queue_idcode_read(dap, NULL, NULL); + } else { dap->ops = &jtag_dp_ops; + } /* Default MEM-AP setup. * @@ -1119,9 +1134,15 @@ int ahbap_debugport_init(struct adiv5_dap *dap) if (retval != ERROR_OK) return retval; - retval = dap_queue_dp_write(dap, DP_CTRL_STAT, SSTICKYERR); - if (retval != ERROR_OK) - return retval; + if (transport_is_swd()) { + retval = dap_queue_dp_write(dap, DP_ABORT, DAPABORT | STKERRCLR | WDERRCLR | ORUNERRCLR); + if (retval != ERROR_OK) + return retval; + } else { + retval = dap_queue_dp_write(dap, DP_CTRL_STAT, SSTICKYERR); + if (retval != ERROR_OK) + return retval; + } retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 37b7771..9a6905f 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -39,10 +39,14 @@ #define JTAG_DP_DPACC 0xA #define JTAG_DP_APACC 0xB +#define SWD_DP_DPACC 0 +#define SWD_DP_APACC 1 + + /* three-bit ACK values for SWD access (sent LSB first) */ -#define SWD_ACK_OK 0x4 +#define SWD_ACK_OK 0x1 #define SWD_ACK_WAIT 0x2 -#define SWD_ACK_FAULT 0x1 +#define SWD_ACK_FAULT 0x4 #define DPAP_WRITE 0 #define DPAP_READ 1 @@ -220,6 +224,11 @@ struct dap_ops { /** AP operation abort. */ int (*queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack); + /** low level DP Scan */ + int (*queue_dp_scan)(struct adiv5_dap *dap, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint8_t *outvalue, uint8_t *invalue, uint8_t *ack); + /** Executes all queued DAP operations. */ int (*run)(struct adiv5_dap *dap); }; diff --git a/tcl/board/r0ket-vsllink.cfg b/tcl/board/r0ket-vsllink.cfg new file mode 100644 index 0000000..40a177c --- /dev/null +++ b/tcl/board/r0ket-vsllink.cfg @@ -0,0 +1,14 @@ +# Target Configuration for the CCC R0ket +# http://r0ket.badge.events.ccc.de/ +# with Versaloon http://www.versaloon.com/ +# or versaloon-r0ket https://github.com/turboj/versaloon-r0ket +# as debug interface + +source [find interface/vsllink.cfg] + +transport select swd + +source [find target/lpc1343.cfg] +swd wcr 2 + +adapter_khz 500 diff --git a/tcl/target/lpc1343.cfg b/tcl/target/lpc1343.cfg new file mode 100644 index 0000000..db885e4 --- /dev/null +++ b/tcl/target/lpc1343.cfg @@ -0,0 +1,63 @@ +# NXP LPC1343 Cortex-M3 with 32kB Flash and 8kB Local On-Chip SRAM, + +# LPC13xx chips support only SWD transports. + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME lpc1343 +} + +# After reset the chip is clocked by the ~12MHz internal RC oscillator. +# When board-specific code (reset-init handler or device firmware) +# configures another oscillator and/or PLL0, set CCLK to match; if +# you don't, then flash erase and write operations may misbehave. +# (The ROM code doing those updates cares about core clock speed...) +# +# CCLK is the core clock frequency in KHz +if { [info exists CCLK] } { + set _CCLK $CCLK +} else { + set _CCLK 12000 +} +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x2BA01477 +} + +#delays on reset lines +adapter_nsrst_delay 200 + +swd newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m3 -chain-position $_TARGETNAME + +# LPC1343 has 8kB of SRAM In the ARMv7-M "Code" area (at 0x10000000) +$_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size 0x2000 + +# LPC1343 has 32kB of flash memory, managed by ROM code (including a +# boot loader which verifies the flash exception table's checksum). +# flash bank <name> lpc2000 <base> <size> 0 0 <target#> <variant> <clock> [calc checksum] +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME lpc2000 0x0 0x8000 0 0 $_TARGETNAME \ + lpc1700 $_CCLK calc_checksum + +# Run with *real slow* clock by default since the +# boot rom could have been playing with the PLL, so +# we have no idea what clock the target is running at. +adapter_khz 10 + +# LPC13xx have working sysresetreq + +cortex_m3 reset_config sysresetreq + +$_TARGETNAME configure -event reset-init { + # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select + # "User Flash Mode" where interrupt vectors are _not_ remapped, + # and reside in flash instead). + # + # + mww 0x40048000 0x02 +} -- ------------------------------------------------------------------------------ Free Next-Gen Firewall Hardware Offer Buy your Sophos next-gen firewall before the end March 2013 and get the hardware for free! Learn more. http://p.sf.net/sfu/sophos-d2d-feb _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
