This is an automated email from Gerrit. Fatih Aşıcı ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/1947
-- gerrit commit 6555547217b7400faade16efdfbbb0bd41e37f86 Author: Fatih Aşıcı <[email protected]> Date: Fri Feb 14 13:37:04 2014 +0200 vsllink: Add SWD support Tested with stm32f1x, stm32f4x and kl25 targets using SWD transport. Change-Id: I118d07371b53f402ea9ac73f874460a309c05100 Signed-off-by: Fatih Aşıcı <[email protected]> diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c index b8d27af..1664d53 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c @@ -30,7 +30,7 @@ #include "usbtoxxx.h" #include "usbtoxxx_internal.h" -RESULT usbtoswd_callback(void *p, uint8_t *src, uint8_t *processed) +RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; @@ -40,6 +40,18 @@ RESULT usbtoswd_callback(void *p, uint8_t *src, uint8_t *processed) return ERROR_OK; } +RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed) +{ + struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; + + if (pending->extra_data != NULL) + *((uint8_t *)pending->extra_data) = src[0]; + + /* mark it processed to ignore other input data */ + *processed = 1; + return ERROR_OK; +} + RESULT usbtoswd_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_SWD, interface_index); @@ -130,14 +142,16 @@ RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, memset(buff + 1, 0, 4); versaloon_set_extra_data(ack); - versaloon_set_callback(usbtoswd_callback); if (request & 0x04) { /* read */ - return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5, - (uint8_t *)data, 1, 4, 0); + versaloon_set_callback(usbtoswd_read_callback); } else { /* write */ - return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5, - NULL, 0, 0, 0); + versaloon_set_callback(usbtoswd_write_callback); } + + /* Input buffer must be passed even for write operations. Otherwise + * the callback function is not called and ack value is not set. */ + return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5, + (uint8_t *)data, 1, 4, 0); } diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index 9580672..59c07b7 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -28,6 +28,9 @@ #include <jtag/interface.h> #include <jtag/commands.h> +#include <jtag/swd.h> +#include <jtag/tcl.h> +#include <target/arm_adi_v5.h> #include "usb_common.h" #include "versaloon/versaloon_include.h" @@ -87,9 +90,58 @@ static int tap_buffer_size; static uint8_t *tms_buffer; static uint8_t *tdi_buffer; static uint8_t *tdo_buffer; +static uint8_t swd_delay; struct vsllink *vsllink_handle; +/* global command context from openocd.c */ +extern struct command_context *global_cmd_ctx; + +static const struct command_registration vsllink_swd_command_handlers[]; + +static int vsllink_swd_read_reg(uint8_t cmd, uint32_t *value) +{ + int retval; + uint32_t val = 0; + uint8_t ack; + + versaloon_interface.adaptors.swd.transact(0, cmd, &val, &ack); + + if (cmd & SWD_CMD_APnDP) + versaloon_interface.adaptors.swd.transact(0, + swd_cmd(true, false, DP_RDBUFF), &val, &ack); + + retval = versaloon_interface.adaptors.peripheral_commit(); + + if (ERROR_OK != retval) + return ERROR_FAIL; + + if (ack != 0x01) + return ack; + + if (value) + *value = val; + + return retval; +} + +static int vsllink_swd_write_reg(uint8_t cmd, uint32_t value) +{ + int retval; + uint8_t ack; + + versaloon_interface.adaptors.swd.transact(0, cmd, &value, &ack); + retval = versaloon_interface.adaptors.peripheral_commit(); + + if (ERROR_OK != retval) + return ERROR_FAIL; + + if (ack != 0x01) + return ack; + + return retval; +} + static int vsllink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; @@ -232,7 +284,9 @@ static int vsllink_execute_queue(void) static int vsllink_speed(int speed) { - versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed); + if (transport_is_swd()) + return ERROR_OK; + return versaloon_interface.adaptors.peripheral_commit(); } @@ -271,7 +325,12 @@ 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(); @@ -281,8 +340,10 @@ static int vsllink_quit(void) return ERROR_OK; } -static int vsllink_init(void) +static int vsllink_interface_init(void) { + uint16_t voltage; + vsllink_handle = vsllink_usb_open(); if (vsllink_handle == 0) { LOG_ERROR("Can't find USB JTAG Interface!" \ @@ -301,22 +362,68 @@ static int vsllink_init(void) return ERROR_FAIL; } - /* malloc buffer size for tap */ - tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32; - vsllink_free_buffer(); - tdi_buffer = malloc(tap_buffer_size); - tdo_buffer = malloc(tap_buffer_size); - tms_buffer = malloc(tap_buffer_size); - if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) { - vsllink_quit(); + versaloon_interface.adaptors.target_voltage.get(&voltage); + LOG_INFO("Target runs at %.3fV", voltage / 1000.0); + + return ERROR_OK; +} + +static int vsllink_swd_init(uint8_t trn) +{ + if (!global_cmd_ctx) return ERROR_FAIL; - } - versaloon_interface.adaptors.jtag_raw.init(0); - versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz()); + register_commands(global_cmd_ctx, NULL, vsllink_swd_command_handlers); + + return ERROR_OK; +} + +static int vsllink_init(void) +{ + int retval = vsllink_interface_init(); + if (ERROR_OK != retval) + return retval; + 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.gpio.config(0, GPIO_SRST, 0, GPIO_SRST, + GPIO_SRST); + versaloon_interface.adaptors.delay.delayms(100); + versaloon_interface.adaptors.peripheral_commit(); + + if (transport_is_swd()) { + versaloon_interface.adaptors.gpio.config(0, GPIO_TRST, 0, + GPIO_TRST, GPIO_TRST); + versaloon_interface.adaptors.swd.init(0); + versaloon_interface.adaptors.swd.config(0, 2, 0, swd_delay); + + const uint8_t jtag_to_swd_seq[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9e, 0xe7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + }; + + versaloon_interface.adaptors.swd.seqout(0, + (uint8_t *) jtag_to_swd_seq, + sizeof(jtag_to_swd_seq) * 8); + + } else { + /* malloc buffer size for tap */ + tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32; + vsllink_free_buffer(); + tdi_buffer = malloc(tap_buffer_size); + tdo_buffer = malloc(tap_buffer_size); + tms_buffer = 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.config(0, GPIO_SRST | GPIO_TRST, + GPIO_TRST, GPIO_SRST, GPIO_SRST); + } + if (ERROR_OK != versaloon_interface.adaptors.peripheral_commit()) return ERROR_FAIL; @@ -442,13 +549,32 @@ 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) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], swd_delay); + command_print(CMD_CTX, "swd_delay: %d cycle(s)", swd_delay); + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_jtag_command) +{ + LOG_DEBUG("vsllink_jtag_command"); + return ERROR_OK; +} + COMMAND_HANDLER(vsllink_handle_usb_vid_command) { if (CMD_ARGC != 1) @@ -660,6 +786,9 @@ static int vsllink_jtag_execute(void) static int vsllink_tap_execute(void) { + if (transport_is_swd()) + return ERROR_OK; + return vsllink_jtag_execute(); } @@ -815,6 +944,39 @@ static void vsllink_debug_buffer(uint8_t *buffer, int length) } #endif /* _DEBUG_JTAG_IO_ */ +static const struct command_registration vsllink_jtag_subcommand_handlers[] = { + { + .name = "arp_init-reset", + .mode = COMMAND_ANY, + .handler = vsllink_jtag_command, + .usage = "" + }, + { + .name = "tapisenabled", + .mode = COMMAND_EXEC, + .jim_handler = jim_jtag_tap_enabler, + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration vsllink_swd_command_handlers[] = { + { + .name = "swd_delay", + .handler = &vsllink_handle_swd_delay_command, + .mode = COMMAND_CONFIG, + .usage = "cycles", + }, + { + /* this is currently a nasty hack so we get + * reset working with non jtag interfaces */ + .name = "jtag", + .mode = COMMAND_ANY, + .usage = "", + .chain = vsllink_jtag_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration vsllink_command_handlers[] = { { .name = "vsllink_usb_vid", @@ -851,11 +1013,18 @@ static const struct command_registration vsllink_command_handlers[] = { static const char *vsllink_transports[] = {"jtag", "swd", NULL}; +static const struct swd_driver vsllink_swd_driver = { + .init = vsllink_swd_init, + .read_reg = vsllink_swd_read_reg, + .write_reg = vsllink_swd_write_reg, +}; + struct jtag_interface vsllink_interface = { .name = "vsllink", .supported = DEBUG_CAP_TMS_SEQ, .commands = vsllink_command_handlers, .transports = vsllink_transports, + .swd = &vsllink_swd_driver, .init = vsllink_init, .quit = vsllink_quit, diff --git a/src/jtag/swd.h b/src/jtag/swd.h index f131ddb..fee7f91 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -33,7 +33,7 @@ /* followed by TRN, 3-bits of ACK, TRN */ /* pbit16 holds precomputed parity bits for each nibble */ -#define pbit(parity, nibble) (parity << nibble) +#define pbit(parity, nibble) ((parity) << (nibble)) static const uint16_t pbit16 = pbit(0, 0) | pbit(1, 1) | pbit(1, 2) | pbit(0, 3) @@ -41,7 +41,7 @@ static const uint16_t pbit16 = | pbit(1, 8) | pbit(0, 9) | pbit(0, 0xa) | pbit(1, 0xb) | pbit(0, 0xc) | pbit(1, 0xd) | pbit(1, 0xe) | pbit(0, 0xf); -#define nibble_parity(nibble) (pbit16 & pbit(1, nibble)) +#define nibble_parity(nibble) (pbit16 & pbit(1, (nibble))) /** * Construct a "cmd" byte, in lSB bit order, which swd_driver.read_reg() diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 6ff858a..52b524e 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -58,14 +58,56 @@ /* YUK! - but this is currently a global.... */ extern struct jtag_interface *jtag_interface; +static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, + uint32_t data); + +static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack) +{ + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + return swd->write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); +} + +/** Select the DP register bank matching bits 7:4 of reg. */ +static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select_dp_bank = (reg & 0x000000F0) >> 4; + + if (reg == DP_SELECT) + return ERROR_OK; + + if (select_dp_bank == dap->dp_bank_value) + return ERROR_OK; + + dap->dp_bank_value = select_dp_bank; + select_dp_bank |= dap->ap_current | dap->ap_bank_value; + + return swd_queue_dp_write(dap, DP_SELECT, select_dp_bank); +} + static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { + int retval; /* REVISIT status return vs ack ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->read_reg(swd_cmd(true, false, reg), data); + retval = swd_queue_dp_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + retval = swd->read_reg(swd_cmd(true, false, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } static int swd_queue_idcode_read(struct adiv5_dap *dap, @@ -82,39 +124,82 @@ static int swd_queue_idcode_read(struct adiv5_dap *dap, static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) { + int retval; /* REVISIT status return vs ack ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->write_reg(swd_cmd(false, false, reg), data); + retval = swd_queue_dp_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + retval = swd->write_reg(swd_cmd(false, false, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } +/** Select the AP register bank matching bits 7:4 of reg. */ +static int swd_queue_ap_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select_ap_bank = reg & 0x000000F0; + + if (select_ap_bank == dap->ap_bank_value) + return ERROR_OK; + + dap->ap_bank_value = select_ap_bank; + select_ap_bank |= dap->ap_current | dap->dp_bank_value; + + return swd_queue_dp_write(dap, DP_SELECT, select_ap_bank); +} static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - /* REVISIT APSEL ... */ /* REVISIT status return ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->read_reg(swd_cmd(true, true, reg), data); + int retval = swd_queue_ap_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + retval = swd->read_reg(swd_cmd(true, true, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - /* REVISIT APSEL ... */ /* REVISIT status return ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->write_reg(swd_cmd(false, true, reg), data); -} + int retval = swd_queue_ap_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; -static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack) -{ - return ERROR_FAIL; + retval = swd->write_reg(swd_cmd(false, true, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } /** Executes all queued DAP operations. */ @@ -356,8 +441,13 @@ static int swd_init(struct command_context *ctx) if (status == ERROR_OK) LOG_INFO("SWD IDCODE %#8.8" PRIx32, idcode); - return status; + /* force clear all sticky faults */ + swd_queue_ap_abort(dap, &ack); + + /* this is a workaround to get polling working */ + jtag_add_reset(0, 0); + return status; } static struct transport swd_transport = { diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 41bd261..1558346 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -781,6 +781,8 @@ int ahbap_debugport_init(struct adiv5_dap *dap) /* DP initialization */ + dap->dp_bank_value = 0; + retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index cdcf928..f406c21 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -47,18 +47,20 @@ #define DPAP_WRITE 0 #define DPAP_READ 1 +#define BANK_REG(bank, reg) (((bank) << 4) | (reg)) + /* A[3:0] for DP registers; A[1:0] are always zero. * - JTAG accesses all of these via JTAG_DP_DPACC, except for * IDCODE (JTAG_DP_IDCODE) and ABORT (JTAG_DP_ABORT). * - SWD accesses these directly, sometimes needing SELECT.CTRLSEL */ -#define DP_IDCODE 0 /* SWD: read */ -#define DP_ABORT 0 /* SWD: write */ -#define DP_CTRL_STAT 0x4 /* r/w */ -#define DP_WCR 0x4 /* SWD: r/w (mux CTRLSEL) */ -#define DP_RESEND 0x8 /* SWD: read */ -#define DP_SELECT 0x8 /* JTAG: r/w; SWD: write */ -#define DP_RDBUFF 0xC /* read-only */ +#define DP_IDCODE BANK_REG(0x0, 0x0) /* SWD: read */ +#define DP_ABORT BANK_REG(0x0, 0x0) /* SWD: write */ +#define DP_CTRL_STAT BANK_REG(0x0, 0x4) /* r/w */ +#define DP_RESEND BANK_REG(0x0, 0x8) /* SWD: read */ +#define DP_SELECT BANK_REG(0x0, 0x8) /* JTAG: r/w; SWD: write */ +#define DP_RDBUFF BANK_REG(0x0, 0xC) /* read-only */ +#define DP_WCR BANK_REG(0x1, 0x4) /* SWD: r/w */ #define WCR_TO_TRN(wcr) ((uint32_t)(1 + (3 & ((wcr)) >> 8))) /* 1..4 clocks */ #define WCR_TO_PRESCALE(wcr) ((uint32_t)(7 & ((wcr)))) /* impl defined */ @@ -162,6 +164,13 @@ struct adiv5_dap { uint32_t ap_bank_value; /** + * Cache for DP_SELECT bits identifying the current four-word DP + * register bank. This caches DP register addresss bits 7:4; JTAG + * and SWD access primitves pass address bits 3:2; bits 1:0 are zero. + */ + uint32_t dp_bank_value; + + /** * Cache for (MEM-AP) AP_REG_CSW register value. This is written to * configure an access mode, such as autoincrementing AP_REG_TAR during * word access. "-1" indicates no cached value. diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index eafa122..feca77c 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -25,19 +25,6 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x10000 } -# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -# -# Since we may be running of an RC oscilator, we crank down the speed a -# bit more to be on the safe side. Perhaps superstition, but if are -# running off a crystal, we can run closer to the limit. Note -# that there can be a pretty wide band where things are more or less stable. -adapter_khz 1000 - -adapter_nsrst_delay 100 -if {$using_jtag} { - jtag_ntrst_delay 100 -} - #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID @@ -73,6 +60,19 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME +# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz +# +# Since we may be running of an RC oscilator, we crank down the speed a +# bit more to be on the safe side. Perhaps superstition, but if are +# running off a crystal, we can run closer to the limit. Note +# that there can be a pretty wide band where things are more or less stable. +adapter_khz 1000 + +adapter_nsrst_delay 100 +if {$using_jtag} { + jtag_ntrst_delay 100 +} + # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq -- ------------------------------------------------------------------------------ Android apps run on BlackBerry 10 Introducing the new BlackBerry 10.2.1 Runtime for Android apps. Now with support for Jelly Bean, Bluetooth, Mapview and more. Get your Android app in front of a whole new audience. Start now. http://pubads.g.doubleclick.net/gampad/clk?id=124407151&iu=/4140/ostg.clktrk _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
