From 2caab84a7f7444d33aa9ddfe5e98fb69dcfb3207 Mon Sep 17 00:00:00 2001 From: Tomek CEDRO Date: Thu, 28 Jul 2011 14:51:44 +0200 Subject: TRANSPORT/SWD: Driver bridge between OpenOCD and LibSWD if now functional and verified. Transport select does not operate on interface anymore, just prepares memory and configures transport, because signals are not yet definet at this point and interface is not initialized. Transport init operates on interface and reads out IDCODE by default. --- src/transport/Makefile.am | 8 +-- src/transport/swd.c | 93 +++++++++++++++++----------------- src/transport/swd.h | 18 ++++++- src/transport/swd_libswd_drv_openocd.c | 65 +++++++++++++++++++++--- 4 files changed, 126 insertions(+), 58 deletions(-) diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 123687bd..b080ae85 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -1,13 +1,15 @@ include $(top_srcdir)/common.mk -#METASOURCES = AUTO +METASOURCES = AUTO noinst_LTLIBRARIES = libtransport.la libtransport_la_SOURCES = \ transport.c \ - swd.c + swd.c \ + swd_libswd_drv_openocd.c noinst_HEADERS = \ transport.h \ - swd.h + swd.h \ + swd_libswd_drv_openocd.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in diff --git a/src/transport/swd.c b/src/transport/swd.c index 16ee41a8..85014cad 100644 --- a/src/transport/swd.c +++ b/src/transport/swd.c @@ -3,7 +3,8 @@ * * SWD Transport Body File for OpenOCD. * - * Copyright (C) 2010-2011, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) + * Copyright (C) 2011 Tomasz Boleslaw CEDRO + * cederom@tlen.pl, http://www.tomek.cedro.info * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,20 +47,17 @@ #endif #include -#include #include //we want this here to use extern global *interface -#include +#include ///Unfortunalety OpenOCD use globals to pass information so we need to use it too. extern struct jtag_interface *jtag_interface; -extern const struct dap_ops swd_dp_ops; -static struct transport swd_transport; /** @{ swd_arm_adi_v5 Function set to support existing ARM ADI v5 target's * infrastructure. */ -int swd_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data){ +int oocd_swd_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data){ int retval; retval=swd_dp_read_idcode(dap->ctx, SWD_OPERATION_ENQUEUE, (int **)&data); if (retval<0) { @@ -68,7 +66,7 @@ int swd_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data){ } else return ERROR_OK; } -int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data){ +int oocd_swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data){ int retval; retval=swd_dp_read((swd_ctx_t *)dap->ctx, SWD_OPERATION_ENQUEUE, reg, (int **)&data); if (retval<0){ @@ -78,7 +76,7 @@ int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data){ return ERROR_OK; } -int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data){ +int oocd_swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data){ int retval; retval=swd_dp_write((swd_ctx_t *)dap->ctx, SWD_OPERATION_ENQUEUE, (char) reg, (int *) &data); if (retval<0){ @@ -88,7 +86,7 @@ int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data){ return ERROR_OK; } -int swd_queue_ap_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data){ +int oocd_swd_queue_ap_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data){ int retval; retval=swd_ap_read((swd_ctx_t *)dap->ctx, SWD_OPERATION_ENQUEUE, (char) reg, (int **) &data); if (retval<0){ @@ -98,7 +96,7 @@ int swd_queue_ap_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data){ return ERROR_OK; } -int swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg, uint32_t data){ +int oocd_swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg, uint32_t data){ int retval; retval=swd_ap_write((swd_ctx_t *)dap->ctx, SWD_OPERATION_ENQUEUE, (char) reg, (int *) &data); if (retval<0){ @@ -108,14 +106,14 @@ int swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg, uint32_t data){ return ERROR_OK; } -int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack){ +int oocd_swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack){ //int retval; //char reg=SWD_DP_ABORT_ADDR; LOG_ERROR("not yet implemented"); return ERROR_FAIL; } -int swd_run(struct adiv5_dap *dap){ +int oocd_swd_run(struct adiv5_dap *dap){ int retval; retval=swd_cmdq_flush((swd_ctx_t *)dap->ctx, SWD_OPERATION_EXECUTE); if (retval<0){ @@ -124,23 +122,11 @@ int swd_run(struct adiv5_dap *dap){ } else return ERROR_OK; } -const struct dap_ops swd_dap_ops = { - .is_swd = true, - - .queue_idcode_read = swd_queue_idcode_read, - .queue_dp_read = swd_queue_dp_read, - .queue_dp_write = swd_queue_dp_write, - .queue_ap_read = swd_queue_ap_read, - .queue_ap_write = swd_queue_ap_write, - .queue_ap_abort = swd_queue_ap_abort, - .run = swd_run, -}; - // Transport select prepares selected transport for later use and bus/target initialization. // TODO: We are operating on global interface pointer, change it into function parameter asap. -int swd_transport_init(struct command_context *ctx){ - LOG_DEBUG("%s",__func__); +int oocd_swd_transport_init(struct command_context *ctx){ + LOG_DEBUG("entering function..."); int retval, *idcode; //struct target *target = get_current_target(ctx); @@ -165,14 +151,16 @@ int swd_transport_init(struct command_context *ctx){ /** * Select SWD transport on interface pointed by global *jtag_interface structure. * Select is assumed to be called before transport init. It prepares everything, - * including interface buffers, context memory and command set for higher layers, - * but does not interrogate target device (with IDCODE read). + * including context memory and command set for higher layers, but not hardware + * and does not interrogate target device (with IDCODE read that is done by + * transport init call). This function does not touch the hardware because + * hardware use signals that are not yet read from config file at this point! */ -int swd_transport_select(struct command_context *ctx){ - LOG_DEBUG("%s",__func__); +int oocd_swd_transport_select(struct command_context *ctx){ + LOG_DEBUG("entering function..."); int retval; - jtag_interface->transport=&swd_transport; + jtag_interface->transport=(struct transport *)&oocd_transport_swd; //struct target *target = get_current_target(ctx); // retval = register_commands(ctx, NULL, swd_handlers); @@ -184,34 +172,47 @@ int swd_transport_select(struct command_context *ctx){ LOG_ERROR("Cannot initialize SWD context!"); return ERROR_FAIL; } - LOG_INFO("New SWD context initialized at 0x%08X", (int)&jtag_interface->transport->ctx); + LOG_INFO("New SWD context initialized at 0x%08X", (int)jtag_interface->transport->ctx); } else LOG_INFO("Working on existing transport context at 0x%0X...", (int)&jtag_interface->transport->ctx); - // Select SWD DAP by sending JTAG-TO-SWD sequence on the transport layer - retval=swd_dap_select((swd_ctx_t *)jtag_interface->transport->ctx, SWD_OPERATION_EXECUTE); - if (retval<0) { - LOG_ERROR("swd_dap_select() error: %s", swd_error_string(retval)); + retval=swd_log_level_inherit(jtag_interface->transport->ctx, debug_level); + if (retval<0){ + LOG_ERROR("Unable to set log level: %s", swd_error_string(retval)); return ERROR_FAIL; } - LOG_DEBUG("SWD Transport selection complete..."); return ERROR_OK; } - -static struct transport swd_transport = { +struct transport oocd_transport_swd = { .name = "swd", - .select = swd_transport_select, - .init = swd_transport_init, + .select = oocd_swd_transport_select, + .init = oocd_swd_transport_init, .ctx = NULL, - .next = NULL + .next = NULL, }; +const struct dap_ops oocd_dap_ops_swd = { + .is_swd = true, + + .queue_idcode_read = oocd_swd_queue_idcode_read, + .queue_dp_read = oocd_swd_queue_dp_read, + .queue_dp_write = oocd_swd_queue_dp_write, + .queue_ap_read = oocd_swd_queue_ap_read, + .queue_ap_write = oocd_swd_queue_ap_write, + .queue_ap_abort = oocd_swd_queue_ap_abort, + .run = oocd_swd_run, +}; + + + + +/** Register SWD Transport at program startup. */ static void swd_constructor(void) __attribute__((constructor)); static void swd_constructor(void) { - transport_register(&swd_transport); + transport_register((struct transport *)&oocd_transport_swd); } /** Returns true if the current debug session @@ -219,7 +220,7 @@ static void swd_constructor(void) */ bool transport_is_swd(void) { - return get_current_transport() == &swd_transport; + return get_current_transport() == &oocd_transport_swd; } /** Returns true if the current debug session @@ -227,7 +228,7 @@ bool transport_is_swd(void) * */ //bool transport_is_swd(void) //{ -// return get_current_transport() == &swd_transport; +// return get_current_transport() == &oocd_transport_swd; //} @@ -299,7 +300,7 @@ int dap_to_swd(struct target *target) retval = jtag_execute_queue(); /* set up the DAP's ops vector for SWD mode. */ - arm->dap->ops = &swd_dap_ops; + arm->dap->ops = &oocd_dap_ops_swd; return retval; } diff --git a/src/transport/swd.h b/src/transport/swd.h index 4d7edc2a..cd908169 100644 --- a/src/transport/swd.h +++ b/src/transport/swd.h @@ -3,7 +3,8 @@ * * SWD Transport Header File for OpenOCD. * - * Copyright (C) 2010-2011, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) + * Copyright (C) 2011 Tomasz Boleslaw CEDRO + * cederom@tle.pl, http://www.tomek.cedro.info * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,4 +37,19 @@ /** \file swd.h SWD Transport Header File for OpenOCD. */ #include +#include +#include + +int oocd_swd_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data); +int oocd_swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data); +int oocd_swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data); +int oocd_swd_queue_ap_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data); +int oocd_swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg, uint32_t data); +int oocd_swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack); +int oocd_swd_run(struct adiv5_dap *dap); +int oocd_swd_transport_init(struct command_context *ctx); +int oocd_swd_transport_select(struct command_context *ctx); + +extern struct transport oocd_transport_swd; +extern const struct dap_ops oocd_dap_ops_swd; diff --git a/src/transport/swd_libswd_drv_openocd.c b/src/transport/swd_libswd_drv_openocd.c index 19c8f9c8..c503a9a2 100644 --- a/src/transport/swd_libswd_drv_openocd.c +++ b/src/transport/swd_libswd_drv_openocd.c @@ -3,7 +3,8 @@ * * Driver Bridge between LibSWD and OpenOCD. * - * Copyright (C) 2010-2011, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) + * Copyright (C) 2010-2011 Tomasz Boleslaw CEDRO + * cederom@tlen.pl, http://www.tomek.cedro.info * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,6 +42,7 @@ #include #include #include +#include /** OpenOCD as for now use global pointer to driver structure. */ extern struct jtag_interface *jtag_interface; @@ -56,6 +58,7 @@ extern struct jtag_interface *jtag_interface; * \return data count transferred, or negative SWD_ERROR code on failure. */ int swd_drv_mosi_8(swd_ctx_t *swdctx, swd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ + LOG_DEBUG("OpenOCD's swd_drv_mosi_8(swdctx=@0x%08X, cmd=@0x%08X, data=0x%08X, bits=%d, nLSBfirst=0x%02X)", (int)swdctx, (int)cmd, *data, bits, nLSBfirst); if (data==NULL) return SWD_ERROR_NULLPOINTER; if (bits<0 && bits>8) return SWD_ERROR_PARAM; if (nLSBfirst!=0 && nLSBfirst!=1) return SWD_ERROR_PARAM; @@ -67,7 +70,7 @@ int swd_drv_mosi_8(swd_ctx_t *swdctx, swd_cmd_t *cmd, char *data, int bits, int /* Split output data into char array. */ for (i=0;i<8;i++) mosidata[(nLSBfirst==SWD_DIR_LSBFIRST)?(i):(7-i)]=((1<transfer(NULL, bits, mosidata, misodata); + res=jtag_interface->transfer(NULL, bits, mosidata, misodata, 0); if (res<0) return SWD_ERROR_DRIVER; return i; @@ -84,6 +87,7 @@ int swd_drv_mosi_8(swd_ctx_t *swdctx, swd_cmd_t *cmd, char *data, int bits, int * \return data count transferred, or negative SWD_ERROR code on failure. */ int swd_drv_mosi_32(swd_ctx_t *swdctx, swd_cmd_t *cmd, int *data, int bits, int nLSBfirst){ + LOG_DEBUG("OpenOCD's swd_drv_mosi_32(swdctx=@0x%08X, cmd=@0x%02X, data=0x%08X, bits=%d, nLSBfirst=0x%02X)", (int)swdctx, (int)cmd, *data, bits, nLSBfirst); if (data==NULL) return SWD_ERROR_NULLPOINTER; if (bits<0 && bits>8) return SWD_ERROR_PARAM; if (nLSBfirst!=0 && nLSBfirst!=1) return SWD_ERROR_PARAM; @@ -94,7 +98,7 @@ int swd_drv_mosi_32(swd_ctx_t *swdctx, swd_cmd_t *cmd, int *data, int bits, int //UrJTAG drivers shift data LSB-First. for (i=0;i<32;i++) mosidata[(nLSBfirst==SWD_DIR_LSBFIRST)?(i):(31-i)]=((1<transfer(NULL, bits, mosidata, misodata); + res=jtag_interface->transfer(NULL, bits, mosidata, misodata, 0); if (res<0) return SWD_ERROR_DRIVER; return i; } @@ -118,11 +122,13 @@ int swd_drv_miso_8(swd_ctx_t *swdctx, swd_cmd_t *cmd, char *data, int bits, int static signed int res; static char misodata[8], mosidata[8]; - res=jtag_interface->transfer(NULL, bits, mosidata, misodata); + // This function sends and reveice MSb-first. + res=jtag_interface->transfer(NULL, bits, mosidata, misodata, 0); if (res<0) return SWD_ERROR_DRIVER; /* Now we need to reconstruct the data byte from shifted in LSBfirst byte array. */ *data=0; for (i=0;itransfer(NULL, bits, mosidata, misodata); + res=jtag_interface->transfer(NULL, bits, mosidata, misodata, 0); if (res<0) return SWD_ERROR_DRIVER; /* Now we need to reconstruct the data byte from shifted in LSBfirst byte array. */ *data=0; for (i=0;iSWD_TURNROUND_MAX_VAL) return SWD_ERROR_TURNAROUND; @@ -173,7 +182,7 @@ int swd_drv_mosi_trn(swd_ctx_t *swdctx, int bits){ if (res<0) return SWD_ERROR_DRIVER; /* Clock specified number of bits for proper TRN transaction. */ - res=jtag_interface->transfer(NULL, bits, buf, buf); + res=jtag_interface->transfer(NULL, bits, buf, buf, 0); if (res<0) return SWD_ERROR_DRIVER; return bits; @@ -189,6 +198,7 @@ int swd_drv_mosi_trn(swd_ctx_t *swdctx, int bits){ * \return number of bits transmitted or negative SWD_ERROR code on failure. */ int swd_drv_miso_trn(swd_ctx_t *swdctx, int bits){ + LOG_DEBUG("OpenOCD's swd_drv_miso_trn(swdctx=@0x%08X, bits=%d)\n", (int)swdctx, bits); if (bitsSWD_TURNROUND_MAX_VAL) return SWD_ERROR_TURNAROUND; @@ -196,11 +206,11 @@ int swd_drv_miso_trn(swd_ctx_t *swdctx, int bits){ static char buf[SWD_TURNROUND_MAX_VAL]; /* Use driver method to set high (read) signal named RnW. */ - res=jtag_interface->bitbang(NULL, "RnW", 0, &val); + res=jtag_interface->bitbang(NULL, "RnW", 0xFFFFFFFF, &val); if (res<0) return SWD_ERROR_DRIVER; /* Clock specified number of bits for proper TRN transaction. */ - res=jtag_interface->transfer(NULL, bits, buf, buf); + res=jtag_interface->transfer(NULL, bits, buf, buf, 0); if (res<0) return SWD_ERROR_DRIVER; return bits; @@ -215,6 +225,7 @@ int swd_drv_miso_trn(swd_ctx_t *swdctx, int bits){ * \return SWD_OK on success, negative SWD_ERROR code on failure. */ int swd_log_level_inherit(swd_ctx_t *swdctx, int loglevel){ + LOG_DEBUG("OpenOCD's swd_log_level_inherit(swdctx=@0x%08X, loglevel=%d)\n", (int)swdctx, loglevel); if (swdctx==NULL){ LOG_WARNING("swd_log_level_inherit(): SWD Context not (yet) initialized...\n"); return SWD_OK; @@ -252,4 +263,42 @@ int swd_log_level_inherit(swd_ctx_t *swdctx, int loglevel){ } else return SWD_OK; } +/** We will use OpenOCD's logging mechanisms to show LibSWD messages. */ +int swd_log(swd_ctx_t *swdctx, swd_loglevel_t loglevel, char *msg, ...){ + if (swdctx==NULL) return SWD_ERROR_NULLCONTEXT; + if (loglevel > SWD_LOGLEVEL_MAX) return SWD_ERROR_PARAM; + + if (loglevel > swdctx->config.loglevel) return SWD_OK; + int res; + va_list ap; + va_start(ap, msg); + res=vprintf(msg, ap); + va_end(ap); + return res; + + + LOG_DEBUG("swdctx=0x%08X, loglevel=0x%02X, msg=%s\n", (int)swdctx, (int)loglevel, msg); + switch(loglevel){ + case SWD_LOGLEVEL_NORMAL: + LOG_USER(msg, ap); + break; + case SWD_LOGLEVEL_ERROR: + LOG_ERROR(msg, ap); + break; + case SWD_LOGLEVEL_WARNING: + LOG_WARNING(msg, ap); + break; + case SWD_LOGLEVEL_INFO: + printf(msg, ap); + break; + case SWD_LOGLEVEL_DEBUG: + LOG_DEBUG(msg, ap); + break; + default: + LOG_USER(msg, ap); + } + va_end(ap); + + return SWD_OK; +} -- cgit v1.2.3