/***************************************************************************
+ * Copyright (C) 2020 by Tarek Bochkati *
+ * Tarek Bochkati <tarek.bouchkati@gmail.com> *
+ * *
* SWIM contributions by Ake Rehnman *
* Copyright (C) 2017 Ake Rehnman *
* ake.rehnman(at)gmail.com *
#include <jtag/hla/hla_layout.h>
#include <jtag/hla/hla_transport.h>
#include <jtag/hla/hla_interface.h>
+#include <jtag/swim.h>
#include <target/target.h>
#include <transport/transport.h>
uint32_t flags;
};
-/** */
-struct stlink_usb_handle_s {
+struct stlink_usb_priv_s {
/** */
struct libusb_device_handle *fd;
/** */
struct libusb_transfer *trans;
+};
+
+struct stlink_backend_s {
+ /** */
+ int (*open)(void *handle, struct hl_interface_param_s *param);
+ /** */
+ int (*close)(void *handle);
+ /** */
+ int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size);
+ /** */
+ int (*read_trace)(void *handle, const uint8_t *buf, int size);
+};
+
+/** */
+struct stlink_usb_handle_s {
+ /** */
+ struct stlink_backend_s *backend;
+ /** */
+ union {
+ struct stlink_usb_priv_s usb_backend_priv;
+ };
/** */
uint8_t rx_ep;
/** */
bool reconnect_pending;
};
+/** */
+static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
+{
+ struct stlink_usb_handle_s *h = handle;
+ return h->backend->open(handle, param);
+}
+
+/** */
+static inline int stlink_usb_close(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ return h->backend->close(handle);
+}
+/** */
+static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+{
+ struct stlink_usb_handle_s *h = handle;
+ return h->backend->xfer_noerrcheck(handle, buf, size);
+}
+
#define STLINK_SWIM_ERR_OK 0x00
#define STLINK_SWIM_BUSY 0x01
#define STLINK_DEBUG_ERR_OK 0x80
uint32_t address
STLINK_SWIM_RESET
- send syncronization seq (16us low, response 64 clocks low)
+ send synchronization seq (16us low, response 64 clocks low)
*/
#define STLINK_SWIM_ENTER 0x00
#define STLINK_SWIM_EXIT 0x01
#define STLINK_TRACE_SIZE 4096
#define STLINK_TRACE_MAX_HZ 2000000
+#define STLINK_V3_TRACE_MAX_HZ 24000000
#define STLINK_V3_MAX_FREQ_NB 10
#define STLINK_F_HAS_AP_INIT BIT(7)
#define STLINK_F_HAS_DPBANKSEL BIT(8)
#define STLINK_F_HAS_RW8_512BYTES BIT(9)
+#define STLINK_F_FIX_CLOSE_AP BIT(10)
/* aliases */
#define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE
+#define STLINK_F_HAS_FPU_REG STLINK_F_HAS_GETLASTRWSTATUS2
+
+#define STLINK_REGSEL_IS_FPU(x) ((x) > 0x1F)
struct speed_map {
int speed;
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
static int stlink_swim_status(void *handle);
-void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size);
+static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size);
static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map);
static int stlink_speed(void *handle, int khz, bool query);
+static int stlink_usb_open_ap(void *handle, unsigned short apsel);
/** */
static unsigned int stlink_usb_block(void *handle)
return STLINK_MAX_RW8;
}
-
-
#ifdef USE_LIBUSB_ASYNCIO
static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
/* read status */
memset(h->cmdbuf, 0, STLINK_SG_SIZE);
- ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13,
+ ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13,
STLINK_READ_TIMEOUT, &tr);
if (ret || tr != 13)
return ERROR_FAIL;
}
return jtag_libusb_bulk_transfer_n(
- h->fd,
+ h->usb_backend_priv.fd,
transfers,
n_transfers,
STLINK_WRITE_TIMEOUT);
assert(handle != NULL);
- ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf,
+ ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)h->cmdbuf,
cmdsize, STLINK_WRITE_TIMEOUT, &tr);
if (ret || tr != cmdsize)
return ERROR_FAIL;
if (h->direction == h->tx_ep && size) {
- ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
+ ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)buf,
size, STLINK_WRITE_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_DEBUG("bulk write failed");
return ERROR_FAIL;
}
} else if (h->direction == h->rx_ep && size) {
- ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
+ ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf,
size, STLINK_READ_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_DEBUG("bulk read failed");
return ERROR_OK;
}
+/** */
+static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int tr, ret;
+
+ ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size,
+ STLINK_READ_TIMEOUT, &tr);
+ if (ret || tr != size) {
+ LOG_ERROR("bulk trace read failed");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
/*
transfers block in cmdbuf
<size> indicates number of bytes in the following
data phase.
Ignore the (eventual) error code in the received packet.
*/
-static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
{
int err, cmdsize = STLINK_CMD_SIZE_V2;
struct stlink_usb_handle_s *h = handle;
static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
{
struct stlink_usb_handle_s *h = handle;
- int tr, ret;
assert(handle != NULL);
assert(h->version.flags & STLINK_F_HAS_TRACE);
- ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size,
- STLINK_READ_TIMEOUT, &tr);
- if (ret || tr != size) {
- LOG_ERROR("bulk trace read failed");
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
+ return h->backend->read_trace(handle, buf, size);
}
/*
if (h->version.jtag >= 28)
flags |= STLINK_F_HAS_AP_INIT;
+ /* API required to return proper error code on close AP from J29 */
+ if (h->version.jtag >= 29)
+ flags |= STLINK_F_FIX_CLOSE_AP;
+
/* Banked regs (DPv1 & DPv2) support from V2J32 */
if (h->version.jtag >= 32)
flags |= STLINK_F_HAS_DPBANKSEL;
/* API required to init AP before any AP access */
flags |= STLINK_F_HAS_AP_INIT;
+ /* API required to return proper error code on close AP */
+ flags |= STLINK_F_FIX_CLOSE_AP;
+
/* Banked regs (DPv1 & DPv2) support from V3J2 */
if (h->version.jtag >= 2)
flags |= STLINK_F_HAS_DPBANKSEL;
return STLINK_MODE_DEBUG_SWD;
case HL_TRANSPORT_JTAG:
return STLINK_MODE_DEBUG_JTAG;
- case HL_TRANSPORT_SWIM:
- return STLINK_MODE_DEBUG_SWIM;
default:
return STLINK_MODE_UNKNOWN;
}
}
/** */
-static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed)
+static int stlink_usb_exit_mode(void *handle)
{
int res;
uint8_t mode;
enum stlink_mode emode;
- struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
break;
}
- if (emode != STLINK_MODE_UNKNOWN) {
- res = stlink_usb_mode_leave(handle, emode);
+ if (emode != STLINK_MODE_UNKNOWN)
+ return stlink_usb_mode_leave(handle, emode);
- if (res != ERROR_OK)
- return res;
- }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed)
+{
+ int res;
+ uint8_t mode;
+ enum stlink_mode emode;
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ res = stlink_usb_exit_mode(handle);
+ if (res != ERROR_OK)
+ return res;
res = stlink_usb_current_mode(handle, &mode);
}
/*
the purpose of this function is unknown...
- capabilites? anyway for swim v6 it returns
+ capabilities? anyway for swim v6 it returns
0001020600000000
*/
__attribute__((unused))
}
/*
- send resyncronize sequence
+ send resynchronize sequence
swim is pulled low for 16us
reply is 64 clks low
*/
assert(handle != NULL);
- if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
- res = stlink_usb_mode_enter(handle, h->st_mode);
- 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, h->st_mode);
assert(handle != NULL);
- if (h->st_mode == STLINK_MODE_DEBUG_SWIM)
- return stlink_swim_generate_rst(handle);
-
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
}
/** */
-static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
+static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
+ if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) {
+ res = stlink_usb_write_debug_reg(h, DCB_DCRSR, regsel & 0x7f);
+ if (res != ERROR_OK)
+ return res;
+
+ /* FIXME: poll DHCSR.S_REGRDY before read DCRDR */
+ return stlink_usb_v2_read_debug_reg(h, DCB_DCRDR, val);
+ }
+
stlink_usb_init_buffer(handle, h->rx_ep, h->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG;
else
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG;
- h->cmdbuf[h->cmdidx++] = num;
+ h->cmdbuf[h->cmdidx++] = regsel;
if (h->version.jtag_api == STLINK_JTAG_API_V1) {
res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4);
}
/** */
-static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
+static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
+ if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) {
+ int res = stlink_usb_write_debug_reg(h, DCB_DCRDR, val);
+ if (res != ERROR_OK)
+ return res;
+
+ return stlink_usb_write_debug_reg(h, DCB_DCRSR, DCRSR_WnR | (regsel & 0x7f));
+ /* FIXME: poll DHCSR.S_REGRDY after write DCRSR */
+ }
+
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG;
else
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG;
- h->cmdbuf[h->cmdidx++] = num;
+ h->cmdbuf[h->cmdidx++] = regsel;
h_u32_to_le(h->cmdbuf+h->cmdidx, val);
h->cmdidx += 4;
if (count < bytes_remaining)
bytes_remaining = count;
- if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
- retval = stlink_swim_readbytes(handle, addr, bytes_remaining, buffer);
- if (retval != ERROR_OK)
- return retval;
- } else
/*
* all stlink support 8/32bit memory read/writes and only from
* stlink V2J26 there is support for 16 bit memory read/write.
if (count < bytes_remaining)
bytes_remaining = count;
- if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
- retval = stlink_swim_writebytes(handle, addr, bytes_remaining, buffer);
- if (retval != ERROR_OK)
- return retval;
- } else
/*
* all stlink support 8/32bit memory read/writes and only from
* stlink V2J26 there is support for 16 bit memory read/write.
static int stlink_speed_swim(void *handle, int khz, bool query)
{
+ int retval;
+
/*
- 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;
+ if (!query) {
+ retval = stlink_swim_speed(handle, (khz < SWIM_FREQ_HIGH) ? 0 : 1);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Unable to set adapter speed");
+ }
+
+ return (khz < SWIM_FREQ_HIGH) ? SWIM_FREQ_LOW : SWIM_FREQ_HIGH;
}
static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_size, int khz, bool query)
return stlink_khz_to_speed_map_jtag[speed_index].speed;
}
-void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size)
+static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size)
{
unsigned int i;
}
/** */
-static int stlink_usb_close(void *handle)
+static int stlink_usb_usb_close(void *handle)
{
- int res;
- uint8_t mode;
- enum stlink_mode emode;
struct stlink_usb_handle_s *h = handle;
- if (h && h->fd)
- res = stlink_usb_current_mode(handle, &mode);
- else
- res = ERROR_FAIL;
- /* do not exit if return code != ERROR_OK,
- it prevents us from closing jtag_libusb */
-
- if (res == ERROR_OK) {
- /* try to exit current mode */
- switch (mode) {
- case STLINK_DEV_DFU_MODE:
- emode = STLINK_MODE_DFU;
- break;
- case STLINK_DEV_DEBUG_MODE:
- emode = STLINK_MODE_DEBUG_SWD;
- break;
- case STLINK_DEV_SWIM_MODE:
- emode = STLINK_MODE_DEBUG_SWIM;
- break;
- case STLINK_DEV_BOOTLOADER_MODE:
- case STLINK_DEV_MASS_MODE:
- default:
- emode = STLINK_MODE_UNKNOWN;
- break;
- }
-
- if (emode != STLINK_MODE_UNKNOWN)
- stlink_usb_mode_leave(handle, emode);
- /* do not check return code, it prevent
- us from closing jtag_libusb */
+ if (h && h->usb_backend_priv.fd) {
+ stlink_usb_exit_mode(h);
+ /* do not check return code, it prevent
+ us from closing jtag_libusb */
+ jtag_libusb_close(h->usb_backend_priv.fd);
}
- if (h && h->fd)
- jtag_libusb_close(h->fd);
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_close(void *handle)
+{
+ if (handle != NULL) {
+ struct stlink_usb_handle_s *h = handle;
+
+ stlink_usb_close(handle);
- free(h);
+ free(h);
+ }
return ERROR_OK;
}
* based on the length (0x1a = 26) we could easily decide if we have to fixup the serial
* and then we have just to convert the raw data into printable characters using sprintf
*/
-char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
+static char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
struct libusb_device_descriptor *dev_desc)
{
int usb_retval;
}
/** */
-static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
+static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param)
{
+ struct stlink_usb_handle_s *h = handle;
int err, retry_count = 1;
- struct stlink_usb_handle_s *h;
-
- LOG_DEBUG("stlink_usb_open");
-
- h = calloc(1, sizeof(struct stlink_usb_handle_s));
-
- if (h == 0) {
- LOG_DEBUG("malloc failed");
- return ERROR_FAIL;
- }
-
- h->st_mode = mode;
-
- for (unsigned i = 0; param->vid[i]; i++) {
- LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
- h->st_mode, param->vid[i], param->pid[i],
- param->serial ? param->serial : "");
- }
/*
On certain host USB configurations(e.g. MacBook Air)
*/
do {
if (jtag_libusb_open(param->vid, param->pid, param->serial,
- &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
+ &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
LOG_ERROR("open failed");
- goto error_open;
+ return ERROR_FAIL;
}
- jtag_libusb_set_configuration(h->fd, 0);
+ jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0);
- if (libusb_claim_interface(h->fd, 0) != ERROR_OK) {
+ if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) {
LOG_DEBUG("claim interface failed");
- goto error_open;
+ return ERROR_FAIL;
}
/* RX EP is common for all versions */
h->rx_ep = STLINK_RX_EP;
uint16_t pid;
- if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) {
+ if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) {
LOG_DEBUG("libusb_get_pid failed");
- goto error_open;
+ return ERROR_FAIL;
}
/* wrap version for first read */
} else if (h->version.stlink == 1 ||
retry_count == 0) {
LOG_ERROR("read version failed");
- goto error_open;
+ return ERROR_FAIL;
} else {
- err = libusb_release_interface(h->fd, 0);
+ err = libusb_release_interface(h->usb_backend_priv.fd, 0);
if (err != ERROR_OK) {
LOG_ERROR("release interface failed");
- goto error_open;
+ return ERROR_FAIL;
}
- err = libusb_reset_device(h->fd);
+ err = libusb_reset_device(h->usb_backend_priv.fd);
if (err != ERROR_OK) {
LOG_ERROR("reset device failed");
- goto error_open;
+ return ERROR_FAIL;
}
- jtag_libusb_close(h->fd);
+ jtag_libusb_close(h->usb_backend_priv.fd);
/*
Give the device one second to settle down and
reenumerate.
}
} while (1);
+ return ERROR_OK;
+}
+
+static struct stlink_backend_s stlink_usb_backend = {
+ .open = stlink_usb_usb_open,
+ .close = stlink_usb_usb_close,
+ .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck,
+ .read_trace = stlink_usb_usb_read_trace,
+};
+
+static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
+{
+ struct stlink_usb_handle_s *h;
+
+ LOG_DEBUG("stlink_open");
+
+ h = calloc(1, sizeof(struct stlink_usb_handle_s));
+
+ if (h == 0) {
+ LOG_DEBUG("malloc failed");
+ return ERROR_FAIL;
+ }
+
+ h->st_mode = mode;
+
+ for (unsigned i = 0; param->vid[i]; i++) {
+ LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
+ h->st_mode, param->vid[i], param->pid[i],
+ param->serial ? param->serial : "");
+ }
+
+ h->backend = &stlink_usb_backend;
+
+ if (stlink_usb_open(h, param) != ERROR_OK)
+ goto error_open;
+
/* check if mode is supported */
- err = ERROR_OK;
+ int err = ERROR_OK;
switch (h->st_mode) {
case STLINK_MODE_DEBUG_SWD:
h->max_mem_packet = (1 << 10);
uint8_t buffer[4];
+ stlink_usb_open_ap(h, 0);
err = stlink_usb_read_mem32(h, CPUID, 4, buffer);
if (err == ERROR_OK) {
uint32_t cpuid = le_to_h_u32(buffer);
return ERROR_OK;
error_open:
- stlink_usb_close(h);
-
+ stlink_close(h);
return ERROR_FAIL;
}
static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
{
- return stlink_usb_open(param, stlink_get_mode(param->transport), fd);
+ return stlink_open(param, stlink_get_mode(param->transport), fd);
}
-int stlink_config_trace(void *handle, bool enabled,
+static int stlink_config_trace(void *handle, bool enabled,
enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
unsigned int *trace_freq, unsigned int traceclkin_freq,
uint16_t *prescaler)
{
struct stlink_usb_handle_s *h = handle;
- uint16_t presc;
if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) ||
pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
return ERROR_FAIL;
}
- if (!enabled) {
- stlink_usb_trace_disable(h);
- return ERROR_OK;
- }
+ unsigned int max_trace_freq = (h->version.stlink == 3) ?
+ STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ;
- if (*trace_freq > STLINK_TRACE_MAX_HZ) {
+ /* Only concern ourselves with the frequency if the STlink is processing it. */
+ if (enabled && *trace_freq > max_trace_freq) {
LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u",
- STLINK_TRACE_MAX_HZ);
+ max_trace_freq);
return ERROR_FAIL;
}
stlink_usb_trace_disable(h);
if (!*trace_freq)
- *trace_freq = STLINK_TRACE_MAX_HZ;
-
- presc = traceclkin_freq / *trace_freq;
+ *trace_freq = max_trace_freq;
- if (traceclkin_freq % *trace_freq > 0)
- presc++;
+ unsigned int presc = (traceclkin_freq + *trace_freq / 2) / *trace_freq;
+ if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) {
+ LOG_ERROR("SWO frequency is not suitable. Please choose a different "
+ "frequency.");
+ return ERROR_FAIL;
+ }
- if (presc > TPIU_ACPR_MAX_SWOSCALER) {
+ /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */
+ unsigned int max_deviation = (traceclkin_freq * 3) / 100;
+ if (presc * *trace_freq < traceclkin_freq - max_deviation ||
+ presc * *trace_freq > traceclkin_freq + max_deviation) {
LOG_ERROR("SWO frequency is not suitable. Please choose a different "
"frequency.");
return ERROR_FAIL;
}
*prescaler = presc;
+
+ if (!enabled)
+ return ERROR_OK;
+
h->trace.source_hz = *trace_freq;
return stlink_usb_trace_enable(h);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG;
h->cmdbuf[h->cmdidx++] = ap_num;
- return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+ /* ignore incorrectly returned error on bogus FW */
+ if (h->version.flags & STLINK_F_FIX_CLOSE_AP)
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+ else
+ return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
+
}
/** */
retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8);
*val = le_to_h_u32(h->databuf + 4);
- LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%x", dap_port, addr, *val);
+ LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, *val);
return retval;
}
if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
return ERROR_COMMAND_NOTFOUND;
- LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%x", dap_port, addr, val);
+ LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, val);
stlink_usb_init_buffer(handle, h->rx_ep, 16);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG;
/** */
.open = stlink_usb_hl_open,
/** */
- .close = stlink_usb_close,
+ .close = stlink_close,
/** */
.idcode = stlink_usb_idcode,
/** */
return retval;
}
-/** */
-static int stlink_dap_open_ap(unsigned short apsel)
+static int stlink_usb_open_ap(void *handle, unsigned short apsel)
{
+ struct stlink_usb_handle_s *h = handle;
int retval;
/* nothing to do on old versions */
- if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT))
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
return ERROR_OK;
if (apsel > DP_APSEL_MAX)
if (test_bit(apsel, opened_ap))
return ERROR_OK;
- retval = stlink_usb_init_access_port(stlink_dap_handle, apsel);
+ retval = stlink_usb_init_access_port(h, apsel);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
+static int stlink_dap_open_ap(unsigned short apsel)
+{
+ return stlink_usb_open_ap(stlink_dap_handle, apsel);
+}
+
/** */
static int stlink_dap_closeall_ap(void)
{
LOG_ERROR("Error closing APs");
}
+static int stlink_swim_op_srst(void)
+{
+ return stlink_swim_generate_rst(stlink_dap_handle);
+}
+
+static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size,
+ uint32_t count, uint8_t *buffer)
+{
+ int retval;
+ uint32_t bytes_remaining;
+
+ LOG_DEBUG_IO("read at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count);
+ count *= size;
+
+ while (count) {
+ bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count;
+ retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += bytes_remaining;
+ addr += bytes_remaining;
+ count -= bytes_remaining;
+ }
+
+ return ERROR_OK;
+}
+
+static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size,
+ uint32_t count, const uint8_t *buffer)
+{
+ int retval;
+ uint32_t bytes_remaining;
+
+ LOG_DEBUG_IO("write at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count);
+ count *= size;
+
+ while (count) {
+ bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count;
+ retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += bytes_remaining;
+ addr += bytes_remaining;
+ count -= bytes_remaining;
+ }
+
+ return ERROR_OK;
+}
+
+static int stlink_swim_op_reconnect(void)
+{
+ int retval;
+
+ retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return stlink_swim_resync(stlink_dap_handle);
+}
+
static int stlink_dap_config_trace(bool enabled,
enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
unsigned int *trace_freq, unsigned int traceclkin_freq,
mode = STLINK_MODE_DEBUG_SWD;
else if (transport_is_dapdirect_jtag())
mode = STLINK_MODE_DEBUG_JTAG;
+ else if (transport_is_swim())
+ mode = STLINK_MODE_DEBUG_SWIM;
else {
LOG_ERROR("Unsupported transport");
return ERROR_FAIL;
}
- retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
+ retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
if (retval != ERROR_OK)
return retval;
- if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) {
+ if ((mode != STLINK_MODE_DEBUG_SWIM) &&
+ !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) {
LOG_ERROR("ST-Link version does not support DAP direct transport");
return ERROR_FAIL;
}
free((void *)stlink_dap_param.serial);
stlink_dap_param.serial = NULL;
- return stlink_usb_close(stlink_dap_handle);
+ return stlink_close(stlink_dap_handle);
}
/** */
.quit = stlink_dap_op_quit, /* optional */
};
-static const char *const stlink_dap_transport[] = { "dapdirect_jtag", "dapdirect_swd", NULL };
+static const struct swim_driver stlink_swim_ops = {
+ .srst = stlink_swim_op_srst,
+ .read_mem = stlink_swim_op_read_mem,
+ .write_mem = stlink_swim_op_write_mem,
+ .reconnect = stlink_swim_op_reconnect,
+};
+
+static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL };
struct adapter_driver stlink_dap_adapter_driver = {
.name = "st-link",
.dap_jtag_ops = &stlink_dap_ops,
.dap_swd_ops = &stlink_dap_ops,
+ .swim_ops = &stlink_swim_ops,
};