CMSIS-DAP support.
Thanks to edbg, pyocd and openocd for code and ideas.
This commit is contained in:
parent
4ba6afed28
commit
ef558eebb8
|
@ -10,7 +10,7 @@ before_install:
|
|||
- wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2.sig
|
||||
- gpg --trust-model always --verify libftdi1-1.2.tar.bz2.sig
|
||||
- tar -xjf libftdi1-1.2.tar.bz2
|
||||
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev
|
||||
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev
|
||||
|
||||
install:
|
||||
- cd libftdi1-1.2
|
||||
|
|
|
@ -9,14 +9,14 @@ LDFLAGS += -lasan
|
|||
else ifneq (, $(findstring mingw, $(SYS)))
|
||||
SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
LDFLAGS += -lhid -lsetupapi
|
||||
LDFLAGS += -lsetupapi
|
||||
else ifneq (, $(findstring cygwin, $(SYS)))
|
||||
SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
LDFLAGS += -lhid -lsetupapi
|
||||
LDFLAGS += -lsetupapi
|
||||
#https://github.com/dmlc/xgboost/issues/1945 indicates macosx as indicator
|
||||
else ifneq (filter, macosx darwin, $(SYS)))
|
||||
LDFLAGS += -lhid -lsetupapi
|
||||
LDFLAGS += -lsetupapi
|
||||
LDFLAGS += hidapi/mac/.libs/libhidapi.a -framework IOKit
|
||||
LDFLAGS += -framework CoreFoundation hidapi/mac/.libs/libhidapi.a
|
||||
CFLAGS += -Ihidapi/hidapi
|
||||
|
@ -26,6 +26,13 @@ LDFLAGS += -lusb-1.0
|
|||
CFLAGS += $(shell pkg-config --cflags libftdi1)
|
||||
LDFLAGS += $(shell pkg-config --libs libftdi1)
|
||||
|
||||
ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
|
||||
CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
|
||||
LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
|
||||
CFLAGS += -DCMSIS_DAP
|
||||
SRC += cmsis_dap.c dap.c
|
||||
endif
|
||||
|
||||
VPATH += platforms/pc
|
||||
SRC += timing.c cl_utils.c utils.c libusb_utils.c
|
||||
SRC += stlinkv2.c
|
||||
|
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019-20 Uwe Bonnes
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* Modified from edbg.c
|
||||
* Links between bmp and edbg
|
||||
*
|
||||
* https://arm-software.github.io/CMSIS_5/DAP/html/index.html
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "adiv5.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <hidapi.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "dap.h"
|
||||
#include "cmsis_dap.h"
|
||||
|
||||
#include "cl_utils.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
|
||||
#define MAX_DEBUGGERS 20
|
||||
|
||||
uint8_t dap_caps;
|
||||
uint8_t mode;
|
||||
|
||||
/*- Variables ---------------------------------------------------------------*/
|
||||
static hid_device *handle = NULL;
|
||||
static uint8_t hid_buffer[1024 + 1];
|
||||
static int report_size = 512 + 1; // TODO: read actual report size
|
||||
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
||||
int dap_init(bmp_info_t *info)
|
||||
{
|
||||
if (hid_init())
|
||||
return -1;
|
||||
int size = strlen(info->serial);
|
||||
wchar_t serial[size + 1], *wc = serial;
|
||||
for (int i = 0; i < size; i++)
|
||||
*wc++ = info->serial[i];
|
||||
*wc = 0;
|
||||
/* Blacklist devices that do not wirk with 513 byte report length
|
||||
* FIXME: Find a solution to decipher from the device.
|
||||
*/
|
||||
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
|
||||
printf("Blacklist\n");
|
||||
report_size = 64 + 1;
|
||||
}
|
||||
handle = hid_open(info->vid, info->pid, serial);
|
||||
if (!handle)
|
||||
return -1;
|
||||
dap_disconnect();
|
||||
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
||||
dap_caps = hid_buffer[0];
|
||||
printf(" Cap (0x%2x): %s%s%s", hid_buffer[0],
|
||||
(hid_buffer[0] & 1)? "SWD" : "",
|
||||
((hid_buffer[0] & 3) == 3) ? "/" : "",
|
||||
(hid_buffer[0] & 2)? "JTAG" : "");
|
||||
if (hid_buffer[0] & 4)
|
||||
printf(", SWO_UART");
|
||||
if (hid_buffer[0] & 8)
|
||||
printf(", SWO_MANCHESTER");
|
||||
if (hid_buffer[0] & 0x10)
|
||||
printf(", Atomic Cmds");
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||
{
|
||||
/* DP Write to Reg 0.*/
|
||||
dap_write_reg(dp, ADIV5_DP_ABORT, abort);
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_error(ADIv5_DP_t *dp)
|
||||
{
|
||||
uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT);
|
||||
uint32_t err = ctrlstat &
|
||||
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
||||
ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR);
|
||||
uint32_t clr = 0;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYORUN)
|
||||
clr |= ADIV5_DP_ABORT_ORUNERRCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYCMP)
|
||||
clr |= ADIV5_DP_ABORT_STKCMPCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYERR)
|
||||
clr |= ADIV5_DP_ABORT_STKERRCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_WDATAERR)
|
||||
clr |= ADIV5_DP_ABORT_WDERRCLR;
|
||||
dap_write_reg(dp, ADIV5_DP_ABORT, clr);
|
||||
dp->fault = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
bool APnDP = addr & ADIV5_APnDP;
|
||||
uint32_t res = 0;
|
||||
uint8_t reg = (addr & 0xc) | ((APnDP)? 1 : 0);
|
||||
if (RnW) {
|
||||
res = dap_read_reg(dp, reg);
|
||||
}
|
||||
else {
|
||||
dap_write_reg(dp, reg, value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
return dap_read_reg(dp, addr);
|
||||
}
|
||||
|
||||
void dap_exit_function(void)
|
||||
{
|
||||
if (handle) {
|
||||
dap_disconnect();
|
||||
hid_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
int dbg_get_report_size(void)
|
||||
{
|
||||
return report_size;
|
||||
}
|
||||
|
||||
int dbg_dap_cmd(uint8_t *data, int size, int rsize)
|
||||
|
||||
{
|
||||
char cmd = data[0];
|
||||
int res;
|
||||
|
||||
memset(hid_buffer, 0xff, report_size + 1);
|
||||
|
||||
hid_buffer[0] = 0x00; // Report ID??
|
||||
memcpy(&hid_buffer[1], data, rsize);
|
||||
|
||||
if (cl_debuglevel & BMP_DEBUG_WIRE) {
|
||||
printf("cmd : ");
|
||||
for(int i = 0; (i < 16) && (i < rsize + 1); i++)
|
||||
printf("%02x.", hid_buffer[i]);
|
||||
printf("\n");
|
||||
}
|
||||
res = hid_write(handle, hid_buffer, rsize + 1);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error: %ls\n", hid_error(handle));
|
||||
exit(-1);
|
||||
}
|
||||
if (size) {
|
||||
res = hid_read(handle, hid_buffer, report_size + 1);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "debugger read(): %ls\n", hid_error(handle));
|
||||
exit(-1);
|
||||
}
|
||||
if (size && hid_buffer[0] != cmd) {
|
||||
printf("cmd %02x invalid response received %02x\n",
|
||||
cmd, hid_buffer[0]);
|
||||
}
|
||||
res--;
|
||||
memcpy(data, &hid_buffer[1], (size < res) ? size : res);
|
||||
if (cl_debuglevel & BMP_DEBUG_WIRE) {
|
||||
printf("cmd res:");
|
||||
for(int i = 0; (i < 16) && (i < size + 4); i++)
|
||||
printf("%02x.", hid_buffer[i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
||||
(((x) & 1) == 0 ? ALIGN_HALFWORD : ALIGN_BYTE))
|
||||
|
||||
static void dap_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return;
|
||||
enum align align = MIN(ALIGNOF(src), ALIGNOF(len));
|
||||
#if 0
|
||||
printf("memread @ %" PRIx32 " len %ld, align %d , start: \n",
|
||||
src, len, align);
|
||||
#endif
|
||||
if (((unsigned)(1 << align)) == len)
|
||||
return dap_read_single(ap, dest, src, align);
|
||||
/* One word transfer for every byte/halfword/word
|
||||
* Total number of bytes in transfer*/
|
||||
unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
|
||||
while (len) {
|
||||
dap_ap_mem_access_setup(ap, src, align);
|
||||
/* Calculate length until next access setup is needed */
|
||||
unsigned int blocksize = (src | 0x3ff) - src + 1;
|
||||
if (blocksize > len)
|
||||
blocksize = len;
|
||||
while (blocksize) {
|
||||
unsigned int transfersize = blocksize;
|
||||
if (transfersize > max_size)
|
||||
transfersize = max_size;
|
||||
unsigned int res = dap_read_block(ap, dest, src, transfersize,
|
||||
align);
|
||||
if (res) {
|
||||
// printf("mem_read failed %02x\n", res);
|
||||
ap->dp->fault = 1;
|
||||
return;
|
||||
}
|
||||
blocksize -= transfersize;
|
||||
len -= transfersize;
|
||||
dest += transfersize;
|
||||
src += transfersize;
|
||||
}
|
||||
}
|
||||
// printf("memread res last data %08" PRIx32 "\n", ((uint32_t*)dest)[-1]);
|
||||
}
|
||||
|
||||
static void dap_mem_write_sized(
|
||||
ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
if (len == 0)
|
||||
return;
|
||||
#if 0
|
||||
printf("memwrite @ %" PRIx32 " len %ld, align %d , %08x start: \n",
|
||||
dest, len, align, *(uint32_t *)src);
|
||||
#endif
|
||||
if (((unsigned)(1 << align)) == len)
|
||||
return dap_write_single(ap, dest, src, align);
|
||||
unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
|
||||
while (len) {
|
||||
dap_ap_mem_access_setup(ap, dest, align);
|
||||
unsigned int blocksize = (dest | 0x3ff) - dest + 1;
|
||||
if (blocksize > len)
|
||||
blocksize = len;
|
||||
while (blocksize) {
|
||||
unsigned int transfersize = blocksize;
|
||||
if (transfersize > max_size)
|
||||
transfersize = max_size;
|
||||
unsigned int res = dap_write_block(ap, dest, src, transfersize,
|
||||
align);
|
||||
if (res) {
|
||||
printf("mem_write failed %02x\n", res);
|
||||
ap->dp->fault = 1;
|
||||
return;
|
||||
}
|
||||
blocksize -= transfersize;
|
||||
len -= transfersize;
|
||||
dest += transfersize;
|
||||
src += transfersize;
|
||||
}
|
||||
}
|
||||
// printf("memwrite done\n");
|
||||
}
|
||||
|
||||
int dap_enter_debug_swd(ADIv5_DP_t *dp)
|
||||
{
|
||||
target_list_free();
|
||||
if (!(dap_caps & DAP_CAP_SWD))
|
||||
return -1;
|
||||
mode = DAP_CAP_SWD;
|
||||
dap_swj_clock(2000000);
|
||||
dap_transfer_configure(2, 128, 128);
|
||||
dap_swd_configure(0);
|
||||
dap_connect(false);
|
||||
dap_led(0, 1);
|
||||
dap_reset_link(false);
|
||||
|
||||
dp->idcode = dap_read_idcode(dp);
|
||||
dp->dp_read = dap_dp_read_reg;
|
||||
dp->error = dap_dp_error;
|
||||
dp->low_access = dap_dp_low_access;
|
||||
dp->abort = dap_dp_abort; /* DP Write to Reg 0.*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||
{
|
||||
if ((mode == DAP_CAP_JTAG) && dap_jtag_configure())
|
||||
return;
|
||||
dp->ap_read = dap_ap_read;
|
||||
dp->ap_write = dap_ap_write;
|
||||
dp->mem_read = dap_mem_read;
|
||||
dp->mem_write_sized = dap_mem_write_sized;
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_reset(void)
|
||||
{
|
||||
jtagtap_soft_reset();
|
||||
/* Is there a way to know if TRST is available?*/
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t TMS[4] = {MS & 0xff, (MS >> 8) & 0xff, (MS >> 16) & 0xff,
|
||||
(MS >> 24) & 0xff};
|
||||
dap_jtagtap_tdi_tdo_seq(NULL, false, TMS, NULL, ticks);
|
||||
if (cl_debuglevel & BMP_DEBUG_PLATFORM)
|
||||
printf("tms_seq DI %08x %d\n", MS, ticks);
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks);
|
||||
if (cl_debuglevel & BMP_DEBUG_PLATFORM)
|
||||
printf("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], DO[0]);
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
dap_jtagtap_tdi_tdo_seq(NULL, (final_tms), NULL, DI, ticks);
|
||||
if (cl_debuglevel & BMP_DEBUG_PLATFORM)
|
||||
printf("jtagtap_tdi_seq %d, %02x\n", ticks, DI[0]);
|
||||
}
|
||||
|
||||
static uint8_t cmsis_dap_jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
uint8_t tdo[1];
|
||||
dap_jtagtap_tdi_tdo_seq(tdo, false, &dTMS, &dTDI, 1);
|
||||
if (cl_debuglevel & BMP_DEBUG_PLATFORM)
|
||||
printf("next tms %02x tdi %02x tdo %02x\n", dTMS, dTDI, tdo[0]);
|
||||
return (tdo[0] & 1);
|
||||
}
|
||||
|
||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
if (cl_debuglevel)
|
||||
printf("jtap_init\n");
|
||||
if (!(dap_caps & DAP_CAP_JTAG))
|
||||
return -1;
|
||||
mode = DAP_CAP_JTAG;
|
||||
dap_disconnect();
|
||||
dap_connect(true);
|
||||
dap_swj_clock(2000000);
|
||||
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
|
||||
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
|
||||
jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
|
||||
dap_reset_link(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
||||
{
|
||||
dp->dp_read = dap_dp_read_reg;
|
||||
dp->error = dap_dp_error;
|
||||
dp->low_access = dap_dp_low_access;
|
||||
dp->abort = dap_dp_abort;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__CMSIS_DAP_H_)
|
||||
#define __CMSIS_DAP_H_
|
||||
|
||||
#include "adiv5.h"
|
||||
#include "cl_utils.h"
|
||||
|
||||
#if defined(CMSIS_DAP)
|
||||
int dap_init(bmp_info_t *info);
|
||||
int dap_enter_debug_swd(ADIv5_DP_t *dp);
|
||||
void dap_exit_function(void);
|
||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||
int dap_jtag_dp_init(ADIv5_DP_t *dp);
|
||||
#else
|
||||
int dap_init(bmp_info_t *info) {(void)info; return -1;}
|
||||
int dap_enter_debug_swd(ADIv5_DP_t *dp) {(void)dp; return -1;}
|
||||
void dap_exit_function(void) {return;};
|
||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {(void)dp; return; }
|
||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
(void)jtag_proc;
|
||||
return -1;
|
||||
}
|
||||
int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
||||
{
|
||||
(void)dp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015, Alex Taradov <alex@taradov.com>
|
||||
* 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. The name of the author may not 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.
|
||||
*/
|
||||
|
||||
/* Modified for Blackmagic Probe
|
||||
* Copyright (c) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
||||
*/
|
||||
|
||||
/*- Includes ----------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "dap.h"
|
||||
#include "jtag_scan.h"
|
||||
|
||||
/*- Definitions -------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
ID_DAP_INFO = 0x00,
|
||||
ID_DAP_LED = 0x01,
|
||||
ID_DAP_CONNECT = 0x02,
|
||||
ID_DAP_DISCONNECT = 0x03,
|
||||
ID_DAP_TRANSFER_CONFIGURE = 0x04,
|
||||
ID_DAP_TRANSFER = 0x05,
|
||||
ID_DAP_TRANSFER_BLOCK = 0x06,
|
||||
ID_DAP_TRANSFER_ABORT = 0x07,
|
||||
ID_DAP_WRITE_ABORT = 0x08,
|
||||
ID_DAP_DELAY = 0x09,
|
||||
ID_DAP_RESET_TARGET = 0x0a,
|
||||
ID_DAP_SWJ_PINS = 0x10,
|
||||
ID_DAP_SWJ_CLOCK = 0x11,
|
||||
ID_DAP_SWJ_SEQUENCE = 0x12,
|
||||
ID_DAP_SWD_CONFIGURE = 0x13,
|
||||
ID_DAP_JTAG_SEQUENCE = 0x14,
|
||||
ID_DAP_JTAG_CONFIGURE = 0x15,
|
||||
ID_DAP_JTAG_IDCODE = 0x16,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_TRANSFER_APnDP = 1 << 0,
|
||||
DAP_TRANSFER_RnW = 1 << 1,
|
||||
DAP_TRANSFER_A2 = 1 << 2,
|
||||
DAP_TRANSFER_A3 = 1 << 3,
|
||||
DAP_TRANSFER_MATCH_VALUE = 1 << 4,
|
||||
DAP_TRANSFER_MATCH_MASK = 1 << 5,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_TRANSFER_INVALID = 0,
|
||||
DAP_TRANSFER_OK = 1 << 0,
|
||||
DAP_TRANSFER_WAIT = 1 << 1,
|
||||
DAP_TRANSFER_FAULT = 1 << 2,
|
||||
DAP_TRANSFER_ERROR = 1 << 3,
|
||||
DAP_TRANSFER_MISMATCH = 1 << 4,
|
||||
DAP_TRANSFER_NO_TARGET = 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_SWJ_SWCLK_TCK = 1 << 0,
|
||||
DAP_SWJ_SWDIO_TMS = 1 << 1,
|
||||
DAP_SWJ_TDI = 1 << 2,
|
||||
DAP_SWJ_TDO = 1 << 3,
|
||||
DAP_SWJ_nTRST = 1 << 5,
|
||||
DAP_SWJ_nRESET = 1 << 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_OK = 0x00,
|
||||
DAP_ERROR = 0xff,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_JTAG_TMS = 1 << 6,
|
||||
DAP_JTAG_TDO_CAPTURE = 1 << 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SWD_DP_R_IDCODE = 0x00,
|
||||
SWD_DP_W_ABORT = 0x00,
|
||||
SWD_DP_R_CTRL_STAT = 0x04,
|
||||
SWD_DP_W_CTRL_STAT = 0x04, // When CTRLSEL == 0
|
||||
SWD_DP_W_WCR = 0x04, // When CTRLSEL == 1
|
||||
SWD_DP_R_RESEND = 0x08,
|
||||
SWD_DP_W_SELECT = 0x08,
|
||||
SWD_DP_R_RDBUFF = 0x0c,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SWD_AP_CSW = 0x00 | DAP_TRANSFER_APnDP,
|
||||
SWD_AP_TAR = 0x04 | DAP_TRANSFER_APnDP,
|
||||
SWD_AP_DRW = 0x0c | DAP_TRANSFER_APnDP,
|
||||
|
||||
SWD_AP_DB0 = 0x00 | DAP_TRANSFER_APnDP, // 0x10
|
||||
SWD_AP_DB1 = 0x04 | DAP_TRANSFER_APnDP, // 0x14
|
||||
SWD_AP_DB2 = 0x08 | DAP_TRANSFER_APnDP, // 0x18
|
||||
SWD_AP_DB3 = 0x0c | DAP_TRANSFER_APnDP, // 0x1c
|
||||
|
||||
SWD_AP_CFG = 0x04 | DAP_TRANSFER_APnDP, // 0xf4
|
||||
SWD_AP_BASE = 0x08 | DAP_TRANSFER_APnDP, // 0xf8
|
||||
SWD_AP_IDR = 0x0c | DAP_TRANSFER_APnDP, // 0xfc
|
||||
};
|
||||
|
||||
#define DP_ABORT_DAPABORT (1 << 0)
|
||||
#define DP_ABORT_STKCMPCLR (1 << 1)
|
||||
#define DP_ABORT_STKERRCLR (1 << 2)
|
||||
#define DP_ABORT_WDERRCLR (1 << 3)
|
||||
#define DP_ABORT_ORUNERRCLR (1 << 4)
|
||||
|
||||
#define DP_CST_ORUNDETECT (1 << 0)
|
||||
#define DP_CST_STICKYORUN (1 << 1)
|
||||
#define DP_CST_TRNMODE_NORMAL (0 << 2)
|
||||
#define DP_CST_TRNMODE_VERIFY (1 << 2)
|
||||
#define DP_CST_TRNMODE_COMPARE (2 << 2)
|
||||
#define DP_CST_STICKYCMP (1 << 4)
|
||||
#define DP_CST_STICKYERR (1 << 5)
|
||||
#define DP_CST_READOK (1 << 6)
|
||||
#define DP_CST_WDATAERR (1 << 7)
|
||||
#define DP_CST_MASKLANE(x) ((x) << 8)
|
||||
#define DP_CST_TRNCNT(x) ((x) << 12)
|
||||
#define DP_CST_CDBGRSTREQ (1 << 26)
|
||||
#define DP_CST_CDBGRSTACK (1 << 27)
|
||||
#define DP_CST_CDBGPWRUPREQ (1 << 28)
|
||||
#define DP_CST_CDBGPWRUPACK (1 << 29)
|
||||
#define DP_CST_CSYSPWRUPREQ (1 << 30)
|
||||
#define DP_CST_CSYSPWRUPACK (1 << 31)
|
||||
|
||||
#define DP_SELECT_CTRLSEL (1 << 0)
|
||||
#define DP_SELECT_APBANKSEL(x) ((x) << 4)
|
||||
#define DP_SELECT_APSEL(x) ((x) << 24)
|
||||
|
||||
#define AP_CSW_SIZE_BYTE (0 << 0)
|
||||
#define AP_CSW_SIZE_HALF (1 << 0)
|
||||
#define AP_CSW_SIZE_WORD (2 << 0)
|
||||
#define AP_CSW_ADDRINC_OFF (0 << 4)
|
||||
#define AP_CSW_ADDRINC_SINGLE (1 << 4)
|
||||
#define AP_CSW_ADDRINC_PACKED (2 << 4)
|
||||
#define AP_CSW_DEVICEEN (1 << 6)
|
||||
#define AP_CSW_TRINPROG (1 << 7)
|
||||
#define AP_CSW_SPIDEN (1 << 23)
|
||||
#define AP_CSW_PROT(x) ((x) << 24)
|
||||
#define AP_CSW_DBGSWENABLE (1 << 31)
|
||||
|
||||
/*- Implementations ---------------------------------------------------------*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_led(int index, int state)
|
||||
{
|
||||
uint8_t buf[3];
|
||||
|
||||
buf[0] = ID_DAP_LED;
|
||||
buf[1] = index;
|
||||
buf[2] = state;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 3);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_connect(bool jtag)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = ID_DAP_CONNECT;
|
||||
buf[1] = (jtag) ? DAP_CAP_JTAG : DAP_CAP_SWD;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 2);
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_disconnect(void)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
|
||||
buf[0] = ID_DAP_DISCONNECT;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_swj_clock(uint32_t clock)
|
||||
{
|
||||
uint8_t buf[5];
|
||||
|
||||
buf[0] = ID_DAP_SWJ_CLOCK;
|
||||
buf[1] = clock & 0xff;
|
||||
buf[2] = (clock >> 8) & 0xff;
|
||||
buf[3] = (clock >> 16) & 0xff;
|
||||
buf[4] = (clock >> 24) & 0xff;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 5);
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry)
|
||||
{
|
||||
uint8_t buf[6];
|
||||
|
||||
buf[0] = ID_DAP_TRANSFER_CONFIGURE;
|
||||
buf[1] = idle;
|
||||
buf[2] = count & 0xff;
|
||||
buf[3] = (count >> 8) & 0xff;
|
||||
buf[4] = retry & 0xff;
|
||||
buf[5] = (retry >> 8) & 0xff;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 6);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_swd_configure(uint8_t cfg)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = ID_DAP_SWD_CONFIGURE;
|
||||
buf[1] = cfg;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int dap_info(int info, uint8_t *data, int size)
|
||||
{
|
||||
uint8_t buf[256];
|
||||
int rsize;
|
||||
|
||||
buf[0] = ID_DAP_INFO;
|
||||
buf[1] = info;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 2);
|
||||
|
||||
rsize = (size < buf[0]) ? size : buf[0];
|
||||
memcpy(data, &buf[1], rsize);
|
||||
|
||||
if (rsize < size)
|
||||
data[rsize] = 0;
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
void dap_reset_pin(int state)
|
||||
{
|
||||
uint8_t buf[7];
|
||||
|
||||
buf[0] = ID_DAP_SWJ_PINS;
|
||||
buf[1] = state ? DAP_SWJ_nRESET : 0; // Value
|
||||
buf[2] = DAP_SWJ_nRESET; // Select
|
||||
buf[3] = 0; // Wait
|
||||
buf[4] = 0;
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||
}
|
||||
|
||||
void dap_trst_reset(void)
|
||||
{
|
||||
uint8_t buf[7];
|
||||
|
||||
buf[0] = ID_DAP_SWJ_PINS;
|
||||
buf[1] = DAP_SWJ_nTRST;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = 4; /* ~ 1 ms*/
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||
|
||||
buf[0] = ID_DAP_SWJ_PINS;
|
||||
buf[1] = DAP_SWJ_nTRST;
|
||||
buf[2] = DAP_SWJ_nTRST;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||
}
|
||||
|
||||
static void dap_line_reset(void)
|
||||
{
|
||||
uint8_t buf[] = {
|
||||
ID_DAP_SWJ_SEQUENCE,
|
||||
64,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0
|
||||
};
|
||||
dbg_dap_cmd(buf, sizeof(buf), 10);
|
||||
if (buf[0])
|
||||
printf("line reset failed\n");
|
||||
}
|
||||
|
||||
static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault)
|
||||
{
|
||||
do {
|
||||
dbg_dap_cmd(buf, size, len);
|
||||
if (buf[1] < DAP_TRANSFER_WAIT)
|
||||
break;
|
||||
} while (buf[1] == DAP_TRANSFER_WAIT);
|
||||
|
||||
if (buf[1] > DAP_TRANSFER_WAIT) {
|
||||
// printf("dap_read_reg fault\n");
|
||||
*dp_fault = 1;
|
||||
}
|
||||
if (buf[1] == DAP_TRANSFER_ERROR) {
|
||||
printf("dap_read_reg, protocoll error\n");
|
||||
dap_line_reset();
|
||||
}
|
||||
uint32_t res =
|
||||
((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) |
|
||||
((uint32_t)buf[3] << 8) | (uint32_t)buf[2];
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
uint8_t dap_index = 0;
|
||||
if (dp->dev)
|
||||
dap_index = dp->dev->dev;
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = 0x01; // Request size
|
||||
buf[3] = reg | DAP_TRANSFER_RnW;
|
||||
uint32_t res = wait_word(buf, 8, 4, &dp->fault);
|
||||
// printf("\tdap_read_reg %02x %08x\n", reg, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
// printf("\tdap_write_reg %02x %08x\n", reg, data);
|
||||
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
uint8_t dap_index = 0;
|
||||
if (dp->dev)
|
||||
dap_index = dp->dev->dev;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = 0x01; // Request size
|
||||
buf[3] = reg & ~DAP_TRANSFER_RnW;;
|
||||
buf[4] = data & 0xff;
|
||||
buf[5] = (data >> 8) & 0xff;
|
||||
buf[6] = (data >> 16) & 0xff;
|
||||
buf[7] = (data >> 24) & 0xff;
|
||||
do {
|
||||
dbg_dap_cmd(buf, sizeof(buf), 8);
|
||||
if (buf[1] < DAP_TRANSFER_WAIT)
|
||||
break;
|
||||
} while (buf[1] == DAP_TRANSFER_WAIT);
|
||||
|
||||
if (buf[1] > DAP_TRANSFER_WAIT) {
|
||||
// printf("dap_write_reg %02x data %08x:fault\n", reg, data);
|
||||
dp->fault = 1;
|
||||
}
|
||||
if (buf[1] == DAP_TRANSFER_ERROR) {
|
||||
// printf("dap_write_reg %02x data %08x: protocoll error\n", reg, data);
|
||||
dap_line_reset();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
uint8_t buf[1024];
|
||||
unsigned int sz = len >> align;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = sz & 0xff;
|
||||
buf[3] = (sz >> 8) & 0xff;
|
||||
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||
dbg_dap_cmd(buf, 1023, 5 + 1);
|
||||
unsigned int transferred = buf[0] + (buf[1] << 8);
|
||||
if (buf[2] > DAP_TRANSFER_FAULT) {
|
||||
printf("line_reset\n");
|
||||
dap_line_reset();
|
||||
}
|
||||
if (sz != transferred) {
|
||||
return 1;
|
||||
} else if (align > ALIGN_HALFWORD) {
|
||||
memcpy(dest, &buf[3], len);
|
||||
} else {
|
||||
uint32_t *p = (uint32_t *)&buf[3];
|
||||
while(sz) {
|
||||
dest = extract(dest, src, *p, align);
|
||||
p++;
|
||||
src += (1 << align);
|
||||
dest += (1 << align);
|
||||
sz--;
|
||||
}
|
||||
}
|
||||
return (buf[2] > DAP_TRANSFER_WAIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
uint8_t buf[1024];
|
||||
unsigned int sz = len >> align;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = sz & 0xff;
|
||||
buf[3] = (sz >> 8) & 0xff;
|
||||
buf[4] = SWD_AP_DRW;
|
||||
if (align > ALIGN_HALFWORD) {
|
||||
memcpy(&buf[5], src, len);
|
||||
} else {
|
||||
unsigned int size = len;
|
||||
uint32_t *p = (uint32_t *)&buf[5];
|
||||
while (size) {
|
||||
uint32_t tmp = 0;
|
||||
/* Pack data into correct data lane */
|
||||
if (align == ALIGN_BYTE) {
|
||||
tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3);
|
||||
} else {
|
||||
tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3);
|
||||
}
|
||||
src = src + (1 << align);
|
||||
dest += (1 << align);
|
||||
size--;
|
||||
*p++ = tmp;
|
||||
}
|
||||
}
|
||||
dbg_dap_cmd(buf, 1023, 5 + (sz << 2));
|
||||
if (buf[2] > DAP_TRANSFER_FAULT) {
|
||||
dap_line_reset();
|
||||
}
|
||||
return (buf[2] > DAP_TRANSFER_WAIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_reset_link(bool jtag)
|
||||
{
|
||||
uint8_t buf[128], *p = buf;
|
||||
|
||||
//-------------
|
||||
*p++ = ID_DAP_SWJ_SEQUENCE;
|
||||
p++;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
if (jtag) {
|
||||
*p++ = 0x3c;
|
||||
*p++ = 0xe7;
|
||||
*p++ = 0x1f;
|
||||
buf[1] = ((p - &buf[2]) * 8) - 2;
|
||||
} else {
|
||||
*p++ = 0x9e;
|
||||
*p++ = 0xe7;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0x00;
|
||||
buf[1] = (p - &buf[2]) * 8;
|
||||
}
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
|
||||
if (!jtag) {
|
||||
//-------------
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
buf[1] = 0; // DAP index
|
||||
buf[2] = 1; // Request size
|
||||
buf[3] = SWD_DP_R_IDCODE | DAP_TRANSFER_RnW;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 4);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t dap_read_idcode(ADIv5_DP_t *dp)
|
||||
{
|
||||
return dap_read_reg(dp, SWD_DP_R_IDCODE);
|
||||
}
|
||||
|
||||
static uint8_t *mem_access_setup(ADIv5_AP_t *ap, uint8_t *p,
|
||||
uint32_t addr, enum align align)
|
||||
{
|
||||
uint32_t csw = ap->csw | ADIV5_AP_CSW_ADDRINC_SINGLE;
|
||||
switch (align) {
|
||||
case ALIGN_BYTE:
|
||||
csw |= ADIV5_AP_CSW_SIZE_BYTE;
|
||||
break;
|
||||
case ALIGN_HALFWORD:
|
||||
csw |= ADIV5_AP_CSW_SIZE_HALFWORD;
|
||||
break;
|
||||
case ALIGN_DWORD:
|
||||
case ALIGN_WORD:
|
||||
csw |= ADIV5_AP_CSW_SIZE_WORD;
|
||||
break;
|
||||
}
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
*p++ = ID_DAP_TRANSFER;
|
||||
*p++ = dap_index;
|
||||
*p++ = 3; /* Nr transfers */
|
||||
*p++ = SWD_DP_W_SELECT;
|
||||
*p++ = ADIV5_AP_CSW & 0xF0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = ap->apsel & 0xff;
|
||||
*p++ = SWD_AP_CSW;
|
||||
*p++ = (csw >> 0) & 0xff;
|
||||
*p++ = (csw >> 8) & 0xff;
|
||||
*p++ = (csw >> 16) & 0xff;
|
||||
*p++ = (csw >> 24) & 0xff;
|
||||
*p++ = SWD_AP_TAR ;
|
||||
*p++ = (addr >> 0) & 0xff;
|
||||
*p++ = (addr >> 8) & 0xff;
|
||||
*p++ = (addr >> 16) & 0xff;
|
||||
*p++ = (addr >> 24) & 0xff;
|
||||
return p;
|
||||
}
|
||||
|
||||
void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
|
||||
{
|
||||
uint8_t buf[63];
|
||||
uint8_t *p = mem_access_setup(ap, buf, addr, align);
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
}
|
||||
|
||||
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
{
|
||||
// printf("dap_ap_read_start\n");
|
||||
uint8_t buf[63], *p = buf;
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
*p++ = ID_DAP_TRANSFER;
|
||||
*p++ = dap_index;
|
||||
*p++ = 2; /* Nr transfers */
|
||||
*p++ = SWD_DP_W_SELECT;
|
||||
*p++ = (addr & 0xF0);
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = ap->apsel & 0xff;
|
||||
*p++ = (addr & 0x0c) | DAP_TRANSFER_RnW |
|
||||
((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
|
||||
uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
||||
return res;
|
||||
}
|
||||
|
||||
void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
{
|
||||
// printf("dap_ap_write addr %04x value %08x\n", addr, value);
|
||||
uint8_t buf[63], *p = buf;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
*p++ = ID_DAP_TRANSFER;
|
||||
*p++ = dap_index;
|
||||
*p++ = 2; /* Nr transfers */
|
||||
*p++ = SWD_DP_W_SELECT;
|
||||
*p++ = (addr & 0xF0);
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = ap->apsel & 0xff;
|
||||
*p++ = (addr & 0x0c) | ((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
|
||||
*p++ = (value >> 0) & 0xff;
|
||||
*p++ = (value >> 8) & 0xff;
|
||||
*p++ = (value >> 16) & 0xff;
|
||||
*p++ = (value >> 24) & 0xff;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
// printf("dap_ap_write done\n");
|
||||
}
|
||||
|
||||
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
|
||||
{
|
||||
uint8_t buf[63];
|
||||
uint8_t *p = mem_access_setup(ap, buf, src, align);
|
||||
*p++ = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||
buf[2] = 4;
|
||||
uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
||||
dest = extract(dest, src, tmp, align);
|
||||
}
|
||||
|
||||
void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
enum align align)
|
||||
{
|
||||
uint8_t buf[63];
|
||||
uint8_t *p = mem_access_setup(ap, buf, dest, align);
|
||||
*p++ = SWD_AP_DRW;
|
||||
uint32_t tmp = 0;
|
||||
/* Pack data into correct data lane */
|
||||
switch (align) {
|
||||
case ALIGN_BYTE:
|
||||
tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3);
|
||||
break;
|
||||
case ALIGN_HALFWORD:
|
||||
tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3);
|
||||
break;
|
||||
case ALIGN_DWORD:
|
||||
case ALIGN_WORD:
|
||||
tmp = *(uint32_t *)src;
|
||||
break;
|
||||
}
|
||||
*p++ = (tmp >> 0) & 0xff;
|
||||
*p++ = (tmp >> 8) & 0xff;
|
||||
*p++ = (tmp >> 16) & 0xff;
|
||||
*p++ = (tmp >> 24) & 0xff;
|
||||
buf[2] = 4;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
}
|
||||
|
||||
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
if (!TMS) {
|
||||
int last_byte = 0;
|
||||
int last_bit = 0;
|
||||
if (final_tms) {
|
||||
last_byte = ticks >> 3;
|
||||
last_bit = ticks & 7;
|
||||
ticks --;
|
||||
}
|
||||
while (ticks) {
|
||||
int transfers = ticks;
|
||||
if (transfers > 64)
|
||||
transfers = 64;
|
||||
uint8_t *p = buf;
|
||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||
*p++ = 1;
|
||||
*p++ = transfers | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
|
||||
int n_di_bytes = (transfers + 7) >> 3;
|
||||
if (DI) {
|
||||
p = memcpy(p, DI, n_di_bytes);
|
||||
DI += n_di_bytes;
|
||||
} else {
|
||||
p = memset(p, 0xff, n_di_bytes);
|
||||
}
|
||||
p += n_di_bytes;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] != DAP_OK)
|
||||
printf("Failed %02x\n", buf[0]);
|
||||
if (DO) {
|
||||
memcpy(DO, &buf[1], (transfers + 7) >> 3);
|
||||
DO += (transfers + 7) >> 3;
|
||||
}
|
||||
ticks -= transfers;
|
||||
}
|
||||
if (final_tms) {
|
||||
uint8_t *p = buf;
|
||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||
*p++ = 1;
|
||||
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS;
|
||||
if (DI) {
|
||||
*p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0);
|
||||
} else {
|
||||
*p++ = 0;
|
||||
}
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] == DAP_ERROR)
|
||||
printf("Failed %02x\n", buf[0]);
|
||||
if (DO) {
|
||||
if (buf[1] & 1)
|
||||
DO[last_byte] |= (1 << last_bit);
|
||||
else
|
||||
DO[last_byte] &= ~(1 << last_bit);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while(ticks) {
|
||||
uint8_t *p = buf;
|
||||
int transfers = ticks;
|
||||
if (transfers > 64)
|
||||
transfers = 64;
|
||||
p = buf;
|
||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||
*p++ = transfers;
|
||||
for (int i = 0; i < transfers; i++) {
|
||||
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) |
|
||||
((TMS[i >> 8] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0);
|
||||
if (DI)
|
||||
*p++ = (DI[i >> 8] & (1 << (i & 7))) ? 1 : 0;
|
||||
else
|
||||
*p++ = 0x55;
|
||||
}
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] == DAP_ERROR)
|
||||
printf("Failed %02x\n", buf[0]);
|
||||
if (DO) {
|
||||
for (int i = 0; i < transfers; i++) {
|
||||
if (buf[i + 1])
|
||||
DO[i >> 8] |= (1 << (i & 7));
|
||||
else
|
||||
DO[i >> 8] &= ~(1 << (i & 7));
|
||||
}
|
||||
}
|
||||
ticks -= transfers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dap_jtag_configure(void)
|
||||
{
|
||||
uint8_t buf[64], *p = &buf[2];
|
||||
int i = 0;
|
||||
for (; i < jtag_dev_count; i++) {
|
||||
struct jtag_dev_s *jtag_dev = &jtag_devs[i];
|
||||
*p++ = jtag_dev->ir_len;
|
||||
printf("irlen %d\n", jtag_dev->ir_len);
|
||||
}
|
||||
if ((!i || i >= JTAG_MAX_DEVS))
|
||||
return -1;
|
||||
buf[0] = 0x15;
|
||||
buf[1] = i;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] != DAP_OK)
|
||||
printf("dap_jtag_configure Failed %02x\n", buf[0]);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015, Alex Taradov <alex@taradov.com>
|
||||
* 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. The name of the author may not 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.
|
||||
*/
|
||||
|
||||
#ifndef _DAP_H_
|
||||
#define _DAP_H_
|
||||
|
||||
/*- Includes ----------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "adiv5.h"
|
||||
|
||||
/*- Definitions -------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
DAP_INFO_VENDOR = 0x01,
|
||||
DAP_INFO_PRODUCT = 0x02,
|
||||
DAP_INFO_SER_NUM = 0x03,
|
||||
DAP_INFO_FW_VER = 0x04,
|
||||
DAP_INFO_DEVICE_VENDOR = 0x05,
|
||||
DAP_INFO_DEVICE_NAME = 0x06,
|
||||
DAP_INFO_CAPABILITIES = 0xf0,
|
||||
DAP_INFO_TDT = 0xf1,
|
||||
DAP_INFO_SWO_BUF_SIZE = 0xfd,
|
||||
DAP_INFO_PACKET_COUNT = 0xfe,
|
||||
DAP_INFO_PACKET_SIZE = 0xff,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_CAP_SWD = (1 << 0),
|
||||
DAP_CAP_JTAG = (1 << 1),
|
||||
DAP_CAP_SWO_UART = (1 << 2),
|
||||
DAP_CAP_SWO_MANCHESTER = (1 << 3),
|
||||
DAP_CAP_ATOMIC_CMD = (1 << 4),
|
||||
DAP_CAP_TDT = (1 << 5),
|
||||
DAP_CAP_SWO_STREAMING = (1 << 6),
|
||||
};
|
||||
|
||||
/*- Prototypes --------------------------------------------------------------*/
|
||||
void dap_led(int index, int state);
|
||||
void dap_connect(bool jtag);
|
||||
void dap_disconnect(void);
|
||||
void dap_swj_clock(uint32_t clock);
|
||||
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry);
|
||||
void dap_swd_configure(uint8_t cfg);
|
||||
int dap_info(int info, uint8_t *data, int size);
|
||||
void dap_reset_target(void);
|
||||
void dap_trst_reset(void);
|
||||
void dap_reset_target_hw(int state);
|
||||
void dap_reset_pin(int state);
|
||||
uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg);
|
||||
void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data);
|
||||
void dap_reset_link(bool jtag);
|
||||
uint32_t dap_read_idcode(ADIv5_DP_t *dp);
|
||||
unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
size_t len, enum align align);
|
||||
unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align);
|
||||
void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align);
|
||||
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr);
|
||||
void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
|
||||
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align);
|
||||
void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
enum align align);
|
||||
int dbg_dap_cmd(uint8_t *data, int size, int rsize);
|
||||
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||
const uint8_t *DI, int ticks);
|
||||
int dap_jtag_configure(void);
|
||||
#endif // _DAP_H_
|
|
@ -36,6 +36,7 @@
|
|||
#include "stlinkv2.h"
|
||||
#include "ftdi_bmp.h"
|
||||
#include "jlink.h"
|
||||
#include "cmsis_dap.h"
|
||||
|
||||
#define VENDOR_ID_BMP 0x1d50
|
||||
#define PRODUCT_ID_BMP 0x6018
|
||||
|
@ -69,6 +70,9 @@ static void exit_function(void)
|
|||
}
|
||||
}
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
dap_exit_function();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -169,6 +173,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
|||
fprintf(stderr, "INFO: STLINKV1 not supported\n");
|
||||
continue;
|
||||
}
|
||||
} else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
|
||||
type = BMP_TYPE_CMSIS_DAP;
|
||||
} else if (desc.idVendor == VENDOR_ID_SEGGER) {
|
||||
type = BMP_TYPE_JLINK;
|
||||
} else{
|
||||
|
@ -244,6 +250,10 @@ void platform_init(int argc, char **argv)
|
|||
if (stlink_init( &info))
|
||||
exit(-1);
|
||||
break;
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
if (dap_init( &info))
|
||||
exit(-1);
|
||||
break;
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
break;
|
||||
case BMP_TYPE_JLINK:
|
||||
|
@ -282,6 +292,18 @@ int platform_adiv5_swdp_scan(void)
|
|||
free(dp);
|
||||
break;
|
||||
}
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
{
|
||||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (!dap_enter_debug_swd(dp)) {
|
||||
adiv5_dp_init(dp);
|
||||
if (target_list)
|
||||
return 1;
|
||||
}
|
||||
free(dp);
|
||||
break;
|
||||
}
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_swdp_scan(&info);
|
||||
default:
|
||||
|
@ -296,6 +318,7 @@ int platform_swdptap_init(void)
|
|||
case BMP_TYPE_BMP:
|
||||
return remote_swdptap_init(&swd_proc);
|
||||
case BMP_TYPE_STLINKV2:
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
case BMP_TYPE_JLINK:
|
||||
return 0;
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
|
@ -312,6 +335,7 @@ int platform_jtag_scan(const uint8_t *lrlens)
|
|||
case BMP_TYPE_BMP:
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
case BMP_TYPE_JLINK:
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return jtag_scan(lrlens);
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return jtag_scan_stlinkv2(&info, lrlens);
|
||||
|
@ -332,6 +356,8 @@ int platform_jtagtap_init(void)
|
|||
return libftdi_jtagtap_init(&jtag_proc);
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_jtagtap_init(&info, &jtag_proc);
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return cmsis_dap_jtagtap_init(&jtag_proc);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -343,6 +369,8 @@ void platform_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
|||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_adiv5_dp_defaults(dp);
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return dap_adiv5_dp_defaults(dp);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -357,6 +385,8 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp)
|
|||
return 0;
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_jtag_dp_init(dp);
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return dap_jtag_dp_init(dp);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
if (optarg)
|
||||
cl_debuglevel = strtol(optarg, NULL, 0);
|
||||
else
|
||||
cl_debuglevel = -1;
|
||||
cl_debuglevel = 1;
|
||||
break;
|
||||
case 'j':
|
||||
opt->opt_usejtag = true;
|
||||
|
|
|
@ -36,6 +36,13 @@ enum bmp_cl_mode {
|
|||
BMP_MODE_FLASH_VERIFY
|
||||
};
|
||||
|
||||
enum BMP_DEBUG {
|
||||
BMP_DEBUG_NONE = 0,
|
||||
BMP_DEBUG_INFO = 1,
|
||||
BMP_DEBUG_PLATFORM = 2,
|
||||
BMP_DEBUG_WIRE = 4
|
||||
};
|
||||
|
||||
typedef struct BMP_CL_OPTIONS_s {
|
||||
enum bmp_cl_mode opt_mode;
|
||||
bool opt_usejtag;
|
||||
|
|
Loading…
Reference in New Issue