This is an automated email from Gerrit. Ake Rehnman ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/3952
-- gerrit commit 040042cee1dbb966c9346db7626792cba107777c Author: Ake Rehnman <[email protected]> Date: Sat Jan 21 10:42:11 2017 +0100 jtag/drivers/stlink_usb : implemented and repaired SWIM support The SWIM support in stlink_usb was basically non existent so I have implemented the missing parts. The bCBWCBLength and dCBWDataTransferLength for STLINK-V1 protocol was not correct so that was fixed. The reason for adding SWIM support is to add STM8 support for OpenOCD. I have tested the driver on: STM8 discovery board with the built-in STLINK-V1 STM8 discovery board with STLINK-V2 dongle STM32 vldiscovery board with the built-in STLINK-V1 STM32F1xxx processor with STLINK-V2 dongle Change-Id: I4aa80a92fb0226174356adaf2f8ff949920a621f Signed-off-by: Ake Rehnman <[email protected]> diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 699c41f..8e098ad 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1,4 +1,8 @@ /*************************************************************************** + * SWIM contributions by Ake Rehnman * + * Copyright (C) 2017 Ake Rehnman * + * ake.rehnman(at)gmail.com * + * * * Copyright (C) 2011-2012 by Mathias Kuester * * Mathias Kuester <[email protected]> * * * @@ -167,8 +171,36 @@ struct stlink_usb_handle_s { #define STLINK_DFU_EXIT 0x07 -#define STLINK_SWIM_ENTER 0x00 -#define STLINK_SWIM_EXIT 0x01 +/* + STLINK_SWIM_ENTER_SEQ + 1.3ms low then 750Hz then 1.5kHz + + STLINK_SWIM_GEN_RST + STM8 DM pulls reset pin low 50us + + STLINK_SWIM_SPEED + uint8_t (0=low|1=high) + + STLINK_SWIM_WRITEMEM + uint16_t length + uint32_t address + + STLINK_SWIM_RESET + send syncronization seq (16us low, response 64 clocks low) +*/ +#define STLINK_SWIM_ENTER 0x00 +#define STLINK_SWIM_EXIT 0x01 +#define STLINK_SWIM_READ_CAP 0x02 +#define STLINK_SWIM_ASSERT_RESET 0x07 +#define STLINK_SWIM_DEASSERT_RESET 0x08 +#define STLINK_SWIM_ENTER_SEQ 0x04 +#define STLINK_SWIM_GEN_RST 0x05 +#define STLINK_SWIM_SPEED 0x03 +#define STLINK_SWIM_WRITEMEM 0x0a +#define STLINK_SWIM_RESET 0x06 +#define STLINK_SWIM_READMEM 0x0b +#define STLINK_SWIM_READBUF 0x0c +#define STLINK_SWIM_READSTATUS 0x09 #define STLINK_DEBUG_ENTER_JTAG 0x00 #define STLINK_DEBUG_GETSTATUS 0x01 @@ -342,7 +374,11 @@ static int stlink_usb_xfer_v1_get_sense(void *handle) return ERROR_OK; } -/** */ +/* + transfers block in cmdbuf + <size> indicates number of bytes in the following + data phase. +*/ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; @@ -350,8 +386,11 @@ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size) assert(handle != NULL); - if (h->version.stlink == 1) + if (h->version.stlink == 1) { cmdsize = STLINK_SG_SIZE; + /* put length in bCBWCBLength */ + h->cmdbuf[14] = h->cmdidx-15; + } err = stlink_usb_xfer_rw(handle, cmdsize, buf, size); @@ -373,6 +412,45 @@ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size) return ERROR_OK; } +/* + send cbw with wait for completion + handle - handle + buf - buffer used in data phase + size - number of bytes in data phase + */ +static int stlink_usb_xfer_busyw(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + int err; + int timeout = 1000; + + assert(handle != NULL); + + err = stlink_usb_xfer(handle, buf, size); + + if (err != ERROR_OK) + return err; + + do { + stlink_usb_init_buffer(handle, h->rx_ep, 4); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READSTATUS; + err = stlink_usb_xfer(handle, buf, 4); + + if (err != ERROR_OK) + return err; + /* 0x01 indicates busy */ + if (buf[0] == 0x01) + usleep(1000); + else + break; + } while (timeout--); + + if (buf[0] != 0) + return ERROR_FAIL; + + return ERROR_OK; +} /** Converts an STLINK status code held in the first byte of a response @@ -388,6 +466,9 @@ static int stlink_usb_error_check(void *handle) if (h->jtag_api == STLINK_JTAG_API_V1) h->databuf[0] = STLINK_DEBUG_ERR_OK; + if (h->transport == HL_TRANSPORT_SWIM) + h->databuf[0] = STLINK_DEBUG_ERR_OK; + switch (h->databuf[0]) { case STLINK_DEBUG_ERR_OK: return ERROR_OK; @@ -487,7 +568,17 @@ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) return ERROR_OK; } -/** */ +/* + this function writes transfer length in + the right place in the cb +*/ +static void stlink_usb_set_cbw_transfer_datalength(void *handle, uint32_t size) +{ + struct stlink_usb_handle_s *h = handle; + + buf_set_u32(h->cmdbuf+8, 0, 32, size); +} + static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size) { struct stlink_usb_handle_s *h = handle; @@ -496,12 +587,16 @@ static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint3 strcpy((char *)h->cmdbuf, "USBC"); h->cmdidx += 4; /* csw tag not used */ + buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, 0); h->cmdidx += 4; + /* cbw data transfer length (in the following data phase in or out) */ buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size); h->cmdidx += 4; + /* cbw flags */ h->cmdbuf[h->cmdidx++] = (direction == h->rx_ep ? ENDPOINT_IN : ENDPOINT_OUT); h->cmdbuf[h->cmdidx++] = 0; /* lun */ - h->cmdbuf[h->cmdidx++] = STLINK_CMD_SIZE_V1; + /* cdb clength (is filled in at xfer) */ + h->cmdbuf[h->cmdidx++] = 0; } /** */ @@ -681,6 +776,8 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; + /* no answer for this function... */ + rx_size = 0; break; case STLINK_MODE_DFU: case STLINK_MODE_MASS: @@ -845,6 +942,182 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset) return ERROR_OK; } +/* + the purpose of this function is unknown... + capabilites? anyway for swim v6 it returns + 0001020600000000 +*/ +__attribute__((unused)) +static int stlink_swim_cap(void *handle, uint8_t *cap) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 8); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READ_CAP; + h->cmdbuf[h->cmdidx++] = 0x01; + res = stlink_usb_xfer(handle, h->databuf, 8); + if (res != ERROR_OK) + return res; + memcpy(cap, h->databuf, 8); + return ERROR_OK; +} + +/* debug dongle assert/deassert sreset line */ +static int stlink_swim_assert_reset(void *handle, int reset) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + if (!reset) + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ASSERT_RESET; + else + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_DEASSERT_RESET; + res = stlink_usb_xfer_busyw(handle, h->databuf, 0); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +/* + send swim enter seq + 1.3ms low then 750Hz then 1.5kHz +*/ +static int stlink_swim_enter(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER_SEQ; + res = stlink_usb_xfer_busyw(handle, h->databuf, 0); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +/* switch high/low speed swim */ +static int stlink_swim_speed(void *handle, int speed) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_SPEED; + if (speed) + h->cmdbuf[h->cmdidx++] = 1; + else + h->cmdbuf[h->cmdidx++] = 0; + res = stlink_usb_xfer_busyw(handle, h->databuf, 0); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +/* + initiate srst from swim. + nrst is pulled low for 50us. +*/ +static int stlink_swim_generate_rst(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_GEN_RST; + res = stlink_usb_xfer_busyw(handle, h->databuf, 0); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +/* + send resyncronize sequence + swim is pulled low for 16us + reply is 64 clks low +*/ +static int stlink_swim_resync(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_RESET; + res = stlink_usb_xfer_busyw(handle, h->databuf, 0); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +static int stlink_swim_writebytes(void *handle, uint32_t addr, const uint8_t *data, uint32_t len) +{ + struct stlink_usb_handle_s *h = handle; + int res; + unsigned int i; + unsigned int datalen = 0; + int cmdsize = STLINK_CMD_SIZE_V2; + + if (len > 4096) + return ERROR_FAIL; + + if (h->version.stlink == 1) + cmdsize = STLINK_SG_SIZE; + + stlink_usb_init_buffer(handle, h->tx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_WRITEMEM; + h_u16_to_be(h->cmdbuf+h->cmdidx, len); + h->cmdidx += 2; + h_u32_to_be(h->cmdbuf+h->cmdidx, addr); + h->cmdidx += 4; + for (i = 0; i < len; i++) { + if (h->cmdidx == cmdsize) + h->databuf[datalen++] = *(data++); + else + h->cmdbuf[h->cmdidx++] = *(data++); + } + if (h->version.stlink == 1) + stlink_usb_set_cbw_transfer_datalength(handle, datalen); + + res = stlink_usb_xfer_busyw(handle, h->databuf, datalen); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +static int stlink_swim_readbytes(void *handle, uint32_t addr, uint8_t *data, uint32_t len) +{ + struct stlink_usb_handle_s *h = handle; + int res; + + stlink_usb_init_buffer(handle, h->rx_ep, 0); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READMEM; + h_u16_to_be(h->cmdbuf+h->cmdidx, len); + h->cmdidx += 2; + h_u32_to_be(h->cmdbuf+h->cmdidx, addr); + h->cmdidx += 4; + res = stlink_usb_xfer_busyw(handle, h->databuf, 0); + if (res != ERROR_OK) + return res; + + stlink_usb_init_buffer(handle, h->rx_ep, len); + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READBUF; + res = stlink_usb_xfer(handle, data, len); + if (res != ERROR_OK) + return res; + + return ERROR_OK; +} + /** */ static int stlink_usb_idcode(void *handle, uint32_t *idcode) { @@ -853,6 +1126,12 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode) assert(handle != NULL); + /* there is no swim read core id cmd */ + if (h->transport == HL_TRANSPORT_SWIM) { + *idcode = 0; + return ERROR_OK; + } + stlink_usb_init_buffer(handle, h->rx_ep, 4); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; @@ -971,6 +1250,18 @@ static enum target_state stlink_usb_state(void *handle) assert(handle != NULL); + if (h->transport == HL_TRANSPORT_SWIM) { + res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); + if (res != ERROR_OK) + return TARGET_UNKNOWN; + + res = stlink_swim_resync(handle); + if (res != ERROR_OK) + return TARGET_UNKNOWN; + + return ERROR_OK; + } + if (h->reconnect_pending) { LOG_INFO("Previous state query failed, trying to reconnect"); res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); @@ -1014,6 +1305,9 @@ static int stlink_usb_assert_srst(void *handle, int srst) assert(handle != NULL); + if (h->transport == HL_TRANSPORT_SWIM) + return stlink_swim_assert_reset(handle, srst); + if (h->version.stlink == 1) return ERROR_COMMAND_NOTFOUND; @@ -1088,6 +1382,9 @@ static int stlink_usb_reset(void *handle) assert(handle != NULL); + if (h->transport == HL_TRANSPORT_SWIM) + return stlink_swim_generate_rst(handle); + stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; @@ -1294,6 +1591,12 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, stlink_usb_init_buffer(handle, h->rx_ep, read_len); + if (h->transport == HL_TRANSPORT_SWIM) { + /* read mem at addr */ + res = stlink_swim_readbytes(handle, addr, buffer, len); + return res; + } + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_8BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); @@ -1332,6 +1635,12 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, stlink_usb_init_buffer(handle, h->tx_ep, len); + if (h->transport == HL_TRANSPORT_SWIM) { + /* read mem at addr */ + res = stlink_swim_writebytes(handle, addr, buffer, len); + return res; + } + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_8BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); @@ -1440,6 +1749,11 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, if (count < bytes_remaining) bytes_remaining = count; + if (h->transport == HL_TRANSPORT_SWIM) { + retval = stlink_usb_read_mem8(handle, addr, bytes_remaining, buffer); + if (retval != ERROR_OK) + return retval; + } else /* the stlink only supports 8/32bit memory read/writes * honour 32bit, all others will be handled as 8bit access */ if (size == 4) { @@ -1510,6 +1824,14 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, if (count < bytes_remaining) bytes_remaining = count; + if (h->transport == HL_TRANSPORT_SWIM) { + if (bytes_remaining > STLINK_MAX_RW8) + bytes_remaining = STLINK_MAX_RW8; + retval = stlink_usb_write_mem8(handle, addr, bytes_remaining, buffer); + if (retval != ERROR_OK) + return retval; + } else + /* the stlink only supports 8/32bit memory read/writes * honour 32bit, all others will be handled as 8bit access */ if (size == 4) { @@ -1574,6 +1896,20 @@ static int stlink_speed(void *handle, int khz, bool query) int speed_diff = INT_MAX; struct stlink_usb_handle_s *h = handle; + if (h && (h->transport == HL_TRANSPORT_SWIM)) { + /* + we dont care what the khz rate is + we only have low and high speed... + before changing speed the SWIM_CSR HS bit + must be updated + */ + if (khz == 0) + stlink_swim_speed(handle, 0); + else + stlink_swim_speed(handle, 1); + return khz; + } + /* only supported by stlink/v2 and for firmware >= 22 */ if (h && (h->version.stlink == 1 || h->version.jtag < 22)) return khz; @@ -1780,6 +2116,17 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) goto error_open; } + if (h->transport == HL_TRANSPORT_SWIM) { + err = stlink_swim_enter(h); + if (err != ERROR_OK) { + LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)"); + goto error_open; + } + *fd = h; + h->max_mem_packet = (1 << 10); + return ERROR_OK; + } + /* clock speed only supported by stlink/v2 and for firmware >= 22 */ if (h->version.stlink >= 2 && h->version.jtag >= 22) { LOG_DEBUG("Supported clock speeds are:"); -- ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
