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

Reply via email to