summaryrefslogtreecommitdiff
path: root/src/transport/swd_libswd_drv_openocd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/swd_libswd_drv_openocd.c')
-rw-r--r--src/transport/swd_libswd_drv_openocd.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/src/transport/swd_libswd_drv_openocd.c b/src/transport/swd_libswd_drv_openocd.c
new file mode 100644
index 00000000..19c8f9c8
--- /dev/null
+++ b/src/transport/swd_libswd_drv_openocd.c
@@ -0,0 +1,255 @@
+/*
+ * $Id$
+ *
+ * Driver Bridge between LibSWD and OpenOCD.
+ *
+ * Copyright (C) 2010-2011, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.*
+ *
+ * Written by Tomasz Boleslaw CEDRO <cederom@tlen.pl>, 2010-2011;
+ *
+ */
+
+/** \file libswd_drv_openocd.c Driver Bridge between LibSWD and OpenOCD. */
+
+#include <libswd.h>
+#include <sys/types.h>
+#include <helper/system.h>
+#include <helper/log.h>
+#include <jtag/interface.h>
+#include <helper/log.h>
+
+/** OpenOCD as for now use global pointer to driver structure. */
+extern struct jtag_interface *jtag_interface;
+
+/**
+ * Use UrJTAG's driver to write 8-bit data (char type).
+ * MOSI (Master Output Slave Input) is a SWD Write Operation.
+ * \param *swdctx swd context to work on.
+ * \param *cmd point to the actual command being sent.
+ * \param *data points to the char data.
+ * \bits tells how many bits to send (at most 8).
+ * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
+ * \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){
+ 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;
+
+ static unsigned int i;
+ static signed int res;
+ static char misodata[8], mosidata[8];
+
+ /* Split output data into char array. */
+ for (i=0;i<8;i++) mosidata[(nLSBfirst==SWD_DIR_LSBFIRST)?(i):(7-i)]=((1<<i)&(*data))?1:0;
+ /* Then send that array into interface hardware. */
+ res=jtag_interface->transfer(NULL, bits, mosidata, misodata);
+ if (res<0) return SWD_ERROR_DRIVER;
+
+ return i;
+}
+
+/**
+ * Use UrJTAG's driver to write 32-bit data (int type).
+ * MOSI (Master Output Slave Input) is a SWD Write Operation.
+ * \param *swdctx swd context to work on.
+ * \param *cmd point to the actual command being sent.
+ * \param *data points to the char buffer array.
+ * \bits tells how many bits to send (at most 32).
+ * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
+ * \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){
+ 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;
+
+ static unsigned int i;
+ static signed int res;
+ static char misodata[32], mosidata[32];
+
+ //UrJTAG drivers shift data LSB-First.
+ for (i=0;i<32;i++) mosidata[(nLSBfirst==SWD_DIR_LSBFIRST)?(i):(31-i)]=((1<<i)&(*data))?1:0;
+ res=jtag_interface->transfer(NULL, bits, mosidata, misodata);
+ if (res<0) return SWD_ERROR_DRIVER;
+ return i;
+}
+
+/**
+ * Use UrJTAG's driver to read 8-bit data (char type).
+ * MISO (Master Input Slave Output) is a SWD Read Operation.
+ * \param *swdctx swd context to work on.
+ * \param *cmd point to the actual command being sent.
+ * \param *data points to the char buffer array.
+ * \bits tells how many bits to send (at most 8).
+ * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
+ * \return data count transferred, or negative SWD_ERROR code on failure.
+ */
+int swd_drv_miso_8(swd_ctx_t *swdctx, swd_cmd_t *cmd, char *data, int bits, int 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;
+
+ static int i;
+ static signed int res;
+ static char misodata[8], mosidata[8];
+
+ res=jtag_interface->transfer(NULL, bits, mosidata, misodata);
+ 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;i<bits;i++) *data|=(misodata[(nLSBfirst==SWD_DIR_LSBFIRST)?(bits-1-i):(i)]?(1<<i):0);
+ return i;
+}
+
+/**
+ * Use UrJTAG's driver to read 32-bit data (int type).
+ * MISO (Master Input Slave Output) is a SWD Read Operation.
+ * \param *swdctx swd context to work on.
+ * \param *cmd point to the actual command being sent.
+ * \param *data points to the char buffer array.
+ * \bits tells how many bits to send (at most 32).
+ * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
+ * \return data count transferred, or negative SWD_ERROR code on failure.
+ */
+int swd_drv_miso_32(swd_ctx_t *swdctx, swd_cmd_t *cmd, int *data, int bits, int 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;
+
+ static int i;
+ static signed int res;
+ static char misodata[32], mosidata[32];
+
+ res=jtag_interface->transfer(NULL, bits, mosidata, misodata);
+ 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;i<bits;i++) *data|=(misodata[(nLSBfirst==SWD_DIR_LSBFIRST)?(bits-1-i):(i)]?(1<<i):0);
+ return i;
+}
+
+/**
+ * This function sets interface buffers to MOSI direction.
+ * MOSI (Master Output Slave Input) is a SWD Write operation.
+ * OpenOCD use global "struct jtag_interface" pointer as interface driver.
+ * OpenOCD driver must support "RnW" signal to drive output buffers for TRN.
+ * \param *swdctx is the swd context to work on.
+ * \param bits specify how many clock cycles must be used for TRN.
+ * \return number of bits transmitted or negative SWD_ERROR code on failure.
+ */
+int swd_drv_mosi_trn(swd_ctx_t *swdctx, int bits){
+ if (bits<SWD_TURNROUND_MIN_VAL && bits>SWD_TURNROUND_MAX_VAL)
+ return SWD_ERROR_TURNAROUND;
+
+ int res, val=0;
+ static char buf[SWD_TURNROUND_MAX_VAL];
+ /* Use driver method to set low (write) signal named RnW. */
+ res=jtag_interface->bitbang(NULL, "RnW", 0, &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);
+ if (res<0) return SWD_ERROR_DRIVER;
+
+ return bits;
+}
+
+/**
+ * This function sets interface buffers to MISO direction.
+ * MISO (Master Input Slave Output) is a SWD Read operation.
+ * OpenOCD use global "struct jtag_interface" pointer as interface driver.
+ * OpenOCD driver must support "RnW" signal to drive output buffers for TRN.
+ * \param *swdctx is the swd context to work on.
+ * \param bits specify how many clock cycles must be used for TRN.
+ * \return number of bits transmitted or negative SWD_ERROR code on failure.
+ */
+int swd_drv_miso_trn(swd_ctx_t *swdctx, int bits){
+ if (bits<SWD_TURNROUND_MIN_VAL && bits>SWD_TURNROUND_MAX_VAL)
+ return SWD_ERROR_TURNAROUND;
+
+ static int res, val=1;
+ 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);
+ if (res<0) return SWD_ERROR_DRIVER;
+
+ /* Clock specified number of bits for proper TRN transaction. */
+ res=jtag_interface->transfer(NULL, bits, buf, buf);
+ if (res<0) return SWD_ERROR_DRIVER;
+
+ return bits;
+}
+
+
+/**
+ * Set SWD debug level according to OpenOCD settings.
+ * \param *swdctx is the context to work on.
+ * \param loglevel is the OpenOCD numerical value of actual loglevel to force
+ * on LibSWD, or -1 to inherit from actual global settings of OpenOCD.
+ * \return SWD_OK on success, negative SWD_ERROR code on failure.
+ */
+int swd_log_level_inherit(swd_ctx_t *swdctx, int loglevel){
+ if (swdctx==NULL){
+ LOG_WARNING("swd_log_level_inherit(): SWD Context not (yet) initialized...\n");
+ return SWD_OK;
+ }
+
+ swd_loglevel_t new_swdlevel;
+ switch ((loglevel==-1)?debug_level:loglevel){
+ case LOG_LVL_DEBUG:
+ new_swdlevel=SWD_LOGLEVEL_DEBUG;
+ break;
+ case LOG_LVL_INFO:
+ new_swdlevel=SWD_LOGLEVEL_INFO;
+ break;
+ case LOG_LVL_WARNING:
+ new_swdlevel=SWD_LOGLEVEL_WARNING;
+ break;
+ case LOG_LVL_ERROR:
+ new_swdlevel=SWD_LOGLEVEL_ERROR;
+ break;
+ case LOG_LVL_USER:
+ case LOG_LVL_OUTPUT:
+ new_swdlevel=SWD_LOGLEVEL_NORMAL;
+ break;
+ case LOG_LVL_SILENT:
+ new_swdlevel=SWD_LOGLEVEL_SILENT;
+ break;
+ default:
+ new_swdlevel=SWD_LOGLEVEL_NORMAL;
+ }
+
+ int res=swd_log_level_set(swdctx, new_swdlevel);
+ if (res<0) {
+ LOG_ERROR("swd_log_level_set() failed (%s)\n", swd_error_string(res));
+ return ERROR_FAIL;
+ } else return SWD_OK;
+}
+
+