dap: add header and macro to instantiate DAP context

Although we have the three layers, SWDP driver API, DAP stack, and USB
backend, to implement a debug probe, there is no way for the user to
instantiate the DAP context, which would allow it to be used with
different backends or to change the configuration at runtime.

The Debug Access Port (DAP) is an implementation of the ARM Debug
Interface (ADI) that is typically integrated into SoC.
With all three layers, we implement a link to the DAP on the SoC.
Let's call it Zephyr DAP Link and use the dap_link prefix. There is also
a MBED DAPLink project that implements similar functionality, but using
a different name would likely cause more confusion.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer
2025-11-28 23:11:50 +01:00
committed by Alberto Escolar
parent 2c254285cb
commit cfd748fff1
5 changed files with 205 additions and 85 deletions

View File

@@ -0,0 +1,113 @@
/*
* SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Main header file for DAP Link API.
*/
#ifndef ZEPHYR_INCLUDE_DAP_DAP_LINK_H
#define ZEPHYR_INCLUDE_DAP_DAP_LINK_H
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/drivers/swdp.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Zephyr DAP Link API
* @defgroup DAP API
* @ingroup io_interfaces
* @since 4.4
* @version 0.1.0
* @{
*/
/**
* @cond INTERNAL_HIDDEN
* Degug Access Port (DAP) Link runtime context
*
*/
struct dap_link_context {
/* Pointer to SWD or JTAG device. Only SWD is supported yet. */
const struct device *dev;
atomic_t state;
/* Runtime debug port type */
uint8_t debug_port;
/* Debug port capabilities */
uint8_t capabilities;
/* Packet size used by a backend */
uint16_t pkt_size;
struct {
/* Idle cycles after transfer */
uint8_t idle_cycles;
/* Number of retries after WAIT response */
uint16_t retry_count;
/* Number of retries if read value does not match */
uint16_t match_retry;
/* Match Mask */
uint32_t match_mask;
} transfer;
};
/** @endcond */
/**
* @brief Define Zephyr DAP Link context structure
*
* Example of use:
*
* @code{.c}
* DAP_LINK_CONTEXT_DEFINE(sample_link_ctx,
* DEVICE_DT_GET_ONE(zephyr_swdp_gpio));
* @endcode
*
* @param ctx_name DAP Link context name
* @param ctx_dev Pointer to SWDP device
*/
#define DAP_LINK_CONTEXT_DEFINE(ctx_name, ctx_dev) \
static struct dap_link_context ctx_name = { \
.dev = ctx_dev, \
}
/**
* @brief Initialize DAP Link
*
* @param[in] dap_link_ctx Pointer to DAP Link context
*
* @return 0 on success, or error code
*/
int dap_link_init(struct dap_link_context *const dap_link_ctx);
/**
* @brief Set packet size used by a DAP Link backend
*
* @param[in] dap_link_ctx Pointer to DAP Link context
* @param[in] pkt_size Packet size
*
*/
void dap_link_set_pkt_size(struct dap_link_context *const dap_link_ctx,
const uint16_t pkt_size);
/**
* @brief Initialize DAP Link USB backend
*
* @param[in] dap_link_ctx Pointer to DAP Link context
*
* @return 0 on success, or error code
*/
int dap_link_backend_usb_init(struct dap_link_context *const dap_link_ctx);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* ZEPHYR_INCLUDE_DAP_DAP_LINK_H */

View File

@@ -12,8 +12,7 @@
#include <zephyr/usb/usbd.h>
#include <zephyr/usb/bos.h>
#include <zephyr/usb/msos_desc.h>
#include <cmsis_dap.h>
#include <zephyr/dap/dap_link.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(dap_sample, LOG_LEVEL_INF);
@@ -21,18 +20,25 @@ LOG_MODULE_REGISTER(dap_sample, LOG_LEVEL_INF);
#include "webusb.h"
#include "msosv2.h"
DAP_LINK_CONTEXT_DEFINE(sample_dap_ctx, DEVICE_DT_GET_ONE(zephyr_swdp_gpio));
int main(void)
{
const struct device *const swd_dev = DEVICE_DT_GET_ONE(zephyr_swdp_gpio);
struct usbd_context *sample_usbd;
int ret;
ret = dap_setup(swd_dev);
ret = dap_link_init(&sample_dap_ctx);
if (ret) {
LOG_ERR("Failed to initialize DAP controller, %d", ret);
return ret;
}
ret = dap_link_backend_usb_init(&sample_dap_ctx);
if (ret) {
LOG_ERR("Failed to initialize DAP Link USB backend, %d", ret);
return ret;
}
sample_usbd = sample_usbd_setup_device(NULL);
if (sample_usbd == NULL) {
LOG_ERR("Failed to setup USB device");

View File

@@ -18,6 +18,7 @@
#include <zephyr/init.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/swdp.h>
#include <zephyr/dap/dap_link.h>
#include <stdint.h>
#include <cmsis_dap.h>
@@ -27,26 +28,6 @@ LOG_MODULE_REGISTER(dap, CONFIG_DAP_LOG_LEVEL);
#define DAP_STATE_CONNECTED 0
struct dap_context {
struct device *swdp_dev;
atomic_t state;
uint8_t debug_port;
uint8_t capabilities;
uint16_t pkt_size;
struct {
/* Idle cycles after transfer */
uint8_t idle_cycles;
/* Number of retries after WAIT response */
uint16_t retry_count;
/* Number of retries if read value does not match */
uint16_t match_retry;
/* Match Mask */
uint32_t match_mask;
} transfer;
};
static struct dap_context dap_ctx[1];
#define CMSIS_DAP_PACKET_MIN_SIZE 64
BUILD_ASSERT(sizeof(CONFIG_CMSIS_DAP_PROBE_VENDOR) <=
@@ -69,7 +50,7 @@ BUILD_ASSERT(sizeof(CONFIG_CMSIS_DAP_DEVICE_NAME) <=
"DEVICE_NAME string is too long.");
/* Get DAP Information */
static uint16_t dap_info(struct dap_context *const ctx,
static uint16_t dap_info(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -165,7 +146,7 @@ static uint16_t dap_info(struct dap_context *const ctx,
}
/* Process Host Status command and prepare response */
static uint16_t dap_host_status(struct dap_context *const ctx,
static uint16_t dap_host_status(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -190,7 +171,7 @@ static uint16_t dap_host_status(struct dap_context *const ctx,
}
/* Process Connect command and prepare response */
static uint16_t dap_connect(struct dap_context *const ctx,
static uint16_t dap_connect(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -213,7 +194,7 @@ static uint16_t dap_connect(struct dap_context *const ctx,
break;
}
(void)swdp_port_on(ctx->swdp_dev);
(void)swdp_port_on(ctx->dev);
break;
case DAP_PORT_JTAG:
LOG_ERR("port unsupported");
@@ -230,7 +211,7 @@ static uint16_t dap_connect(struct dap_context *const ctx,
}
/* Process Disconnect command and prepare response */
static uint16_t dap_disconnect(struct dap_context *const ctx,
static uint16_t dap_disconnect(struct dap_link_context *const ctx,
uint8_t *const response)
{
@@ -239,7 +220,7 @@ static uint16_t dap_disconnect(struct dap_context *const ctx,
ctx->debug_port = DAP_PORT_DISABLED;
if (atomic_test_bit(&ctx->state, DAP_STATE_CONNECTED)) {
(void)swdp_port_off(ctx->swdp_dev);
(void)swdp_port_off(ctx->dev);
} else {
LOG_WRN("DAP device is not connected");
}
@@ -251,7 +232,7 @@ static uint16_t dap_disconnect(struct dap_context *const ctx,
}
/* Process Delay command and prepare response */
static uint16_t dap_delay(struct dap_context *const ctx,
static uint16_t dap_delay(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -266,7 +247,7 @@ static uint16_t dap_delay(struct dap_context *const ctx,
}
/* Process Reset Target command and prepare response */
static uint16_t dap_reset_target(struct dap_context *const ctx,
static uint16_t dap_reset_target(struct dap_link_context *const ctx,
uint8_t *const response)
{
response[0] = DAP_OK;
@@ -277,7 +258,7 @@ static uint16_t dap_reset_target(struct dap_context *const ctx,
}
/* Process SWJ Pins command and prepare response */
static uint16_t dap_swj_pins(struct dap_context *const ctx,
static uint16_t dap_swj_pins(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -295,11 +276,11 @@ static uint16_t dap_swj_pins(struct dap_context *const ctx,
/* Skip if nothing selected. */
if (select) {
(void)swdp_set_pins(ctx->swdp_dev, select, value);
(void)swdp_set_pins(ctx->dev, select, value);
}
do {
(void)swdp_get_pins(ctx->swdp_dev, &state);
(void)swdp_get_pins(ctx->dev, &state);
LOG_INF("select 0x%02x, value 0x%02x, wait %u, state 0x%02x",
select, value, wait, state);
if ((value & select) == (state & select)) {
@@ -314,7 +295,7 @@ static uint16_t dap_swj_pins(struct dap_context *const ctx,
}
/* Process SWJ Clock command and prepare response */
static uint16_t dap_swj_clock(struct dap_context *const ctx,
static uint16_t dap_swj_clock(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -324,7 +305,7 @@ static uint16_t dap_swj_clock(struct dap_context *const ctx,
if (atomic_test_bit(&ctx->state, DAP_STATE_CONNECTED)) {
if (clk) {
(void)swdp_set_clock(ctx->swdp_dev, clk);
(void)swdp_set_clock(ctx->dev, clk);
response[0] = DAP_OK;
} else {
response[0] = DAP_ERROR;
@@ -338,7 +319,7 @@ static uint16_t dap_swj_clock(struct dap_context *const ctx,
}
/* Process SWJ Sequence command and prepare response */
static uint16_t dap_swj_sequence(struct dap_context *const ctx,
static uint16_t dap_swj_sequence(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -356,14 +337,14 @@ static uint16_t dap_swj_sequence(struct dap_context *const ctx,
return 1U;
}
(void)swdp_output_sequence(ctx->swdp_dev, count, &request[1]);
(void)swdp_output_sequence(ctx->dev, count, &request[1]);
response[0] = DAP_OK;
return 1U;
}
/* Process SWD Configure command and prepare response */
static uint16_t dap_swdp_configure(struct dap_context *const ctx,
static uint16_t dap_swdp_configure(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -376,14 +357,14 @@ static uint16_t dap_swdp_configure(struct dap_context *const ctx,
return 1U;
}
(void)swdp_configure(ctx->swdp_dev, turnaround, data_phase);
(void)swdp_configure(ctx->dev, turnaround, data_phase);
response[0] = DAP_OK;
return 1U;
}
/* Process Transfer Configure command and prepare response */
static uint16_t dap_transfer_cfg(struct dap_context *const ctx,
static uint16_t dap_transfer_cfg(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -400,7 +381,7 @@ static uint16_t dap_transfer_cfg(struct dap_context *const ctx,
return 1U;
}
static inline uint8_t do_swdp_transfer(struct dap_context *const ctx,
static inline uint8_t do_swdp_transfer(struct dap_link_context *const ctx,
const uint8_t req_val,
uint32_t *data)
{
@@ -408,7 +389,7 @@ static inline uint8_t do_swdp_transfer(struct dap_context *const ctx,
uint8_t rspns_val;
do {
(void)swdp_transfer(ctx->swdp_dev,
(void)swdp_transfer(ctx->dev,
req_val,
data,
ctx->transfer.idle_cycles,
@@ -418,7 +399,7 @@ static inline uint8_t do_swdp_transfer(struct dap_context *const ctx,
return rspns_val;
}
static uint8_t swdp_transfer_match(struct dap_context *const ctx,
static uint8_t swdp_transfer_match(struct dap_link_context *const ctx,
const uint8_t req_val,
const uint32_t match_val)
{
@@ -463,7 +444,7 @@ static uint8_t swdp_transfer_match(struct dap_context *const ctx,
* one byte request (register)
* four byte data (for write request only)
*/
static uint16_t dap_swdp_transfer(struct dap_context *const ctx,
static uint16_t dap_swdp_transfer(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -605,7 +586,7 @@ end:
}
/* Delegate DAP Transfer command */
static uint16_t dap_transfer(struct dap_context *const ctx,
static uint16_t dap_transfer(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -631,7 +612,7 @@ static uint16_t dap_transfer(struct dap_context *const ctx,
return retval;
}
static uint16_t dap_swdp_sequence(struct dap_context *const ctx,
static uint16_t dap_swdp_sequence(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -665,10 +646,10 @@ static uint16_t dap_swdp_sequence(struct dap_context *const ctx,
request_data += 1;
if (input) {
(void)swdp_input_sequence(ctx->swdp_dev, num_cycles, response_data);
(void)swdp_input_sequence(ctx->dev, num_cycles, response_data);
response_data += num_bytes;
} else {
(void)swdp_output_sequence(ctx->swdp_dev, num_cycles, request_data);
(void)swdp_output_sequence(ctx->dev, num_cycles, request_data);
request_data += num_bytes;
}
}
@@ -684,7 +665,7 @@ static uint16_t dap_swdp_sequence(struct dap_context *const ctx,
* one byte block_request (register)
* data[transfer_count * sizeof(uint32_t)]
*/
static uint16_t dap_swdp_transferblock(struct dap_context *const ctx,
static uint16_t dap_swdp_transferblock(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -764,7 +745,7 @@ end:
}
/* Delegate Transfer Block command */
static uint16_t dap_transferblock(struct dap_context *const ctx,
static uint16_t dap_transferblock(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -797,7 +778,7 @@ static uint16_t dap_transferblock(struct dap_context *const ctx,
}
/* Process SWD Write ABORT command and prepare response */
static uint16_t dap_swdp_writeabort(struct dap_context *const ctx,
static uint16_t dap_swdp_writeabort(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -805,7 +786,7 @@ static uint16_t dap_swdp_writeabort(struct dap_context *const ctx,
uint32_t data = sys_get_le32(&request[1]);
/* Write Abort register */
(void)swdp_transfer(ctx->swdp_dev, DP_ABORT, &data,
(void)swdp_transfer(ctx->dev, DP_ABORT, &data,
ctx->transfer.idle_cycles, NULL);
response[0] = DAP_OK;
@@ -813,7 +794,7 @@ static uint16_t dap_swdp_writeabort(struct dap_context *const ctx,
}
/* Delegate DAP Write ABORT command */
static uint16_t dap_writeabort(struct dap_context *const ctx,
static uint16_t dap_writeabort(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -839,7 +820,7 @@ static uint16_t dap_writeabort(struct dap_context *const ctx,
}
/* Process DAP Vendor command request */
static uint16_t dap_process_vendor_cmd(struct dap_context *const ctx,
static uint16_t dap_process_vendor_cmd(struct dap_link_context *const ctx,
const uint8_t *const request,
uint8_t *const response)
{
@@ -856,7 +837,7 @@ static uint16_t dap_process_vendor_cmd(struct dap_context *const ctx,
* All the subsequent command functions have the same parameter
* and return value structure.
*/
static uint16_t dap_process_cmd(struct dap_context *const ctx,
static uint16_t dap_process_cmd(struct dap_link_context *const ctx,
const uint8_t *request,
uint8_t *response)
{
@@ -1002,8 +983,8 @@ static uint16_t dap_process_cmd(struct dap_context *const ctx,
* response: pointer to response data
* return: number of bytes in response
*/
uint32_t dap_execute_cmd(const uint8_t *request,
uint8_t *response)
uint32_t dap_link_execute_cmd(struct dap_link_context *const dap_link_ctx,
const uint8_t *request, uint8_t *response)
{
uint32_t retval;
uint16_t n;
@@ -1019,7 +1000,7 @@ uint32_t dap_execute_cmd(const uint8_t *request,
retval = sizeof(count) + 1U;
LOG_WRN("(untested) ID DAP EXECUTE_COMMANDS count %u", count);
while (count--) {
n = dap_process_cmd(&dap_ctx[0], request, response);
n = dap_process_cmd(dap_link_ctx, request, response);
retval += n;
request += n;
response += n;
@@ -1027,33 +1008,32 @@ uint32_t dap_execute_cmd(const uint8_t *request,
return retval;
}
return dap_process_cmd(&dap_ctx[0], request, response);
return dap_process_cmd(dap_link_ctx, request, response);
}
void dap_update_pkt_size(const uint16_t pkt_size)
void dap_link_set_pkt_size(struct dap_link_context *const dap_link_ctx,
const uint16_t pkt_size)
{
dap_ctx[0].pkt_size = pkt_size;
LOG_INF("New packet size %u", dap_ctx[0].pkt_size);
dap_link_ctx->pkt_size = pkt_size;
LOG_INF("New packet size %u", dap_link_ctx->pkt_size);
}
int dap_setup(const struct device *const dev)
int dap_link_init(struct dap_link_context *const dap_link_ctx)
{
dap_ctx[0].swdp_dev = (void *)dev;
if (!device_is_ready(dap_ctx[0].swdp_dev)) {
LOG_ERR("SWD driver not ready");
if (!device_is_ready(dap_link_ctx->dev)) {
LOG_ERR("SWD driver %s not ready", dap_link_ctx->dev->name);
return -ENODEV;
}
/* Default settings */
dap_ctx[0].pkt_size = CMSIS_DAP_PACKET_MIN_SIZE;
dap_ctx[0].debug_port = 0U;
dap_ctx[0].transfer.idle_cycles = 0U;
dap_ctx[0].transfer.retry_count = 100U;
dap_ctx[0].transfer.match_retry = 0U;
dap_ctx[0].transfer.match_mask = 0U;
dap_ctx[0].capabilities = DAP_SUPPORTS_ATOMIC_COMMANDS |
DAP_DP_SUPPORTS_SWD;
dap_link_ctx->pkt_size = CMSIS_DAP_PACKET_MIN_SIZE;
dap_link_ctx->debug_port = 0U;
dap_link_ctx->transfer.idle_cycles = 0U;
dap_link_ctx->transfer.retry_count = 100U;
dap_link_ctx->transfer.match_retry = 0U;
dap_link_ctx->transfer.match_mask = 0U;
dap_link_ctx->capabilities = DAP_SUPPORTS_ATOMIC_COMMANDS |
DAP_DP_SUPPORTS_SWD;
return 0;
}

View File

@@ -19,7 +19,8 @@
#ifndef ZEPHYR_INCLUDE_CMSIS_DAP_H_
#define ZEPHYR_INCLUDE_CMSIS_DAP_H_
#include <zephyr/kernel.h>
#include <stdint.h>
#include <zephyr/dap/dap_link.h>
/* Firmware Version */
#define DAP_FW_VER "2.1.0"
@@ -129,9 +130,7 @@
#define DAP_MBMSG_FROM_IFACE 0x1U
#define DAP_MBMSG_FROM_CONTROLLER 0x2U
/* Keep it internal until an other interface has been implemented. */
int dap_setup(const struct device *const dev);
uint32_t dap_execute_cmd(const uint8_t *request, uint8_t *response);
void dap_update_pkt_size(const uint16_t pkt_size);
uint32_t dap_link_execute_cmd(struct dap_link_context *const dap_link_ctx,
const uint8_t *request, uint8_t *response);
#endif /* ZEPHYR_INCLUDE_CMSIS_DAP_H_ */

View File

@@ -7,6 +7,7 @@
#include <zephyr/usb/usbd.h>
#include <zephyr/drivers/usb/udc.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/dap/dap_link.h>
#include "cmsis_dap.h"
@@ -41,6 +42,7 @@ struct dap_func_data {
const struct usb_desc_header **const hs_desc;
struct usbd_desc_node *const iface_str_desc_nd;
atomic_t state;
struct dap_link_context *dap_link_ctx;
};
static uint8_t dap_func_get_bulk_out(struct usbd_class_data *const c_data)
@@ -91,7 +93,8 @@ static int dap_func_request_handler(struct usbd_class_data *c_data,
} else {
bi->ep = dap_func_get_bulk_in(c_data);
len = dap_execute_cmd(buf->data, response_buf);
len = dap_link_execute_cmd(data->dap_link_ctx,
buf->data, response_buf);
net_buf_reset(buf);
LOG_DBG("response length %u, starting with [0x%02X, 0x%02X]",
len, response_buf[0], response_buf[1]);
@@ -159,9 +162,9 @@ static void dap_func_enable(struct usbd_class_data *const c_data)
if (!atomic_test_and_set_bit(&data->state, SAMPLE_FUNCTION_ENABLED)) {
if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
dap_update_pkt_size(512);
dap_link_set_pkt_size(data->dap_link_ctx, 512);
} else {
dap_update_pkt_size(64);
dap_link_set_pkt_size(data->dap_link_ctx, 64);
}
buf = dap_func_buf_alloc(c_data, dap_func_get_bulk_out(c_data));
@@ -191,6 +194,11 @@ static int dap_func_init(struct usbd_class_data *c_data)
struct dap_func_data *data = usbd_class_get_private(c_data);
struct dap_func_desc *desc = data->desc;
if (data->dap_link_ctx == NULL) {
LOG_ERR("No DAP Link context provided");
return -EIO;
}
LOG_DBG("Init class instance %p", (void *)c_data);
if (usbd_add_descriptor(uds_ctx, data->iface_str_desc_nd)) {
@@ -303,3 +311,17 @@ const static struct usb_desc_header *dap_func_hs_desc_##n[] = { \
LISTIFY(1, DAP_FUNC_DESCRIPTOR_DEFINE, ())
LISTIFY(1, DAP_FUNC_FUNCTION_DATA_DEFINE, ())
int dap_link_backend_usb_init(struct dap_link_context *const dap_link_ctx)
{
struct usbd_class_data *const c_data = &dap_func_0;
struct dap_func_data *data = usbd_class_get_private(c_data);
if (atomic_test_bit(&data->state, SAMPLE_FUNCTION_ENABLED)) {
return -EALREADY;
}
data->dap_link_ctx = dap_link_ctx;
return 0;
}