Merge commit '61e237ec87c525876817e72fc82ce28b2a4951ae' into sam-update
This commit is contained in:
commit
f109bc2e98
@ -20,11 +20,20 @@
|
|||||||
|
|
||||||
#ifndef __SWDPTAP_H
|
#ifndef __SWDPTAP_H
|
||||||
#define __SWDPTAP_H
|
#define __SWDPTAP_H
|
||||||
|
#include "adiv5.h"
|
||||||
|
|
||||||
typedef struct swd_proc_s {
|
typedef struct swd_proc_s {
|
||||||
uint32_t (*swdptap_seq_in)(int ticks);
|
uint32_t (*swdptap_seq_in)(int ticks);
|
||||||
bool (*swdptap_seq_in_parity)(uint32_t *data, int ticks);
|
bool (*swdptap_seq_in_parity)(uint32_t *data, int ticks);
|
||||||
void (*swdptap_seq_out)(uint32_t MS, int ticks);
|
void (*swdptap_seq_out)(uint32_t MS, int ticks);
|
||||||
void (*swdptap_seq_out_parity)(uint32_t MS, int ticks);
|
void (*swdptap_seq_out_parity)(uint32_t MS, int ticks);
|
||||||
|
# if PC_HOSTED == 1
|
||||||
|
uint32_t (*swdp_read)(ADIv5_DP_t *dp, uint16_t addr);
|
||||||
|
uint32_t (*swdp_error)(ADIv5_DP_t *dp);
|
||||||
|
uint32_t (*swdp_low_access)(ADIv5_DP_t *dp, uint8_t RnW,
|
||||||
|
uint16_t addr, uint32_t value);
|
||||||
|
void (*swdp_abort)(ADIv5_DP_t *dp, uint32_t abort);
|
||||||
|
#endif
|
||||||
} swd_proc_t;
|
} swd_proc_t;
|
||||||
extern swd_proc_t swd_proc;
|
extern swd_proc_t swd_proc;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "bmp_hosted.h"
|
#include "bmp_hosted.h"
|
||||||
|
#include "swdptap.h"
|
||||||
#include "dap.h"
|
#include "dap.h"
|
||||||
#include "cmsis_dap.h"
|
#include "cmsis_dap.h"
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ int dap_init(bmp_info_t *info)
|
|||||||
*/
|
*/
|
||||||
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
|
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
|
||||||
DEBUG_WARN("Blacklist\n");
|
DEBUG_WARN("Blacklist\n");
|
||||||
report_size = 64 + 1;
|
report_size = 64;
|
||||||
}
|
}
|
||||||
handle = hid_open(info->vid, info->pid, (serial[0]) ? serial : NULL);
|
handle = hid_open(info->vid, info->pid, (serial[0]) ? serial : NULL);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
@ -79,12 +80,12 @@ int dap_init(bmp_info_t *info)
|
|||||||
if (sscanf((const char *)hid_buffer, "%d.%d.%d",
|
if (sscanf((const char *)hid_buffer, "%d.%d.%d",
|
||||||
&major, &minor, &sub)) {
|
&major, &minor, &sub)) {
|
||||||
if (sub == -1) {
|
if (sub == -1) {
|
||||||
if (minor > 10) {
|
if (minor >= 10) {
|
||||||
minor /= 10;
|
minor /= 10;
|
||||||
sub = 0;
|
sub = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
has_swd_sequence = ((major > 0 ) && (minor > 1));
|
has_swd_sequence = ((major > 1 ) || ((major > 0 ) && (minor > 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
||||||
@ -99,6 +100,11 @@ int dap_init(bmp_info_t *info)
|
|||||||
DEBUG_INFO(", SWO_MANCHESTER");
|
DEBUG_INFO(", SWO_MANCHESTER");
|
||||||
if (dap_caps & 0x10)
|
if (dap_caps & 0x10)
|
||||||
DEBUG_INFO(", Atomic Cmds");
|
DEBUG_INFO(", Atomic Cmds");
|
||||||
|
size = dap_info(DAP_INFO_PACKET_SIZE, hid_buffer, sizeof(hid_buffer));
|
||||||
|
if (size) {
|
||||||
|
report_size = hid_buffer[0];
|
||||||
|
DEBUG_INFO(", Reportsize %d", hid_buffer[0]);
|
||||||
|
}
|
||||||
DEBUG_INFO("\n");
|
DEBUG_INFO("\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -170,38 +176,36 @@ int dbg_dap_cmd(uint8_t *data, int size, int rsize)
|
|||||||
char cmd = data[0];
|
char cmd = data[0];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
memset(hid_buffer, 0xff, report_size + 1);
|
memset(hid_buffer, 0, report_size + 1);
|
||||||
|
|
||||||
hid_buffer[0] = 0x00; // Report ID??
|
|
||||||
memcpy(&hid_buffer[1], data, rsize);
|
memcpy(&hid_buffer[1], data, rsize);
|
||||||
|
|
||||||
DEBUG_WIRE("cmd : ");
|
DEBUG_WIRE("cmd : ");
|
||||||
for(int i = 0; (i < 16) && (i < rsize + 1); i++)
|
for(int i = 0; (i < 16) && (i < rsize + 1); i++)
|
||||||
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
||||||
DEBUG_WIRE("\n");
|
DEBUG_WIRE("\n");
|
||||||
res = hid_write(handle, hid_buffer, rsize + 1);
|
/* Write must be as long as we expect the result, at least
|
||||||
|
* for Dappermime 20210213 */
|
||||||
|
res = hid_write(handle, hid_buffer, report_size + 1);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
DEBUG_WARN( "Error: %ls\n", hid_error(handle));
|
DEBUG_WARN( "Error: %ls\n", hid_error(handle));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
if (size) {
|
res = hid_read(handle, hid_buffer, report_size + 1);
|
||||||
res = hid_read(handle, hid_buffer, report_size + 1);
|
if (res < 0) {
|
||||||
if (res < 0) {
|
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
|
||||||
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
|
exit(-1);
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
if (size && hid_buffer[0] != cmd) {
|
|
||||||
DEBUG_WARN("cmd %02x invalid response received %02x\n",
|
|
||||||
cmd, hid_buffer[0]);
|
|
||||||
}
|
|
||||||
res--;
|
|
||||||
memcpy(data, &hid_buffer[1], (size < res) ? size : res);
|
|
||||||
DEBUG_WIRE("cmd res:");
|
|
||||||
for(int i = 0; (i < 16) && (i < size + 4); i++)
|
|
||||||
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
|
||||||
DEBUG_WIRE("\n");
|
|
||||||
}
|
}
|
||||||
|
DEBUG_WIRE("res %2d: ", res);
|
||||||
|
for(int i = 0; (i < 16) && (i < res + 1); i++)
|
||||||
|
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
||||||
|
DEBUG_WIRE("\n");
|
||||||
|
if (hid_buffer[0] != cmd) {
|
||||||
|
DEBUG_WARN("cmd %02x invalid response received %02x\n",
|
||||||
|
cmd, hid_buffer[0]);
|
||||||
|
}
|
||||||
|
if (size)
|
||||||
|
memcpy(data, &hid_buffer[1], (size < res) ? size : res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
||||||
@ -283,16 +287,6 @@ static void dap_mem_write_sized(
|
|||||||
|
|
||||||
int dap_enter_debug_swd(ADIv5_DP_t *dp)
|
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_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->idcode = dap_read_idcode(dp);
|
||||||
dp->dp_read = dap_dp_read_reg;
|
dp->dp_read = dap_dp_read_reg;
|
||||||
dp->error = dap_dp_error;
|
dp->error = dap_dp_error;
|
||||||
@ -355,12 +349,12 @@ int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
|||||||
mode = DAP_CAP_JTAG;
|
mode = DAP_CAP_JTAG;
|
||||||
dap_disconnect();
|
dap_disconnect();
|
||||||
dap_connect(true);
|
dap_connect(true);
|
||||||
|
dap_reset_link(true);
|
||||||
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
|
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
|
||||||
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
|
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
|
||||||
jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq;
|
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_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq;
|
||||||
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
|
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
|
||||||
dap_reset_link(true);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,3 +367,26 @@ int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dap_swdptap_init(swd_proc_t *swd_proc)
|
||||||
|
{
|
||||||
|
if (!(dap_caps & DAP_CAP_SWD))
|
||||||
|
return 1;
|
||||||
|
mode = DAP_CAP_SWD;
|
||||||
|
dap_transfer_configure(2, 128, 128);
|
||||||
|
dap_swd_configure(0);
|
||||||
|
dap_connect(false);
|
||||||
|
dap_led(0, 1);
|
||||||
|
dap_reset_link(false);
|
||||||
|
if (has_swd_sequence) {
|
||||||
|
swd_proc->swdptap_seq_in = dap_swdptap_seq_in;
|
||||||
|
swd_proc->swdptap_seq_in_parity = dap_swdptap_seq_in_parity;
|
||||||
|
swd_proc->swdptap_seq_out = dap_swdptap_seq_out;
|
||||||
|
swd_proc->swdptap_seq_out_parity = dap_swdptap_seq_out_parity;
|
||||||
|
swd_proc->swdp_read = dap_dp_read_reg;
|
||||||
|
swd_proc->swdp_error = dap_dp_error;
|
||||||
|
swd_proc->swdp_low_access = dap_dp_low_access;
|
||||||
|
swd_proc->swdp_abort = dap_dp_abort;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -28,8 +28,10 @@ int dap_enter_debug_swd(ADIv5_DP_t *dp);
|
|||||||
void dap_exit_function(void);
|
void dap_exit_function(void);
|
||||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
|
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||||
|
int dap_swdptap_init(swd_proc_t *swd_proc);
|
||||||
int dap_jtag_dp_init(ADIv5_DP_t *dp);
|
int dap_jtag_dp_init(ADIv5_DP_t *dp);
|
||||||
uint32_t dap_swj_clock(uint32_t clock);
|
uint32_t dap_swj_clock(uint32_t clock);
|
||||||
|
void dap_swd_configure(uint8_t cfg);
|
||||||
#else
|
#else
|
||||||
int dap_init(bmp_info_t *info)
|
int dap_init(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
@ -44,8 +46,10 @@ uint32_t dap_swj_clock(uint32_t clock) {return 0;}
|
|||||||
void dap_exit_function(void) {};
|
void dap_exit_function(void) {};
|
||||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
|
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
|
||||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) {return -1;}
|
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) {return -1;}
|
||||||
|
int dap_swdptap_init(swd_proc_t *swd_proc) {return -1;}
|
||||||
int dap_jtag_dp_init(ADIv5_DP_t *dp) {return -1;}
|
int dap_jtag_dp_init(ADIv5_DP_t *dp) {return -1;}
|
||||||
# pragma GCC diagnostic pop
|
void dap_swd_configure(uint8_t cfg) {};
|
||||||
|
## pragma GCC diagnostic pop
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Modified for Blackmagic Probe
|
/* Modified for Blackmagic Probe
|
||||||
* Copyright (c) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
* Copyright (c) 2020-21 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*- Includes ----------------------------------------------------------------*/
|
/*- Includes ----------------------------------------------------------------*/
|
||||||
@ -57,6 +57,7 @@ enum
|
|||||||
ID_DAP_JTAG_SEQUENCE = 0x14,
|
ID_DAP_JTAG_SEQUENCE = 0x14,
|
||||||
ID_DAP_JTAG_CONFIGURE = 0x15,
|
ID_DAP_JTAG_CONFIGURE = 0x15,
|
||||||
ID_DAP_JTAG_IDCODE = 0x16,
|
ID_DAP_JTAG_IDCODE = 0x16,
|
||||||
|
ID_DAP_SWD_SEQUENCE = 0x1D,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -197,7 +198,7 @@ void dap_connect(bool jtag)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void dap_disconnect(void)
|
void dap_disconnect(void)
|
||||||
{
|
{
|
||||||
uint8_t buf[1];
|
uint8_t buf[65];
|
||||||
|
|
||||||
buf[0] = ID_DAP_DISCONNECT;
|
buf[0] = ID_DAP_DISCONNECT;
|
||||||
dbg_dap_cmd(buf, sizeof(buf), 1);
|
dbg_dap_cmd(buf, sizeof(buf), 1);
|
||||||
@ -212,7 +213,7 @@ uint32_t dap_swj_clock(uint32_t clock)
|
|||||||
{
|
{
|
||||||
if (clock == 0)
|
if (clock == 0)
|
||||||
return swj_clock;
|
return swj_clock;
|
||||||
uint8_t buf[5];
|
uint8_t buf[65];
|
||||||
buf[0] = ID_DAP_SWJ_CLOCK;
|
buf[0] = ID_DAP_SWJ_CLOCK;
|
||||||
buf[1] = clock & 0xff;
|
buf[1] = clock & 0xff;
|
||||||
buf[2] = (clock >> 8) & 0xff;
|
buf[2] = (clock >> 8) & 0xff;
|
||||||
@ -253,7 +254,7 @@ void dap_swd_configure(uint8_t cfg)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
int dap_info(int info, uint8_t *data, int size)
|
int dap_info(int info, uint8_t *data, int size)
|
||||||
{
|
{
|
||||||
uint8_t buf[256];
|
uint8_t buf[32];
|
||||||
int rsize;
|
int rsize;
|
||||||
|
|
||||||
buf[0] = ID_DAP_INFO;
|
buf[0] = ID_DAP_INFO;
|
||||||
@ -750,3 +751,75 @@ int dap_jtag_configure(void)
|
|||||||
DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]);
|
DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dap_swdptap_seq_out(uint32_t MS, int ticks)
|
||||||
|
{
|
||||||
|
uint8_t buf[] = {
|
||||||
|
ID_DAP_SWJ_SEQUENCE,
|
||||||
|
ticks,
|
||||||
|
(MS >> 0) & 0xff,
|
||||||
|
(MS >> 8) & 0xff,
|
||||||
|
(MS >> 16) & 0xff,
|
||||||
|
(MS >> 24) & 0xff
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 1, sizeof(buf));
|
||||||
|
if (buf[0])
|
||||||
|
DEBUG_WARN("dap_swdptap_seq_out error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||||
|
{
|
||||||
|
uint8_t buf[] = {
|
||||||
|
ID_DAP_SWJ_SEQUENCE,
|
||||||
|
ticks + 1,
|
||||||
|
(MS >> 0) & 0xff,
|
||||||
|
(MS >> 8) & 0xff,
|
||||||
|
(MS >> 16) & 0xff,
|
||||||
|
(MS >> 24) & 0xff,
|
||||||
|
__builtin_parity(MS) & 1
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 1, sizeof(buf));
|
||||||
|
if (buf[0])
|
||||||
|
DEBUG_WARN("dap_swdptap_seq_out error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWD_SEQUENCE_IN 0x80
|
||||||
|
uint32_t dap_swdptap_seq_in(int ticks)
|
||||||
|
{
|
||||||
|
uint8_t buf[16] = {
|
||||||
|
ID_DAP_SWD_SEQUENCE,
|
||||||
|
1,
|
||||||
|
ticks + SWD_SEQUENCE_IN
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 2 + ((ticks + 7) >> 3), 3);
|
||||||
|
uint32_t res = 0;
|
||||||
|
int len = (ticks + 7) >> 3;
|
||||||
|
while (len--) {
|
||||||
|
res <<= 8;
|
||||||
|
res += buf[len + 1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dap_swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||||
|
{
|
||||||
|
(void)ticks;
|
||||||
|
uint8_t buf[16] = {
|
||||||
|
ID_DAP_SWD_SEQUENCE,
|
||||||
|
2,
|
||||||
|
32 + SWD_SEQUENCE_IN,
|
||||||
|
1 + SWD_SEQUENCE_IN,
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 7, 4);
|
||||||
|
uint32_t res = 0;
|
||||||
|
int len = 4;
|
||||||
|
while (len--) {
|
||||||
|
res <<= 8;
|
||||||
|
res += buf[len + 1];
|
||||||
|
}
|
||||||
|
*ret = res;
|
||||||
|
unsigned int parity = __builtin_parity(res) & 1;
|
||||||
|
parity ^= (buf[5] % 1);
|
||||||
|
DEBUG_WARN("Res %08" PRIx32" %d\n", *ret, parity & 1);
|
||||||
|
return (!parity & 1);
|
||||||
|
}
|
||||||
|
@ -90,4 +90,8 @@ 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,
|
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||||
const uint8_t *DI, int ticks);
|
const uint8_t *DI, int ticks);
|
||||||
int dap_jtag_configure(void);
|
int dap_jtag_configure(void);
|
||||||
|
void dap_swdptap_seq_out(uint32_t MS, int ticks);
|
||||||
|
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||||
|
uint32_t dap_swdptap_seq_in(int ticks);
|
||||||
|
bool dap_swdptap_seq_in_parity(uint32_t *ret, int ticks);
|
||||||
#endif // _DAP_H_
|
#endif // _DAP_H_
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Copyright(C) 2018 - 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -212,7 +211,10 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
|
|||||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
||||||
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
||||||
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
||||||
|
swd_proc->swdp_read = firmware_swdp_read;
|
||||||
|
swd_proc->swdp_error = firmware_swdp_error;
|
||||||
|
swd_proc->swdp_low_access = firmware_swdp_low_access;
|
||||||
|
swd_proc->swdp_abort = firmware_swdp_abort;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,18 +144,26 @@ int platform_adiv5_swdp_scan(uint32_t targetid)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BMP_TYPE_CMSIS_DAP:
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
{
|
if (dap_swdptap_init(&swd_proc))
|
||||||
target_list_free();
|
return 0;
|
||||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
if (swd_proc.swdptap_seq_in) {
|
||||||
if (dap_enter_debug_swd(dp)) {
|
dap_swd_configure(4); /* No abort for now*/
|
||||||
free(dp);
|
return adiv5_swdp_scan(targetid);
|
||||||
} else {
|
} else {
|
||||||
adiv5_dp_init(dp);
|
/* We need to ignore errors with TARGET_SEL.
|
||||||
if (target_list)
|
* Therefore we need DAP_SWD_Sequence obly available on >= V1.2
|
||||||
return 1;
|
*/
|
||||||
|
target_list_free();
|
||||||
|
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||||
|
if (dap_enter_debug_swd(dp)) {
|
||||||
|
free(dp);
|
||||||
|
} else {
|
||||||
|
adiv5_dp_init(dp);
|
||||||
|
if (target_list)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case BMP_TYPE_JLINK:
|
case BMP_TYPE_JLINK:
|
||||||
return jlink_swdp_scan(&info);
|
return jlink_swdp_scan(&info);
|
||||||
default:
|
default:
|
||||||
@ -169,8 +177,9 @@ int platform_swdptap_init(void)
|
|||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
return remote_swdptap_init(&swd_proc);
|
return remote_swdptap_init(&swd_proc);
|
||||||
case BMP_TYPE_STLINKV2:
|
|
||||||
case BMP_TYPE_CMSIS_DAP:
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
|
// return dap_swdptap_init(&swd_proc);
|
||||||
|
case BMP_TYPE_STLINKV2:
|
||||||
case BMP_TYPE_JLINK:
|
case BMP_TYPE_JLINK:
|
||||||
return 0;
|
return 0;
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
* Modified by Dave Marples <dave@marples.net>
|
* Modified by Dave Marples <dave@marples.net>
|
||||||
* Modification (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Modified 2020 - 2021 by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -54,7 +54,10 @@ int remote_swdptap_init(swd_proc_t *swd_proc)
|
|||||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
||||||
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
||||||
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
||||||
|
swd_proc->swdp_read = firmware_swdp_read;
|
||||||
|
swd_proc->swdp_error = firmware_swdp_error;
|
||||||
|
swd_proc->swdp_low_access = firmware_swdp_low_access;
|
||||||
|
swd_proc->swdp_abort = firmware_swdp_abort;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,13 +707,6 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dp->idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
|
|
||||||
/* Read TargetID. Can be done with device in WFI, sleep or reset!*/
|
|
||||||
adiv5_dp_write(dp, ADIV5_DP_SELECT, ADIV5_DP_BANK2);
|
|
||||||
dp->targetid = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
|
|
||||||
adiv5_dp_write(dp, ADIV5_DP_SELECT, ADIV5_DP_BANK0);
|
|
||||||
DEBUG_INFO("TARGETID %08" PRIx32 "\n", dp->targetid);
|
|
||||||
}
|
|
||||||
/* Probe for APs on this DP */
|
/* Probe for APs on this DP */
|
||||||
uint32_t last_base = 0;
|
uint32_t last_base = 0;
|
||||||
int void_aps = 0;
|
int void_aps = 0;
|
||||||
|
@ -27,18 +27,20 @@
|
|||||||
#define ADIV5_DP_REG(x) (x)
|
#define ADIV5_DP_REG(x) (x)
|
||||||
#define ADIV5_AP_REG(x) (ADIV5_APnDP | (x))
|
#define ADIV5_AP_REG(x) (ADIV5_APnDP | (x))
|
||||||
|
|
||||||
|
#define ADIV5_DP_BANK0 0x00
|
||||||
|
#define ADIV5_DP_BANK1 0x10
|
||||||
|
#define ADIV5_DP_BANK2 0x20
|
||||||
|
#define ADIV5_DP_BANK3 0x30
|
||||||
|
#define ADIV5_DP_BANK4 0x40
|
||||||
|
|
||||||
/* ADIv5 DP Register addresses */
|
/* ADIv5 DP Register addresses */
|
||||||
#define ADIV5_DP_IDCODE ADIV5_DP_REG(0x0)
|
#define ADIV5_DP_IDCODE ADIV5_DP_REG(0x0)
|
||||||
#define ADIV5_DP_ABORT ADIV5_DP_REG(0x0)
|
#define ADIV5_DP_ABORT ADIV5_DP_REG(0x0)
|
||||||
#define ADIV5_DP_CTRLSTAT ADIV5_DP_REG(0x4)
|
#define ADIV5_DP_CTRLSTAT ADIV5_DP_REG(0x4)
|
||||||
|
#define ADIV5_DP_TARGETID (ADIV5_DP_BANK2 | ADIV5_DP_REG(0x4))
|
||||||
#define ADIV5_DP_SELECT ADIV5_DP_REG(0x8)
|
#define ADIV5_DP_SELECT ADIV5_DP_REG(0x8)
|
||||||
#define ADIV5_DP_RDBUFF ADIV5_DP_REG(0xC)
|
#define ADIV5_DP_RDBUFF ADIV5_DP_REG(0xC)
|
||||||
|
#define ADIV5_DP_TARGETSEL ADIV5_DP_REG(0xC)
|
||||||
#define ADIV5_DP_BANK0 0
|
|
||||||
#define ADIV5_DP_BANK1 1
|
|
||||||
#define ADIV5_DP_BANK2 2
|
|
||||||
#define ADIV5_DP_BANK3 3
|
|
||||||
#define ADIV5_DP_BANK4 4
|
|
||||||
|
|
||||||
#define ADIV5_DP_VERSION_MASK 0xf000
|
#define ADIV5_DP_VERSION_MASK 0xf000
|
||||||
#define ADIV5_DPv1 0x1000
|
#define ADIV5_DPv1 0x1000
|
||||||
|
@ -49,10 +49,51 @@ static unsigned int make_packet_request(uint8_t RnW, uint16_t addr)
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Provide bare DP access functions without timeout and exception */
|
||||||
|
|
||||||
|
static void dp_line_reset(void)
|
||||||
|
{
|
||||||
|
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||||
|
swd_proc.swdptap_seq_out(0x0FFFFFFF, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dp_write(uint16_t addr, const uint32_t data)
|
||||||
|
{
|
||||||
|
int bank = (addr >> 4) & 0xf;
|
||||||
|
unsigned int request;
|
||||||
|
if (bank)
|
||||||
|
dp_write(ADIV5_DP_SELECT, bank);
|
||||||
|
request = make_packet_request(ADIV5_LOW_WRITE, addr & 0xf);
|
||||||
|
swd_proc.swdptap_seq_out(request, 8);
|
||||||
|
swd_proc.swdptap_seq_in(3);
|
||||||
|
swd_proc.swdptap_seq_out_parity(data, 32);
|
||||||
|
if (bank)
|
||||||
|
dp_write(ADIV5_DP_SELECT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dp_read(uint16_t addr, uint32_t *res)
|
||||||
|
{
|
||||||
|
int bank = (addr >> 4) & 0xf;
|
||||||
|
unsigned int request;
|
||||||
|
if (bank)
|
||||||
|
dp_write(ADIV5_DP_SELECT, bank);
|
||||||
|
request = make_packet_request(ADIV5_LOW_READ, addr & 0xf);
|
||||||
|
swd_proc.swdptap_seq_out(request, 8);
|
||||||
|
swd_proc.swdptap_seq_in(3);
|
||||||
|
if (swd_proc.swdptap_seq_in_parity(res, 32)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (bank)
|
||||||
|
dp_write(ADIV5_DP_SELECT, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try first the dormant to SWD procedure.
|
||||||
|
* If target id given, scan DPs 0 .. 15 on that device and return.
|
||||||
|
* Otherwise
|
||||||
|
*/
|
||||||
int adiv5_swdp_scan(uint32_t targetid)
|
int adiv5_swdp_scan(uint32_t targetid)
|
||||||
{
|
{
|
||||||
uint32_t ack;
|
|
||||||
(void) targetid;
|
|
||||||
target_list_free();
|
target_list_free();
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
if (platform_swdptap_init()) {
|
if (platform_swdptap_init()) {
|
||||||
@ -64,41 +105,90 @@ int adiv5_swdp_scan(uint32_t targetid)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Switch from JTAG to SWD mode */
|
/* DORMANT-> SWD sequence*/
|
||||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 16);
|
|
||||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 18);
|
|
||||||
swd_proc.swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
|
|
||||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 18);
|
/* 128 bit selection alert sequence for SW-DP-V2 */
|
||||||
swd_proc.swdptap_seq_out(0, 16);
|
swd_proc.swdptap_seq_out(0x6209f392, 32);
|
||||||
|
swd_proc.swdptap_seq_out(0x86852d95, 32);
|
||||||
/* Read the SW-DP IDCODE register to syncronise */
|
swd_proc.swdptap_seq_out(0xe3ddafe9, 32);
|
||||||
/* This could be done with adiv_swdp_low_access(), but this doesn't
|
swd_proc.swdptap_seq_out(0x19bc0ea2, 32);
|
||||||
* allow the ack to be checked here. */
|
/* 4 cycle low,
|
||||||
uint32_t request = make_packet_request(ADIV5_LOW_READ, ADIV5_DP_IDCODE);
|
* 0x1a Arm CoreSight SW-DP activation sequence
|
||||||
swd_proc.swdptap_seq_out(request, 8);
|
* 20 bits start of reset another reset sequence*/
|
||||||
ack = swd_proc.swdptap_seq_in(3);
|
swd_proc.swdptap_seq_out(0x1a0, 12);
|
||||||
uint32_t idcode;
|
uint32_t idcode = 0;
|
||||||
if((ack != SWDP_ACK_OK) || swd_proc.swdptap_seq_in_parity(&idcode, 32)) {
|
uint32_t target_id;
|
||||||
DEBUG_WARN("Read SW-DP IDCODE failed %1" PRIx32 "\n", ack);
|
bool is_v2 = true;
|
||||||
return -1;
|
if (!targetid) {
|
||||||
|
/* Try to read ID */
|
||||||
|
dp_line_reset();
|
||||||
|
bool res = dp_read(ADIV5_DP_IDCODE, &idcode);
|
||||||
|
if (res) {
|
||||||
|
is_v2 = false;
|
||||||
|
DEBUG_WARN("Trying old JTAG to SWD sequence\n");
|
||||||
|
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||||
|
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||||
|
swd_proc.swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
|
||||||
|
dp_line_reset();
|
||||||
|
bool res = dp_read(ADIV5_DP_IDCODE, &idcode);
|
||||||
|
if (res) {
|
||||||
|
DEBUG_WARN("No usable DP found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
|
||||||
|
is_v2 = true;
|
||||||
|
bool res = dp_read(ADIV5_DP_TARGETID, &target_id);
|
||||||
|
if (res) {
|
||||||
|
DEBUG_WARN("Read Targetid failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
is_v2 = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target_id = targetid;
|
||||||
}
|
}
|
||||||
|
int nr_dps = (is_v2) ? 16: 1;
|
||||||
|
uint32_t dp_targetid;
|
||||||
|
for (int i = 0; i < nr_dps; i++) {
|
||||||
|
if (is_v2) {
|
||||||
|
dp_line_reset();
|
||||||
|
dp_targetid = (i << 28) | (target_id & 0x0fffffff);
|
||||||
|
dp_write(ADIV5_DP_TARGETSEL, dp_targetid);
|
||||||
|
bool res = dp_read(ADIV5_DP_IDCODE, &idcode);
|
||||||
|
if (res)
|
||||||
|
continue;
|
||||||
|
if (dp_targetid == 0xf1002927) /* Fixme: Handle RP2040 rescue port */
|
||||||
|
continue;
|
||||||
|
DEBUG_WARN("DP %2d IDCODE %08" PRIx32 " TID 0x%08" PRIx32 "\n", i, idcode, dp_targetid);
|
||||||
|
} else {
|
||||||
|
dp_targetid = 0;
|
||||||
|
}
|
||||||
|
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||||
|
if (!dp) { /* calloc failed: heap exhaustion */
|
||||||
|
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dp->idcode = idcode;
|
||||||
|
dp->targetid = dp_targetid;
|
||||||
|
#if HOSTED == 0
|
||||||
|
dp->dp_read = firmware_swdp_read;
|
||||||
|
dp->error = firmware_swdp_error;
|
||||||
|
dp->low_access = firmware_swdp_low_access;
|
||||||
|
dp->abort = firmware_swdp_abort;
|
||||||
|
firmware_swdp_error(dp);
|
||||||
|
#else
|
||||||
|
dp->dp_read = swd_proc->swdp_read;
|
||||||
|
dp->error = swd_proc->swdp_error;
|
||||||
|
dp->low_access = swd_proc->swdp_low_access;
|
||||||
|
dp->abort = swd_proc->swdp_abort;
|
||||||
|
swd_proc->swdp_error();
|
||||||
|
#endif
|
||||||
|
adiv5_dp_init(dp);
|
||||||
|
|
||||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
|
||||||
if (!dp) { /* calloc failed: heap exhaustion */
|
|
||||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dp->idcode = idcode;
|
|
||||||
dp->dp_read = firmware_swdp_read;
|
|
||||||
dp->error = firmware_swdp_error;
|
|
||||||
dp->low_access = firmware_swdp_low_access;
|
|
||||||
dp->abort = firmware_swdp_abort;
|
|
||||||
|
|
||||||
firmware_swdp_error(dp);
|
|
||||||
adiv5_dp_init(dp);
|
|
||||||
return target_list?1:0;
|
return target_list?1:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +207,15 @@ uint32_t firmware_swdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
|||||||
{
|
{
|
||||||
uint32_t err, clr = 0;
|
uint32_t err, clr = 0;
|
||||||
|
|
||||||
|
if ((dp->idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
|
||||||
|
/* On protocoll error target gets deselected.
|
||||||
|
* With DP Change, another target needs selection.
|
||||||
|
* => Reselect with right target! */
|
||||||
|
dp_line_reset();
|
||||||
|
dp_write(ADIV5_DP_TARGETSEL, dp->targetid);
|
||||||
|
uint32_t dummy;
|
||||||
|
dp_read(ADIV5_DP_IDCODE, &dummy);
|
||||||
|
}
|
||||||
err = firmware_swdp_read(dp, ADIV5_DP_CTRLSTAT) &
|
err = firmware_swdp_read(dp, ADIV5_DP_CTRLSTAT) &
|
||||||
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
||||||
ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR);
|
ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user