This is an automated email from Gerrit. Paul Fertser (fercer...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2004
-- gerrit commit e29579d646e90a3a61e9867d1eefe16b2e81f29c Author: Paul Fertser <fercer...@gmail.com> Date: Thu Feb 27 22:50:57 2014 +0400 jtag/drivers/bitbang, bcm2835gpio: SWD support Tested on a RaspberryPi with direct connection to STM32F100. Specifying bcm2835gpio_swdio_drive_num should allow the same code to work in a buffered mode via Olimex or similar adapter. Tested without one by using 330 Ohms resistor hack. Change-Id: Icfac1b138c69adf57ed1e7dfa11e1a6c88a6a3d0 Signed-off-by: Paul Fertser <fercer...@gmail.com> diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index a2ba8e6..e549470 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -54,6 +54,7 @@ static volatile uint32_t *pio_base; static int bcm2835gpio_read(void); static void bcm2835gpio_write(int tck, int tms, int tdi); static void bcm2835gpio_reset(int trst, int srst); +static void bcm2835gpio_drive(bool on); static int bcm2835gpio_init(void); static int bcm2835gpio_quit(void); @@ -62,6 +63,7 @@ static struct bitbang_interface bcm2835gpio_bitbang = { .read = bcm2835gpio_read, .write = bcm2835gpio_write, .reset = bcm2835gpio_reset, + .swdio_drive = bcm2835gpio_drive, .blink = NULL }; @@ -78,6 +80,8 @@ static int trst_gpio = -1; static int trst_gpio_mode; static int srst_gpio = -1; static int srst_gpio_mode; +static int swdio_drive_gpio = -1; +static int swdio_drive_gpio_mode; /* Transition delay coefficients */ static int speed_coeff = 113714; @@ -86,7 +90,10 @@ static unsigned int jtag_delay; static int bcm2835gpio_read(void) { - return !!(GPIO_LEV & 1<<tdo_gpio); + if (!swd_mode || swdio_drive_gpio != -1) + return !!(GPIO_LEV & 1<<tdo_gpio); + else + return !!(GPIO_LEV & 1<<tdi_gpio); } static void bcm2835gpio_write(int tck, int tms, int tdi) @@ -121,6 +128,21 @@ static void bcm2835gpio_reset(int trst, int srst) GPIO_CLR = clear; } +static void bcm2835gpio_drive(bool on) +{ + if (swdio_drive_gpio != -1) { + if (on) + GPIO_SET = 1 << swdio_drive_gpio; + else + GPIO_CLR = 1 << swdio_drive_gpio; + } else { + if (on) + OUT_GPIO(tdi_gpio); + else + INP_GPIO(tdi_gpio); + } +} + static int bcm2835gpio_khz(int khz, int *jtag_speed) { if (!khz) { @@ -222,6 +244,15 @@ COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst) return ERROR_OK; } +COMMAND_HANDLER(bcm2835gpio_handle_swdio_drive_gpionum) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_drive_gpio); + + command_print(CMD_CTX, "BCM2835 GPIO config: swdio_drive = %d", swdio_drive_gpio); + return ERROR_OK; +} + COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs) { if (CMD_ARGC == 2) { @@ -276,6 +307,12 @@ static const struct command_registration bcm2835gpio_command_handlers[] = { .help = "gpio number for trst.", }, { + .name = "bcm2835gpio_swdio_drive_num", + .handler = &bcm2835gpio_handle_swdio_drive_gpionum, + .mode = COMMAND_CONFIG, + .help = "gpio number for SWDIO drive enable.", + }, + { .name = "bcm2835gpio_speed_coeffs", .handler = &bcm2835gpio_handle_speed_coeffs, .mode = COMMAND_CONFIG, @@ -284,11 +321,15 @@ static const struct command_registration bcm2835gpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; + struct jtag_interface bcm2835gpio_interface = { .name = "bcm2835gpio", .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, - .transports = jtag_only, + .transports = bcm2835_transports, + .swd = &bitbang_swd, + .speed = bcm2835gpio_speed, .khz = bcm2835gpio_khz, .speed_div = bcm2835gpio_speed_div, @@ -361,16 +402,28 @@ static int bcm2835gpio_init(void) GPIO_SET = 1 << srst_gpio; OUT_GPIO(srst_gpio); } + if (swdio_drive_gpio != -1) { + swdio_drive_gpio_mode = MODE_GPIO(swdio_drive_gpio); + GPIO_SET = 1 << swdio_drive_gpio; + OUT_GPIO(swdio_drive_gpio); + /* assume nTRST needs to be low for an SWD adapter */ + GPIO_CLR = 1 << trst_gpio; + } LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d " "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode, tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode); + if (swd_mode) + bitbang_switch_to_swd(); + return ERROR_OK; } static int bcm2835gpio_quit(void) { + if (swdio_drive_gpio != -1) + SET_MODE_GPIO(swdio_drive_gpio, swdio_drive_gpio_mode); SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode); SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode); SET_MODE_GPIO(tck_gpio, tck_gpio_mode); diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index 795764a..16ea428 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -337,3 +337,157 @@ int bitbang_execute_queue(void) return retval; } + +bool swd_mode; +static uint8_t swd_trn; +static int queued_retval; + +static int bitbang_swd_init(uint8_t trn) +{ + swd_mode = true; + swd_trn = trn; + return ERROR_OK; +} + +static void bitbang_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt) +{ + int tdi; + + for (unsigned int i = offset; i < bit_cnt + offset; i++) { + int bytec = i/8; + int bcval = 1 << (i % 8); + tdi = !rnw && (buf[bytec] & bcval); + + bitbang_interface->write(0, 0, tdi); + + if (rnw && buf) { + if (bitbang_interface->read()) + buf[bytec] |= bcval; + else + buf[bytec] &= ~bcval; + } + + bitbang_interface->write(1, 0, tdi); + } +} + +void bitbang_switch_to_swd(void) +{ + static 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, + /* Switching sequence enables SWD and disables JTAG + * NOTE: bits in the DP's IDCODE may expose the need for + * an old/obsolete/deprecated sequence (0xb6 0xed). + */ + 0x9e, 0xe7, + /* 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, 0x0f, + }; + + bitbang_exchange(false, jtag2swd_bitseq, 0, sizeof(jtag2swd_bitseq) * 8); +} + +static void bitbang_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value) +{ + assert(cmd & SWD_CMD_RnW); + + if (queued_retval != ERROR_OK) + return; + + uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; + + cmd |= SWD_CMD_START | (1 << 7); + bitbang_exchange(false, &cmd, 0, 8); + + bitbang_interface->swdio_drive(false); + bitbang_exchange(true, trn_ack_data_parity_trn, 0, swd_trn + 3 + 32 + 1 + swd_trn); + bitbang_interface->swdio_drive(true); + + int ack = buf_get_u32(trn_ack_data_parity_trn, swd_trn, 3); + uint32_t data = buf_get_u32(trn_ack_data_parity_trn, swd_trn + 3, 32); + int parity = buf_get_u32(trn_ack_data_parity_trn, swd_trn + 3 + 32, 1); + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + data); + + if (ack != SWD_ACK_OK) { + queued_retval = ack; + return; + } + + if (parity != parity_u32(data)) { + queued_retval = ERROR_FAIL; + return; + } + + if (value) + *value = data; + + if (cmd & SWD_CMD_APnDP) + bitbang_exchange(true, NULL, 0, dap->memaccess_tck); +} + +static void bitbang_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value) +{ + assert(!(cmd & SWD_CMD_RnW)); + + if (queued_retval != ERROR_OK) + return; + + uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; + buf_set_u32(trn_ack_data_parity_trn, swd_trn + 3 + swd_trn, 32, value); + buf_set_u32(trn_ack_data_parity_trn, swd_trn + 3 + swd_trn + 32, 1, parity_u32(value)); + + cmd |= SWD_CMD_START | (1 << 7); + bitbang_exchange(false, &cmd, 0, 8); + + bitbang_interface->swdio_drive(false); + bitbang_exchange(true, trn_ack_data_parity_trn, 0, swd_trn + 3 + swd_trn); + bitbang_interface->swdio_drive(true); + + int ack = buf_get_u32(trn_ack_data_parity_trn, swd_trn, 3); + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + buf_get_u32(trn_ack_data_parity_trn, swd_trn + 3 + swd_trn, 32)); + + if (ack != SWD_ACK_OK) { + queued_retval = ack; + return; + } + + bitbang_exchange(false, trn_ack_data_parity_trn, swd_trn + 3 + swd_trn, 32 + 1); + + if (cmd & SWD_CMD_APnDP) + bitbang_exchange(true, NULL, 0, dap->memaccess_tck); +} + +static int bitbang_swd_run_queue(struct adiv5_dap *dap) +{ + /* A transaction must be followed by another transaction or at least 8 idle cycles to + * ensure that data is clocked through the AP. */ + bitbang_exchange(true, NULL, 0, 8); + + int retval = queued_retval; + queued_retval = ERROR_OK; + LOG_DEBUG("SWD queue return value: %02x", retval); + return retval; +} + +const struct swd_driver bitbang_swd = { + .init = bitbang_swd_init, + .read_reg = bitbang_swd_read_reg, + .write_reg = bitbang_swd_write_reg, + .run = bitbang_swd_run_queue, +}; diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index 6b7d63a..6d5001d 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -24,6 +24,8 @@ #ifndef BITBANG_H #define BITBANG_H +#include <jtag/swd.h> + struct bitbang_interface { /* low level callbacks (for bitbang) */ @@ -31,9 +33,15 @@ struct bitbang_interface { void (*write)(int tck, int tms, int tdi); void (*reset)(int trst, int srst); void (*blink)(int on); + void (*swdio_drive)(bool on); }; +const struct swd_driver bitbang_swd; + +extern bool swd_mode; + int bitbang_execute_queue(void); +void bitbang_switch_to_swd(void); extern struct bitbang_interface *bitbang_interface; -- ------------------------------------------------------------------------------ Flow-based real-time traffic analytics software. Cisco certified tool. Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer Customize your own dashboards, set traffic alerts and generate reports. Network behavioral analysis & security monitoring. All-in-one tool. http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel