X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fstlink_usb.c;h=18498dd22e2dd8b3f75a50e1818e9badde045536;hp=554ffc1edcbfc2e76e6fe9fd558a3dce37f988b1;hb=4ed3a1efa2e653836133cabddb0a7e50150b3bd4;hpb=d019080dfaa6c0c49228ecec2ad0c585ac65cb73 diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 554ffc1edc..18498dd22e 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -124,12 +124,8 @@ struct stlink_usb_handle_s { struct { /** whether SWO tracing is enabled or not */ bool enabled; - /** trace data destination file */ - FILE *output_f; - /** trace module source clock (for prescaler) */ + /** trace module source clock */ uint32_t source_hz; - /** trace module clock prescaler */ - uint32_t prescale; } trace; /** reconnect is needed next time we try to query the * status */ @@ -139,6 +135,8 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_ERR_OK 0x80 #define STLINK_DEBUG_ERR_FAULT 0x81 #define STLINK_SWD_AP_WAIT 0x10 +#define STLINK_JTAG_WRITE_ERROR 0x0c +#define STLINK_JTAG_WRITE_VERIF_ERROR 0x0d #define STLINK_SWD_DP_WAIT 0x14 #define STLINK_CORE_RUNNING 0x80 @@ -394,6 +392,12 @@ static int stlink_usb_error_check(void *handle) case STLINK_SWD_DP_WAIT: LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_AP_WAIT); return ERROR_WAIT; + case STLINK_JTAG_WRITE_ERROR: + LOG_DEBUG("Write error"); + return ERROR_FAIL; + case STLINK_JTAG_WRITE_VERIF_ERROR: + LOG_DEBUG("Verify error"); + return ERROR_FAIL; default: LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); return ERROR_FAIL; @@ -870,7 +874,7 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) } /** */ -static void stlink_usb_trace_read(void *handle) +static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size) { struct stlink_usb_handle_s *h = handle; @@ -885,29 +889,20 @@ static void stlink_usb_trace_read(void *handle) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GET_TRACE_NB; res = stlink_usb_xfer(handle, h->databuf, 2); - if (res == ERROR_OK) { - uint8_t buf[STLINK_TRACE_SIZE]; - size_t size = le_to_h_u16(h->databuf); - - if (size > 0) { - size = size < sizeof(buf) ? size : sizeof(buf) - 1; - - res = stlink_usb_read_trace(handle, buf, size); - if (res == ERROR_OK) { - if (h->trace.output_f) { - /* Log retrieved trace output */ - if (fwrite(buf, 1, size, h->trace.output_f) > 0) - fflush(h->trace.output_f); - } - } - } + if (res != ERROR_OK) + return res; + + size_t bytes_avail = le_to_h_u16(h->databuf); + *size = bytes_avail < *size ? bytes_avail : *size - 1; + + if (*size > 0) { + res = stlink_usb_read_trace(handle, buf, *size); + if (res != ERROR_OK) + return res; + return ERROR_OK; } } -} - -static int stlink_usb_trace_read_callback(void *handle) -{ - stlink_usb_trace_read(handle); + *size = 0; return ERROR_OK; } @@ -925,8 +920,6 @@ static enum target_state stlink_usb_v2_get_status(void *handle) else if (status & S_RESET_ST) return TARGET_RESET; - stlink_usb_trace_read(handle); - return TARGET_RUNNING; } @@ -975,25 +968,6 @@ static enum target_state stlink_usb_state(void *handle) return TARGET_UNKNOWN; } -/** */ -static int stlink_usb_reset(void *handle) -{ - struct stlink_usb_handle_s *h = handle; - - assert(handle != NULL); - - stlink_usb_init_buffer(handle, h->rx_ep, 2); - - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - - if (h->jtag_api == STLINK_JTAG_API_V1) - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS; - else - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS; - - return stlink_cmd_allow_retry(handle, h->databuf, 2); -} - static int stlink_usb_assert_srst(void *handle, int srst) { struct stlink_usb_handle_s *h = handle; @@ -1012,62 +986,6 @@ static int stlink_usb_assert_srst(void *handle, int srst) return stlink_cmd_allow_retry(handle, h->databuf, 2); } -/** */ -static int stlink_configure_target_trace_port(void *handle) -{ - int res; - uint32_t reg; - struct stlink_usb_handle_s *h = handle; - - assert(handle != NULL); - - /* configure the TPI */ - - /* enable the trace subsystem */ - res = stlink_usb_v2_read_debug_reg(handle, DCB_DEMCR, ®); - if (res != ERROR_OK) - goto out; - res = stlink_usb_write_debug_reg(handle, DCB_DEMCR, TRCENA|reg); - if (res != ERROR_OK) - goto out; - /* set the TPI clock prescaler */ - res = stlink_usb_write_debug_reg(handle, TPI_ACPR, h->trace.prescale); - if (res != ERROR_OK) - goto out; - /* select the pin protocol. The STLinkv2 only supports asynchronous - * UART emulation (NRZ) mode, so that's what we pick. */ - res = stlink_usb_write_debug_reg(handle, TPI_SPPR, 0x02); - if (res != ERROR_OK) - goto out; - /* disable continuous formatting */ - res = stlink_usb_write_debug_reg(handle, TPI_FFCR, (1<<8)); - if (res != ERROR_OK) - goto out; - - /* configure the ITM */ - - /* unlock access to the ITM registers */ - res = stlink_usb_write_debug_reg(handle, ITM_LAR, 0xC5ACCE55); - if (res != ERROR_OK) - goto out; - /* enable trace with ATB ID 1 */ - res = stlink_usb_write_debug_reg(handle, ITM_TCR, (1<<16)|(1<<0)|(1<<2)); - if (res != ERROR_OK) - goto out; - /* trace privilege */ - res = stlink_usb_write_debug_reg(handle, ITM_TPR, 1); - if (res != ERROR_OK) - goto out; - /* trace port enable (port 0) */ - res = stlink_usb_write_debug_reg(handle, ITM_TER, (1<<0)); - if (res != ERROR_OK) - goto out; - - res = ERROR_OK; -out: - return res; -} - /** */ static void stlink_usb_trace_disable(void *handle) { @@ -1085,10 +1003,8 @@ static void stlink_usb_trace_disable(void *handle) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX; res = stlink_usb_xfer(handle, h->databuf, 2); - if (res == ERROR_OK) { + if (res == ERROR_OK) h->trace.enabled = false; - target_unregister_timer_callback(stlink_usb_trace_read_callback, handle); - } } @@ -1101,38 +1017,20 @@ static int stlink_usb_trace_enable(void *handle) assert(handle != NULL); if (h->version.jtag >= STLINK_TRACE_MIN_VERSION) { - uint32_t trace_hz; - - res = stlink_configure_target_trace_port(handle); - if (res != ERROR_OK) - LOG_ERROR("Unable to configure tracing on target"); - - trace_hz = h->trace.prescale > 0 ? - h->trace.source_hz / (h->trace.prescale + 1) : - h->trace.source_hz; - stlink_usb_init_buffer(handle, h->rx_ep, 10); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_START_TRACE_RX; h_u16_to_le(h->cmdbuf+h->cmdidx, (uint16_t)STLINK_TRACE_SIZE); h->cmdidx += 2; - h_u32_to_le(h->cmdbuf+h->cmdidx, trace_hz); + h_u32_to_le(h->cmdbuf+h->cmdidx, h->trace.source_hz); h->cmdidx += 4; res = stlink_usb_xfer(handle, h->databuf, 2); if (res == ERROR_OK) { h->trace.enabled = true; - LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", trace_hz); - /* We need the trace read function to be called at a - * high-enough frequency to ensure reasonable - * "timeliness" in processing ITM/DWT data. - * TODO: An alternative could be using the asynchronous - * features of the libusb-1.0 API to queue up one or more - * reads in advance and requeue them once they are - * completed. */ - target_register_timer_callback(stlink_usb_trace_read_callback, 1, 1, handle); + LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", h->trace.source_hz); } } else { LOG_ERROR("Tracing is not supported by this version."); @@ -1142,6 +1040,35 @@ static int stlink_usb_trace_enable(void *handle) return res; } +/** */ +static int stlink_usb_reset(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + int retval; + + assert(handle != NULL); + + stlink_usb_init_buffer(handle, h->rx_ep, 2); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + + if (h->jtag_api == STLINK_JTAG_API_V1) + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS; + else + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS; + + retval = stlink_cmd_allow_retry(handle, h->databuf, 2); + if (retval != ERROR_OK) + return retval; + + if (h->trace.enabled) { + stlink_usb_trace_disable(h); + return stlink_usb_trace_enable(h); + } + + return ERROR_OK; +} + /** */ static int stlink_usb_run(void *handle) { @@ -1153,14 +1080,6 @@ static int stlink_usb_run(void *handle) if (h->jtag_api == STLINK_JTAG_API_V2) { res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); - /* Try to start tracing, if requested */ - if (res == ERROR_OK && h->trace.source_hz && !h->trace.enabled) { - if (stlink_usb_trace_enable(handle) == ERROR_OK) - LOG_DEBUG("Tracing: enabled"); - else - LOG_ERROR("Tracing: enable failed"); - } - return res; } @@ -1183,9 +1102,6 @@ static int stlink_usb_halt(void *handle) if (h->jtag_api == STLINK_JTAG_API_V2) { res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); - if (res == ERROR_OK && h->trace.enabled) - stlink_usb_trace_disable(handle); - return res; } @@ -1816,17 +1732,6 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) /* set the used jtag api, this will default to the newest supported version */ h->jtag_api = api; - if (h->jtag_api >= 2 && param->trace_source_hz > 0) { - uint32_t prescale; - - prescale = param->trace_source_hz > STLINK_TRACE_MAX_HZ ? - (param->trace_source_hz / STLINK_TRACE_MAX_HZ) - 1 : 0; - - h->trace.output_f = param->trace_f; - h->trace.source_hz = param->trace_source_hz; - h->trace.prescale = prescale; - } - /* initialize the debug hardware */ err = stlink_usb_init_mode(h, param->connect_under_reset); @@ -1872,6 +1777,36 @@ error_open: return ERROR_FAIL; } +int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol, + uint32_t port_size, unsigned int *trace_freq) +{ + struct stlink_usb_handle_s *h = handle; + + if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) { + LOG_ERROR("The attached ST-LINK version doesn't support this trace mode"); + return ERROR_FAIL; + } + + if (!enabled) { + stlink_usb_trace_disable(h); + return ERROR_OK; + } + + if (*trace_freq > STLINK_TRACE_MAX_HZ) { + LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", + STLINK_TRACE_MAX_HZ); + return ERROR_FAIL; + } + + stlink_usb_trace_disable(h); + + if (!*trace_freq) + *trace_freq = STLINK_TRACE_MAX_HZ; + h->trace.source_hz = *trace_freq; + + return stlink_usb_trace_enable(h); +} + /** */ struct hl_layout_api_s stlink_usb_layout_api = { /** */ @@ -1908,4 +1843,8 @@ struct hl_layout_api_s stlink_usb_layout_api = { .override_target = stlink_usb_override_target, /** */ .speed = stlink_speed, + /** */ + .config_trace = stlink_config_trace, + /** */ + .poll_trace = stlink_usb_trace_read, };