Merge pull request #561 from UweBonnes/pc_prog
Command line interaction for pc-hosted platforms.
This commit is contained in:
commit
0b6f393d5b
|
@ -22,6 +22,7 @@
|
|||
#define __GENERAL_H
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define __USE_MINGW_ANSI_STDIO 1
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -44,15 +45,5 @@
|
|||
#undef MAX
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
# define PRI_SIZET PRIu64
|
||||
# else
|
||||
# define PRI_SIZET PRIu32
|
||||
# endif
|
||||
#else
|
||||
# define PRI_SIZET "zu"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -8,4 +8,5 @@ else ifneq (, $(findstring cygwin, $(SYS)))
|
|||
LDFLAGS += -lusb-1.0 -lws2_32
|
||||
endif
|
||||
VPATH += platforms/pc
|
||||
SRC += timing.c \
|
||||
SRC += timing.c cl_utils.c
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
struct ftdi_context *ftdic;
|
||||
|
||||
#include "cl_utils.h"
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
static uint8_t outbuf[BUF_SIZE];
|
||||
static uint16_t bufptr = 0;
|
||||
|
@ -180,29 +182,21 @@ cable_desc_t cable_desc[] = {
|
|||
|
||||
void platform_init(int argc, char **argv)
|
||||
{
|
||||
int err;
|
||||
int c;
|
||||
unsigned index = 0;
|
||||
char *serial = NULL;
|
||||
char * cablename = "ftdi";
|
||||
while((c = getopt(argc, argv, "c:s:")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
cablename = optarg;
|
||||
break;
|
||||
case 's':
|
||||
serial = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BMP_CL_OPTIONS_t cl_opts = {0};
|
||||
cl_opts.opt_idstring = "Blackmagic Debug Probe for FTDI/MPSSE";
|
||||
cl_opts.opt_cable = "ftdi";
|
||||
cl_init(&cl_opts, argc, argv);
|
||||
|
||||
int err;
|
||||
unsigned index = 0;
|
||||
int ret = -1;
|
||||
for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]);
|
||||
index++)
|
||||
if (strcmp(cable_desc[index].name, cablename) == 0)
|
||||
if (strcmp(cable_desc[index].name, cl_opts.opt_cable) == 0)
|
||||
break;
|
||||
|
||||
if (index == sizeof(cable_desc)/sizeof(cable_desc[0])){
|
||||
fprintf(stderr, "No cable matching %s found\n",cablename);
|
||||
fprintf(stderr, "No cable matching %s found\n", cl_opts.opt_cable);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
@ -226,32 +220,42 @@ void platform_init(int argc, char **argv)
|
|||
if((err = ftdi_set_interface(ftdic, active_cable->interface)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_interface: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
goto error_1;
|
||||
}
|
||||
if((err = ftdi_usb_open_desc(
|
||||
ftdic, active_cable->vendor, active_cable->product,
|
||||
active_cable->description, serial)) != 0) {
|
||||
active_cable->description, cl_opts.opt_serial)) != 0) {
|
||||
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
goto error_1;
|
||||
}
|
||||
|
||||
if((err = ftdi_set_latency_timer(ftdic, 1)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_latency_timer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
goto error_2;
|
||||
}
|
||||
if((err = ftdi_set_baudrate(ftdic, 1000000)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_baudrate: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
goto error_2;
|
||||
}
|
||||
if((err = ftdi_write_data_set_chunksize(ftdic, BUF_SIZE)) != 0) {
|
||||
fprintf(stderr, "ftdi_write_data_set_chunksize: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
goto error_2;
|
||||
}
|
||||
assert(gdb_if_init() == 0);
|
||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
||||
ret = cl_execute(&cl_opts);
|
||||
} else {
|
||||
assert(gdb_if_init() == 0);
|
||||
return;
|
||||
}
|
||||
error_2:
|
||||
ftdi_usb_close(ftdic);
|
||||
error_1:
|
||||
ftdi_free(ftdic);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
void platform_srst_set_val(bool assert)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
TARGET=blackmagic_stlinkv2
|
||||
SYS = $(shell $(CC) -dumpmachine)
|
||||
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DSTLINKV2 -DJTAG_HL -DENABLE_DEBUG
|
||||
CFLAGS +=-I ./target
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
||||
LDFLAGS += -lusb-1.0
|
||||
ifneq (, $(findstring mingw, $(SYS)))
|
||||
LDFLAGS += -lws2_32
|
||||
|
@ -9,5 +9,5 @@ else ifneq (, $(findstring cygwin, $(SYS)))
|
|||
LDFLAGS += -lws2_32
|
||||
endif
|
||||
VPATH += platforms/pc
|
||||
SRC += timing.c stlinkv2.c
|
||||
SRC += timing.c stlinkv2.c cl_utils.c
|
||||
OWN_HL = 1
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "cl_utils.h"
|
||||
|
||||
#if !defined(timersub)
|
||||
/* This is a copy from GNU C Library (GNU LGPL 2.1), sys/time.h. */
|
||||
# define timersub(a, b, result) \
|
||||
|
@ -219,6 +221,7 @@ typedef struct {
|
|||
uint8_t ver_swim;
|
||||
uint8_t ver_bridge;
|
||||
uint16_t block_size;
|
||||
bool ap_error;
|
||||
libusb_device_handle *handle;
|
||||
struct libusb_transfer* req_trans;
|
||||
struct libusb_transfer* rep_trans;
|
||||
|
@ -397,7 +400,7 @@ static int send_recv(uint8_t *txbuf, size_t txsize,
|
|||
if (res >0) {
|
||||
int i;
|
||||
uint8_t *p = rxbuf;
|
||||
DEBUG_USB(" Rec (%" PRI_SIZET "/%d)", rxsize, res);
|
||||
DEBUG_USB(" Rec (%zu/%d)", rxsize, res);
|
||||
for (i = 0; i < res && i < 32 ; i++) {
|
||||
if ( i && ((i & 7) == 0))
|
||||
DEBUG_USB(".");
|
||||
|
@ -464,6 +467,7 @@ static int stlink_usb_error_check(uint8_t *data, bool verbose)
|
|||
* Change in error status when reading outside RAM.
|
||||
* This fix allows CDT plugin to visualize memory.
|
||||
*/
|
||||
Stlink.ap_error = true;
|
||||
if (verbose)
|
||||
DEBUG("STLINK_SWD_AP_FAULT\n");
|
||||
return STLINK_ERROR_DP_FAULT;
|
||||
|
@ -685,46 +689,18 @@ static void stlink_resetsys(void)
|
|||
send_recv(cmd, 16, data, 2);
|
||||
}
|
||||
|
||||
void stlink_help(char **argv)
|
||||
{
|
||||
DEBUG("Blackmagic Debug Probe on STM StlinkV2 and 3\n\n");
|
||||
DEBUG("Usage: %s [options]\n", argv[0]);
|
||||
DEBUG("\t-v[1|2]\t\t: Increasing verbosity\n");
|
||||
DEBUG("\t-s \"string\"\t: Use Stlink with (partial) "
|
||||
"serial number \"string\"\n");
|
||||
DEBUG("\t-n\t\t: Exit immediate if no device found\n");
|
||||
DEBUG("\t-h\t\t: This help.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void stlink_init(int argc, char **argv)
|
||||
{
|
||||
BMP_CL_OPTIONS_t cl_opts = {0};
|
||||
cl_opts.opt_idstring = "Blackmagic Debug Probe on StlinkV2/3";
|
||||
cl_init(&cl_opts, argc, argv);
|
||||
libusb_device **devs, *dev;
|
||||
int r;
|
||||
int ret = -1;
|
||||
atexit(exit_function);
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
signal(SIGINT, sigterm_handler);
|
||||
libusb_init(&Stlink.libusb_ctx);
|
||||
char *serial = NULL;
|
||||
int c;
|
||||
bool wait_for_attach = true;
|
||||
while((c = getopt(argc, argv, "ns:v:h")) != -1) {
|
||||
switch(c) {
|
||||
case 'n':
|
||||
wait_for_attach = false;
|
||||
break;
|
||||
case 's':
|
||||
serial = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
if (optarg)
|
||||
debug_level = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
stlink_help(argv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r = libusb_init(NULL);
|
||||
if (r < 0)
|
||||
DEBUG("Failed: %s", libusb_strerror(r));
|
||||
|
@ -792,7 +768,8 @@ void stlink_init(int argc, char **argv)
|
|||
else
|
||||
snprintf(s, 3, "%02x", *p & 0xff);
|
||||
}
|
||||
if (serial && (!strncmp(Stlink.serial, serial, strlen(serial))))
|
||||
if (cl_opts.opt_serial && (!strncmp(Stlink.serial, cl_opts.opt_serial,
|
||||
strlen(cl_opts.opt_serial))))
|
||||
DEBUG("Found ");
|
||||
if (desc.idProduct == PRODUCT_ID_STLINKV2) {
|
||||
DEBUG("STLINKV20 serial %s\n", Stlink.serial);
|
||||
|
@ -818,8 +795,9 @@ void stlink_init(int argc, char **argv)
|
|||
DEBUG("Unknown STLINK variant, serial %s\n", Stlink.serial);
|
||||
}
|
||||
nr_stlinks++;
|
||||
if (serial) {
|
||||
if (!strncmp(Stlink.serial, serial, strlen(serial))) {
|
||||
if (cl_opts.opt_serial) {
|
||||
if (!strncmp(Stlink.serial, cl_opts.opt_serial,
|
||||
strlen(cl_opts.opt_serial))) {
|
||||
break;
|
||||
} else {
|
||||
libusb_close(Stlink.handle);
|
||||
|
@ -833,15 +811,15 @@ void stlink_init(int argc, char **argv)
|
|||
}
|
||||
libusb_free_device_list(devs, 1);
|
||||
if (!Stlink.handle) {
|
||||
if (nr_stlinks && serial) {
|
||||
DEBUG("No Stlink with given serial number %s\n", serial);
|
||||
if (nr_stlinks && cl_opts.opt_serial) {
|
||||
DEBUG("No Stlink with given serial number %s\n", cl_opts.opt_serial);
|
||||
} else if (nr_stlinks > 1) {
|
||||
DEBUG("Multiple Stlinks. Please specify serial number\n");
|
||||
goto error;
|
||||
} else {
|
||||
DEBUG("No Stlink device found!\n");
|
||||
}
|
||||
if (hotplug && wait_for_attach) {
|
||||
if (hotplug && !cl_opts.opt_no_wait) {
|
||||
libusb_hotplug_callback_handle hp;
|
||||
int rc = libusb_hotplug_register_callback
|
||||
(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0,
|
||||
|
@ -853,9 +831,9 @@ void stlink_init(int argc, char **argv)
|
|||
goto error;
|
||||
}
|
||||
DEBUG("Waiting for %sST device%s%s to attach\n",
|
||||
(serial)? "" : "some ",
|
||||
(serial)? " with serial ": "",
|
||||
(serial)? serial: "");
|
||||
(cl_opts.opt_serial)? "" : "some ",
|
||||
(cl_opts.opt_serial)? " with serial ": "",
|
||||
(cl_opts.opt_serial)? cl_opts.opt_serial: "");
|
||||
DEBUG("Terminate with ^C\n");
|
||||
while (has_attached == 0) {
|
||||
rc = libusb_handle_events (NULL);
|
||||
|
@ -923,13 +901,17 @@ void stlink_init(int argc, char **argv)
|
|||
}
|
||||
stlink_leave_state();
|
||||
stlink_resetsys();
|
||||
assert(gdb_if_init() == 0);
|
||||
return;
|
||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
||||
ret = cl_execute(&cl_opts);
|
||||
} else {
|
||||
assert(gdb_if_init() == 0);
|
||||
return;
|
||||
}
|
||||
error_1:
|
||||
libusb_close(Stlink.handle);
|
||||
error:
|
||||
libusb_exit(Stlink.libusb_ctx);
|
||||
exit(-1);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
void stlink_srst_set_val(bool assert)
|
||||
|
@ -1080,6 +1062,8 @@ uint32_t stlink_dp_error(ADIv5_DP_t *dp)
|
|||
dp->fault = 0;
|
||||
if (err)
|
||||
DEBUG("stlink_dp_error %d\n", err);
|
||||
err |= Stlink.ap_error;
|
||||
Stlink.ap_error = false;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1229,7 +1213,7 @@ void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
|||
type = STLINK_DEBUG_READMEM_32BIT;
|
||||
|
||||
}
|
||||
DEBUG_STLINK("%s len %" PRI_SIZET " addr 0x%08" PRIx32 " AP %d : ",
|
||||
DEBUG_STLINK("%s len %zu addr 0x%08" PRIx32 " AP %d : ",
|
||||
CMD, len, src, ap->apsel);
|
||||
uint8_t cmd[16] = {
|
||||
STLINK_DEBUG_COMMAND,
|
||||
|
@ -1259,7 +1243,7 @@ void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
|||
void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len,
|
||||
uint8_t *buffer)
|
||||
{
|
||||
DEBUG_STLINK("Mem Write8 AP %d len %" PRI_SIZET " addr 0x%08" PRIx32 ": ",
|
||||
DEBUG_STLINK("Mem Write8 AP %d len %zu addr 0x%08" PRIx32 ": ",
|
||||
ap->apsel, len, addr);
|
||||
for (size_t t = 0; t < len; t++) {
|
||||
DEBUG_STLINK("%02x", buffer[t]);
|
||||
|
@ -1288,7 +1272,7 @@ void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len,
|
|||
void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len,
|
||||
uint16_t *buffer)
|
||||
{
|
||||
DEBUG_STLINK("Mem Write16 AP %d len %" PRI_SIZET " addr 0x%08" PRIx32 ": ",
|
||||
DEBUG_STLINK("Mem Write16 AP %d len %zu addr 0x%08" PRIx32 ": ",
|
||||
ap->apsel, len, addr);
|
||||
for (size_t t = 0; t < len; t+=2) {
|
||||
DEBUG_STLINK("%04x", buffer[t]);
|
||||
|
@ -1308,7 +1292,7 @@ void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len,
|
|||
void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len,
|
||||
uint32_t *buffer)
|
||||
{
|
||||
DEBUG_STLINK("Mem Write32 AP %d len %" PRI_SIZET " addr 0x%08" PRIx32 ": ",
|
||||
DEBUG_STLINK("Mem Write32 AP %d len %zu addr 0x%08" PRIx32 ": ",
|
||||
ap->apsel, len, addr);
|
||||
for (size_t t = 0; t < len; t+=4) {
|
||||
DEBUG_STLINK("%04x", buffer[t]);
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019
|
||||
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* This file allows pc-hosted BMP platforms to erase and flash a
|
||||
* binary file from the command line.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
|
||||
#include "cl_utils.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#else
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
struct mmap_data {
|
||||
void *data;
|
||||
size_t size;
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
HANDLE hFile;
|
||||
HANDLE hMapFile;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int bmp_mmap(char *file, struct mmap_data *map)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
map->hFile = CreateFile(file, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_ALWAYS, 0, NULL);
|
||||
if (map->hFile == INVALID_HANDLE_VALUE) {
|
||||
DEBUG("Open file %s failed: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
map->size = GetFileSize(map->hFile, NULL);
|
||||
map->hMapFile = CreateFileMapping(
|
||||
map->hFile,
|
||||
NULL, /* default security */
|
||||
PAGE_READONLY , /* read only access */
|
||||
0, /* max. object size high */
|
||||
0, /* max. object size low */
|
||||
NULL); /* name of mapping object */
|
||||
|
||||
if (map->hMapFile == NULL || map->hMapFile == INVALID_HANDLE_VALUE) {
|
||||
DEBUG("Map file %s failed: %s\n", file, strerror(errno));
|
||||
CloseHandle(map->hFile);
|
||||
return -1;
|
||||
}
|
||||
map->data = MapViewOfFile(map->hMapFile, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!map->data) {
|
||||
printf("Could not create file mapping object (%s).\n",
|
||||
strerror(errno));
|
||||
CloseHandle(map->hMapFile);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
map->fd = open(file, O_RDONLY | O_BINARY);
|
||||
if (map->fd < 0) {
|
||||
DEBUG("Open file %s failed: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct stat stat;
|
||||
if (fstat(map->fd, &stat))
|
||||
return -1;
|
||||
map->size = stat.st_size;
|
||||
map->data = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, map->fd, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bmp_munmap(struct mmap_data *map)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
UnmapViewOfFile(map->data);
|
||||
CloseHandle(map->hMapFile);
|
||||
CloseHandle(map->hFile);
|
||||
#else
|
||||
munmap(map->data, map->size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
|
||||
{
|
||||
printf("%s\n\n", opt->opt_idstring);
|
||||
printf("Usage: %s [options]\n", argv[0]);
|
||||
printf("\t-h\t\t: This help.\n");
|
||||
printf("\t-v[1|2]\t\t: Increasing verbosity\n");
|
||||
printf("\t-s \"string\"\t: Use dongle with (partial) "
|
||||
"serial number \"string\"\n");
|
||||
printf("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n");
|
||||
printf("\t-n\t\t: Exit immediate if no device found\n");
|
||||
printf("\tRun mode related options:\n");
|
||||
printf("\t-t\t\t: Scan SWD, with no target found scan jtag and exit\n");
|
||||
printf("\t-V\t\t: Verify flash against binary file\n");
|
||||
printf("\t-r\t\t: Read flash and write to binary file\n");
|
||||
printf("\t\tDefault mode is starting the debug server\n");
|
||||
printf("\tFlash operation modifiers options:\n");
|
||||
printf("\t-a <num>\t: Start flash operation at flash address <num>\n"
|
||||
"\t\t\tDefault start is 0x08000000\n");
|
||||
printf("\t-S <num>\t: Read <num> bytes. Default is until read fails.\n");
|
||||
printf("\t-j\t\t: Use JTAG. SWD is default.\n");
|
||||
printf("\t <file>\t\t: Use (binary) file <file> for flash operation\n"
|
||||
"\t\t\tGiven <file> writes to flash if neither -r or -V is given\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
opt->opt_target_dev = 1;
|
||||
opt->opt_flash_start = 0x08000000;
|
||||
opt->opt_flash_size = 16 * 1024 *1024;
|
||||
while((c = getopt(argc, argv, "hv::s:c:nN:tVta:S:jr")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
if (optarg)
|
||||
opt->opt_cable = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
cl_help(argv, opt);
|
||||
break;
|
||||
case 'v':
|
||||
if (optarg)
|
||||
opt->opt_debuglevel = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'j':
|
||||
opt->opt_usejtag = true;
|
||||
break;
|
||||
case 'n':
|
||||
opt->opt_no_wait = true;
|
||||
break;
|
||||
case 's':
|
||||
if (optarg)
|
||||
opt->opt_serial = optarg;
|
||||
break;
|
||||
case 't':
|
||||
opt->opt_mode = BMP_MODE_TEST;
|
||||
break;
|
||||
case 'V':
|
||||
opt->opt_mode = BMP_MODE_FLASH_VERIFY;
|
||||
break;
|
||||
case 'r':
|
||||
opt->opt_mode = BMP_MODE_FLASH_READ;
|
||||
break;
|
||||
case 'a':
|
||||
if (optarg)
|
||||
opt->opt_flash_start = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'N':
|
||||
if (optarg)
|
||||
opt->opt_target_dev = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'S':
|
||||
if (optarg) {
|
||||
char *endptr;
|
||||
opt->opt_flash_size = strtol(optarg, &endptr, 0);
|
||||
if (endptr) {
|
||||
switch(endptr[0]) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
opt->opt_flash_size *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
opt->opt_flash_size *= 1024 * 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((optind) && argv[optind]) {
|
||||
if (opt->opt_mode == BMP_MODE_DEBUG)
|
||||
opt->opt_mode = BMP_MODE_FLASH_WRITE;
|
||||
opt->opt_flash_file = argv[optind];
|
||||
}
|
||||
/* Checks */
|
||||
if ((opt->opt_flash_file) && (opt->opt_mode == BMP_MODE_TEST)) {
|
||||
printf("Ignoring filename in test mode\n");
|
||||
opt->opt_flash_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int cl_execute(BMP_CL_OPTIONS_t *opt)
|
||||
{
|
||||
int res = -1;
|
||||
int num_targets;
|
||||
if (opt->opt_mode == BMP_MODE_TEST) {
|
||||
printf("Running in Test Mode\n");
|
||||
num_targets = adiv5_swdp_scan();
|
||||
if (num_targets == 0)
|
||||
num_targets = jtag_scan(NULL);
|
||||
if (num_targets)
|
||||
return 0;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
if (opt->opt_usejtag) {
|
||||
num_targets = jtag_scan(NULL);
|
||||
} else {
|
||||
num_targets = adiv5_swdp_scan();
|
||||
}
|
||||
if (!num_targets) {
|
||||
DEBUG("No target found\n");
|
||||
return res;
|
||||
}
|
||||
if (opt->opt_target_dev > num_targets) {
|
||||
DEBUG("Given target nummer %d not available\n", opt->opt_target_dev);
|
||||
return res;
|
||||
}
|
||||
struct target_controller tc = {NULL};
|
||||
target *t = target_attach_n(opt->opt_target_dev, &tc);
|
||||
if (!t) {
|
||||
DEBUG("Can not attach to target %d\n", opt->opt_target_dev);
|
||||
goto target_detach;
|
||||
}
|
||||
int read_file = -1;
|
||||
struct mmap_data map = {0};
|
||||
if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
|
||||
(opt->opt_mode == BMP_MODE_FLASH_VERIFY)) {
|
||||
int mmap_res = bmp_mmap(opt->opt_flash_file, &map);
|
||||
if (mmap_res) {
|
||||
DEBUG("Can not map file: %s. Aborting!\n", strerror(errno));
|
||||
goto target_detach;
|
||||
}
|
||||
} else {
|
||||
/* Open as binary */
|
||||
read_file = open(opt->opt_flash_file, O_CREAT | O_RDWR | O_BINARY,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (read_file == -1) {
|
||||
printf("Error opening flashfile %s for read: %s\n",
|
||||
opt->opt_flash_file, strerror(errno));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (opt->opt_flash_size < map.size)
|
||||
/* restrict to size given on command line */
|
||||
map.size = opt->opt_flash_size;
|
||||
if (opt->opt_mode == BMP_MODE_FLASH_WRITE) {
|
||||
DEBUG("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
|
||||
opt->opt_flash_start);
|
||||
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
||||
map.size);
|
||||
if (erased) {
|
||||
DEBUG("Erased failed!\n");
|
||||
goto free_map;
|
||||
} else {
|
||||
DEBUG("Flashing %zu bytes at 0x%08" PRIx32 "\n",
|
||||
map.size, opt->opt_flash_start);
|
||||
unsigned int flashed = target_flash_write(t, opt->opt_flash_start,
|
||||
map.data, map.size);
|
||||
/* Buffered write cares for padding*/
|
||||
if (flashed) {
|
||||
DEBUG("Flashing failed!\n");
|
||||
} else {
|
||||
DEBUG("Success!\n");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
target_flash_done(t);
|
||||
} else {
|
||||
#define WORKSIZE 1024
|
||||
uint8_t *data = malloc(WORKSIZE);
|
||||
if (!data) {
|
||||
printf("Can not malloc memory for flash read/verify operation\n");
|
||||
return res;
|
||||
}
|
||||
if (opt->opt_mode == BMP_MODE_FLASH_READ)
|
||||
printf("Reading flash from 0x%08" PRIx32 " for %zu"
|
||||
" bytes to %s\n", opt->opt_flash_start, opt->opt_flash_size,
|
||||
opt->opt_flash_file);
|
||||
uint32_t flash_src = opt->opt_flash_start;
|
||||
size_t size = opt->opt_flash_size;
|
||||
int bytes_read = 0;
|
||||
void *flash = map.data;
|
||||
while (size) {
|
||||
int worksize = (size > WORKSIZE) ? WORKSIZE : size;
|
||||
int n_read = target_mem_read(t, data, flash_src, worksize);
|
||||
if (n_read) {
|
||||
if (opt->opt_flash_size == 0) {/* we reached end of flash */
|
||||
printf("Reached end of flash at size %" PRId32 "\n",
|
||||
flash_src - opt->opt_flash_start);
|
||||
break;
|
||||
} else {
|
||||
printf("Read failed at flash address 0x%08" PRIx32 "\n",
|
||||
flash_src);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
bytes_read += worksize;
|
||||
}
|
||||
if (opt->opt_mode == BMP_MODE_FLASH_VERIFY) {
|
||||
int difference = memcmp(data, flash, worksize);
|
||||
if (difference){
|
||||
printf("Verify failed at flash region 0x%08" PRIx32 "\n",
|
||||
flash_src);
|
||||
return -1;
|
||||
}
|
||||
flash += worksize;
|
||||
} else if (read_file != -1) {
|
||||
int written = write(read_file, data, worksize);
|
||||
if (written < worksize) {
|
||||
printf("Read failed at flash region 0x%08" PRIx32 "\n",
|
||||
flash_src);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
flash_src += worksize;
|
||||
size -= worksize;
|
||||
if (size <= 0)
|
||||
res = 0;
|
||||
}
|
||||
if (read_file != -1)
|
||||
close(read_file);
|
||||
printf("Read/Verifed succeeded for %d bytes\n", bytes_read);
|
||||
}
|
||||
target_reset(t);
|
||||
free_map:
|
||||
if (map.size)
|
||||
bmp_munmap(&map);
|
||||
target_detach:
|
||||
if (t)
|
||||
target_detach(t);
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* This file implements the interface to command line command for PC-Hosted
|
||||
* platforms.
|
||||
*/
|
||||
#if !defined(__CL_UTILS_H)
|
||||
#define __CL_UTILS_H
|
||||
|
||||
enum bmp_cl_mode {
|
||||
BMP_MODE_DEBUG,
|
||||
BMP_MODE_TEST,
|
||||
BMP_MODE_FLASH_WRITE,
|
||||
BMP_MODE_FLASH_READ,
|
||||
BMP_MODE_FLASH_VERIFY
|
||||
};
|
||||
|
||||
typedef struct BMP_CL_OPTIONS_s {
|
||||
enum bmp_cl_mode opt_mode;
|
||||
bool opt_usejtag;
|
||||
bool opt_no_wait;
|
||||
char *opt_flash_file;
|
||||
char *opt_serial;
|
||||
char *opt_cable;
|
||||
int opt_debuglevel;
|
||||
int opt_target_dev;
|
||||
uint32_t opt_flash_start;
|
||||
size_t opt_flash_size;
|
||||
char *opt_idstring;
|
||||
}BMP_CL_OPTIONS_t;
|
||||
|
||||
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv);
|
||||
int cl_execute(BMP_CL_OPTIONS_t *opt);
|
||||
#endif
|
|
@ -0,0 +1,766 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2014 Richard Meadows <richardeoin>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* This file implements Atmel SAM D target specific functions for
|
||||
* detecting the device, providing the XML memory map and Flash memory
|
||||
* programming.
|
||||
*
|
||||
* Tested with
|
||||
* * SAMD20E17A (rev C)
|
||||
* * SAMD20J18A (rev B)
|
||||
* * SAMD21J18A (rev B)
|
||||
* *
|
||||
*/
|
||||
/* Refer to the SAM D20 Datasheet:
|
||||
* http://www.atmel.com/Images/Atmel-42129-SAM-D20_Datasheet.pdf
|
||||
* particularly Sections 12. DSU and 20. NVMCTRL
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
#include "cortexm.h"
|
||||
|
||||
static int samd_flash_erase(struct target_flash *t, target_addr addr, size_t len);
|
||||
static int samd_flash_write(struct target_flash *f,
|
||||
target_addr dest, const void *src, size_t len);
|
||||
|
||||
bool samd_cmd_erase_all(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_lock_flash(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_unlock_flash(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_unlock_bootprot(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_lock_bootprot(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_read_userrow(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_serial(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_mbist(target *t, int argc, const char **argv);
|
||||
static bool samd_cmd_ssb(target *t, int argc, const char **argv);
|
||||
|
||||
const struct command_s samd_cmd_list[] = {
|
||||
{"erase_mass", (cmd_handler)samd_cmd_erase_all, "Erase entire flash memory"},
|
||||
{"lock_flash", (cmd_handler)samd_cmd_lock_flash, "Locks flash against spurious commands"},
|
||||
{"unlock_flash", (cmd_handler)samd_cmd_unlock_flash, "Unlocks flash"},
|
||||
{"lock_bootprot", (cmd_handler)samd_cmd_lock_bootprot, "Lock the boot protections to maximum"},
|
||||
{"unlock_bootprot", (cmd_handler)samd_cmd_unlock_bootprot, "Unlock the boot protections to minimum"},
|
||||
{"user_row", (cmd_handler)samd_cmd_read_userrow, "Prints user row from flash"},
|
||||
{"serial", (cmd_handler)samd_cmd_serial, "Prints serial number"},
|
||||
{"mbist", (cmd_handler)samd_cmd_mbist, "Runs the built-in memory test"},
|
||||
{"set_security_bit", (cmd_handler)samd_cmd_ssb, "Sets the Security Bit"},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Non-Volatile Memory Controller (NVMC) Parameters */
|
||||
#define SAMD_ROW_SIZE 256
|
||||
#define SAMD_PAGE_SIZE 64
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Non-Volatile Memory Controller (NVMC) Registers */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define SAMD_NVMC 0x41004000
|
||||
#define SAMD_NVMC_CTRLA (SAMD_NVMC + 0x0)
|
||||
#define SAMD_NVMC_CTRLB (SAMD_NVMC + 0x04)
|
||||
#define SAMD_NVMC_PARAM (SAMD_NVMC + 0x08)
|
||||
#define SAMD_NVMC_INTFLAG (SAMD_NVMC + 0x14)
|
||||
#define SAMD_NVMC_ADDRESS (SAMD_NVMC + 0x1C)
|
||||
|
||||
/* Control A Register (CTRLA) */
|
||||
#define SAMD_CTRLA_CMD_KEY 0xA500
|
||||
#define SAMD_CTRLA_CMD_ERASEROW 0x0002
|
||||
#define SAMD_CTRLA_CMD_WRITEPAGE 0x0004
|
||||
#define SAMD_CTRLA_CMD_ERASEAUXROW 0x0005
|
||||
#define SAMD_CTRLA_CMD_WRITEAUXPAGE 0x0006
|
||||
#define SAMD_CTRLA_CMD_LOCK 0x0040
|
||||
#define SAMD_CTRLA_CMD_UNLOCK 0x0041
|
||||
#define SAMD_CTRLA_CMD_PAGEBUFFERCLEAR 0x0044
|
||||
#define SAMD_CTRLA_CMD_SSB 0x0045
|
||||
#define SAMD_CTRLA_CMD_INVALL 0x0046
|
||||
|
||||
/* Interrupt Flag Register (INTFLAG) */
|
||||
#define SAMD_NVMC_READY (1 << 0)
|
||||
|
||||
/* Non-Volatile Memory Calibration and Auxiliary Registers */
|
||||
#define SAMD_NVM_USER_ROW_LOW 0x00804000
|
||||
#define SAMD_NVM_USER_ROW_HIGH 0x00804004
|
||||
#define SAMD_NVM_CALIBRATION 0x00806020
|
||||
#define SAMD_NVM_SERIAL(n) (0x0080A00C + (0x30 * ((n + 3) / 4)) + \
|
||||
(0x4 * n))
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Device Service Unit (DSU) Registers */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define SAMD_DSU 0x41002000
|
||||
#define SAMD_DSU_EXT_ACCESS (SAMD_DSU + 0x100)
|
||||
#define SAMD_DSU_CTRLSTAT (SAMD_DSU_EXT_ACCESS + 0x0)
|
||||
#define SAMD_DSU_ADDRESS (SAMD_DSU_EXT_ACCESS + 0x4)
|
||||
#define SAMD_DSU_LENGTH (SAMD_DSU_EXT_ACCESS + 0x8)
|
||||
#define SAMD_DSU_DID (SAMD_DSU_EXT_ACCESS + 0x018)
|
||||
#define SAMD_DSU_PID(n) (SAMD_DSU + 0x1FE0 + \
|
||||
(0x4 * (n % 4)) - (0x10 * (n / 4)))
|
||||
#define SAMD_DSU_CID(n) (SAMD_DSU + 0x1FF0 + \
|
||||
(0x4 * (n % 4)))
|
||||
|
||||
/* Control and Status Register (CTRLSTAT) */
|
||||
#define SAMD_CTRL_CHIP_ERASE (1 << 4)
|
||||
#define SAMD_CTRL_MBIST (1 << 3)
|
||||
#define SAMD_CTRL_CRC (1 << 2)
|
||||
#define SAMD_STATUSA_PERR (1 << 12)
|
||||
#define SAMD_STATUSA_FAIL (1 << 11)
|
||||
#define SAMD_STATUSA_BERR (1 << 10)
|
||||
#define SAMD_STATUSA_CRSTEXT (1 << 9)
|
||||
#define SAMD_STATUSA_DONE (1 << 8)
|
||||
#define SAMD_STATUSB_PROT (1 << 16)
|
||||
|
||||
/* Device Identification Register (DID) */
|
||||
#define SAMD_DID_MASK 0xFFBC0000
|
||||
#define SAMD_DID_CONST_VALUE 0x10000000
|
||||
#define SAMD_DID_DEVSEL_MASK 0x0F
|
||||
#define SAMD_DID_DEVSEL_POS 0
|
||||
#define SAMD_DID_REVISION_MASK 0x0F
|
||||
#define SAMD_DID_REVISION_POS 8
|
||||
#define SAMD_DID_SERIES_MASK 0x03
|
||||
#define SAMD_DID_SERIES_POS 16
|
||||
|
||||
/* Peripheral ID */
|
||||
#define SAMD_PID_MASK 0x00F7FFFF
|
||||
#define SAMD_PID_CONST_VALUE 0x0001FCD0
|
||||
|
||||
/* Component ID */
|
||||
#define SAMD_CID_VALUE 0xB105100D
|
||||
|
||||
/**
|
||||
* Reads the SAM D20 Peripheral ID
|
||||
*/
|
||||
uint64_t samd_read_pid(target *t)
|
||||
{
|
||||
uint64_t pid = 0;
|
||||
uint8_t i, j;
|
||||
|
||||
/* Five PID registers to read LSB first */
|
||||
for (i = 0, j = 0; i < 5; i++, j += 8)
|
||||
pid |= (target_mem_read32(t, SAMD_DSU_PID(i)) & 0xFF) << j;
|
||||
|
||||
return pid;
|
||||
}
|
||||
/**
|
||||
* Reads the SAM D20 Component ID
|
||||
*/
|
||||
uint32_t samd_read_cid(target *t)
|
||||
{
|
||||
uint64_t cid = 0;
|
||||
uint8_t i, j;
|
||||
|
||||
/* Four CID registers to read LSB first */
|
||||
for (i = 0, j = 0; i < 4; i++, j += 8)
|
||||
cid |= (target_mem_read32(t, SAMD_DSU_CID(i)) & 0xFF) << j;
|
||||
|
||||
return cid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloads the default cortexm reset function with a version that
|
||||
* removes the target from extended reset where required.
|
||||
*/
|
||||
void samd_reset(target *t)
|
||||
{
|
||||
/**
|
||||
* SRST is not asserted here as it appears to reset the adiv5
|
||||
* logic, meaning that subsequent adiv5_* calls PLATFORM_FATAL_ERROR.
|
||||
*
|
||||
* This is ok as normally you can just connect the debugger and go,
|
||||
* but if that's not possible (protection or SWCLK being used for
|
||||
* something else) then having SWCLK low on reset should get you
|
||||
* debug access (cold-plugging). TODO: Confirm this
|
||||
*
|
||||
* See the SAM D20 datasheet §12.6 Debug Operation for more
|
||||
* details.
|
||||
*
|
||||
* jtagtap_srst(true);
|
||||
* jtagtap_srst(false);
|
||||
*/
|
||||
|
||||
/* Read DHCSR here to clear S_RESET_ST bit before reset */
|
||||
target_mem_read32(t, CORTEXM_DHCSR);
|
||||
|
||||
/* Request system reset from NVIC: SRST doesn't work correctly */
|
||||
/* This could be VECTRESET: 0x05FA0001 (reset only core)
|
||||
* or SYSRESETREQ: 0x05FA0004 (system reset)
|
||||
*/
|
||||
target_mem_write32(t, CORTEXM_AIRCR,
|
||||
CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ);
|
||||
|
||||
/* Exit extended reset */
|
||||
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
|
||||
SAMD_STATUSA_CRSTEXT) {
|
||||
/* Write bit to clear from extended reset */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_CRSTEXT);
|
||||
}
|
||||
|
||||
/* Poll for release from reset */
|
||||
while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST);
|
||||
|
||||
/* Reset DFSR flags */
|
||||
target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL);
|
||||
|
||||
/* Clear any target errors */
|
||||
target_check_error(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloads the default cortexm detached function with a version that
|
||||
* removes the target from extended reset where required.
|
||||
*
|
||||
* Only required for SAM D20 _Revision B_ Silicon
|
||||
*/
|
||||
static void
|
||||
samd20_revB_detach(target *t)
|
||||
{
|
||||
cortexm_detach(t);
|
||||
|
||||
/* ---- Additional ---- */
|
||||
/* Exit extended reset */
|
||||
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
|
||||
SAMD_STATUSA_CRSTEXT) {
|
||||
/* Write bit to clear from extended reset */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
|
||||
SAMD_STATUSA_CRSTEXT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloads the default cortexm halt_resume function with a version
|
||||
* that removes the target from extended reset where required.
|
||||
*
|
||||
* Only required for SAM D20 _Revision B_ Silicon
|
||||
*/
|
||||
static void
|
||||
samd20_revB_halt_resume(target *t, bool step)
|
||||
{
|
||||
cortexm_halt_resume(t, step);
|
||||
|
||||
/* ---- Additional ---- */
|
||||
/* Exit extended reset */
|
||||
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) & SAMD_STATUSA_CRSTEXT) {
|
||||
/* Write bit to clear from extended reset */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
|
||||
SAMD_STATUSA_CRSTEXT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload the default cortexm attach for when the samd is protected.
|
||||
*
|
||||
* If the samd is protected then the default cortexm attach will
|
||||
* fail as the S_HALT bit in the DHCSR will never go high. This
|
||||
* function allows users to attach on a temporary basis so they can
|
||||
* rescue the device.
|
||||
*/
|
||||
bool samd_protected_attach(target *t)
|
||||
{
|
||||
/**
|
||||
* TODO: Notify the user that we're not really attached and
|
||||
* they should issue the 'monitor erase_mass' command to
|
||||
* regain access to the chip.
|
||||
*/
|
||||
|
||||
/* Patch back in the normal cortexm attach for next time */
|
||||
t->attach = cortexm_attach;
|
||||
|
||||
/* Allow attach this time */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the DSU Device Indentification Register to populate a struct
|
||||
* describing the SAM D device.
|
||||
*/
|
||||
struct samd_descr {
|
||||
uint8_t series;
|
||||
char revision;
|
||||
char pin;
|
||||
uint8_t mem;
|
||||
char package[3];
|
||||
};
|
||||
struct samd_descr samd_parse_device_id(uint32_t did)
|
||||
{
|
||||
struct samd_descr samd;
|
||||
memset(samd.package, 0, 3);
|
||||
|
||||
uint8_t series = (did >> SAMD_DID_SERIES_POS)
|
||||
& SAMD_DID_SERIES_MASK;
|
||||
uint8_t revision = (did >> SAMD_DID_REVISION_POS)
|
||||
& SAMD_DID_REVISION_MASK;
|
||||
uint8_t devsel = (did >> SAMD_DID_DEVSEL_POS)
|
||||
& SAMD_DID_DEVSEL_MASK;
|
||||
|
||||
/* Series */
|
||||
switch (series) {
|
||||
case 0: samd.series = 20; break;
|
||||
case 1: samd.series = 21; break;
|
||||
case 2: samd.series = 10; break;
|
||||
case 3: samd.series = 11; break;
|
||||
}
|
||||
/* Revision */
|
||||
samd.revision = 'A' + revision;
|
||||
|
||||
switch (samd.series) {
|
||||
case 20: /* SAM D20 */
|
||||
case 21: /* SAM D21 */
|
||||
switch (devsel / 5) {
|
||||
case 0: samd.pin = 'J'; break;
|
||||
case 1: samd.pin = 'G'; break;
|
||||
case 2: samd.pin = 'E'; break;
|
||||
default: samd.pin = 'u'; break;
|
||||
}
|
||||
samd.mem = 18 - (devsel % 5);
|
||||
break;
|
||||
case 10: /* SAM D10 */
|
||||
case 11: /* SAM D11 */
|
||||
switch (devsel / 3) {
|
||||
case 0: samd.package[0] = 'M'; break;
|
||||
case 1: samd.package[0] = 'S'; samd.package[1] = 'S'; break;
|
||||
}
|
||||
samd.pin = 'D';
|
||||
samd.mem = 14 - (devsel % 3);
|
||||
break;
|
||||
}
|
||||
|
||||
return samd;
|
||||
}
|
||||
|
||||
static void samd_add_flash(target *t, uint32_t addr, size_t length)
|
||||
{
|
||||
struct target_flash *f = calloc(1, sizeof(*f));
|
||||
if (!f) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
f->start = addr;
|
||||
f->length = length;
|
||||
f->blocksize = SAMD_ROW_SIZE;
|
||||
f->erase = samd_flash_erase;
|
||||
f->write = samd_flash_write;
|
||||
f->buf_size = SAMD_PAGE_SIZE;
|
||||
target_add_flash(t, f);
|
||||
}
|
||||
|
||||
char variant_string[60];
|
||||
bool samd_probe(target *t)
|
||||
{
|
||||
uint32_t cid = samd_read_cid(t);
|
||||
uint32_t pid = samd_read_pid(t);
|
||||
|
||||
/* Check the ARM Coresight Component and Perhiperal IDs */
|
||||
if ((cid != SAMD_CID_VALUE) ||
|
||||
((pid & SAMD_PID_MASK) != SAMD_PID_CONST_VALUE))
|
||||
return false;
|
||||
|
||||
/* Read the Device ID */
|
||||
uint32_t did = target_mem_read32(t, SAMD_DSU_DID);
|
||||
|
||||
/* If the Device ID matches */
|
||||
if ((did & SAMD_DID_MASK) != SAMD_DID_CONST_VALUE)
|
||||
return false;
|
||||
|
||||
uint32_t ctrlstat = target_mem_read32(t, SAMD_DSU_CTRLSTAT);
|
||||
struct samd_descr samd = samd_parse_device_id(did);
|
||||
|
||||
/* Protected? */
|
||||
bool protected = (ctrlstat & SAMD_STATUSB_PROT);
|
||||
|
||||
/* Part String */
|
||||
if (protected) {
|
||||
snprintf(variant_string, sizeof(variant_string),
|
||||
"Atmel SAMD%d%c%dA%s (rev %c) (PROT=1)",
|
||||
samd.series, samd.pin, samd.mem,
|
||||
samd.package, samd.revision);
|
||||
} else {
|
||||
snprintf(variant_string, sizeof(variant_string),
|
||||
"Atmel SAMD%d%c%dA%s (rev %c)",
|
||||
samd.series, samd.pin, samd.mem,
|
||||
samd.package, samd.revision);
|
||||
}
|
||||
|
||||
/* Setup Target */
|
||||
t->driver = variant_string;
|
||||
t->reset = samd_reset;
|
||||
|
||||
if (samd.series == 20 && samd.revision == 'B') {
|
||||
/**
|
||||
* These functions check for and
|
||||
* extended reset. Appears to be
|
||||
* related to Errata 35.4.1 ref 12015
|
||||
*/
|
||||
t->detach = samd20_revB_detach;
|
||||
t->halt_resume = samd20_revB_halt_resume;
|
||||
}
|
||||
if (protected) {
|
||||
/**
|
||||
* Overload the default cortexm attach
|
||||
* for when the samd is protected.
|
||||
* This function allows users to
|
||||
* attach on a temporary basis so they
|
||||
* can rescue the device.
|
||||
*/
|
||||
t->attach = samd_protected_attach;
|
||||
}
|
||||
|
||||
target_add_ram(t, 0x20000000, 0x8000);
|
||||
samd_add_flash(t, 0x00000000, 0x40000);
|
||||
target_add_commands(t, samd_cmd_list, "SAMD");
|
||||
|
||||
/* If we're not in reset here */
|
||||
if (!platform_srst_get_val()) {
|
||||
/* We'll have to release the target from
|
||||
* extended reset to make attach possible */
|
||||
if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) &
|
||||
SAMD_STATUSA_CRSTEXT) {
|
||||
|
||||
/* Write bit to clear from extended reset */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
|
||||
SAMD_STATUSA_CRSTEXT);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary (until next reset) flash memory locking / unlocking
|
||||
*/
|
||||
static void samd_lock_current_address(target *t)
|
||||
{
|
||||
/* Issue the unlock command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_LOCK);
|
||||
}
|
||||
static void samd_unlock_current_address(target *t)
|
||||
{
|
||||
/* Issue the unlock command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_UNLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase flash row by row
|
||||
*/
|
||||
static int samd_flash_erase(struct target_flash *f, target_addr addr, size_t len)
|
||||
{
|
||||
target *t = f->t;
|
||||
while (len) {
|
||||
/* Write address of first word in row to erase it */
|
||||
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
|
||||
target_mem_write32(t, SAMD_NVMC_ADDRESS, addr >> 1);
|
||||
|
||||
/* Unlock */
|
||||
samd_unlock_current_address(t);
|
||||
|
||||
/* Issue the erase command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEROW);
|
||||
/* Poll for NVM Ready */
|
||||
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
|
||||
if (target_check_error(t))
|
||||
return -1;
|
||||
|
||||
/* Lock */
|
||||
samd_lock_current_address(t);
|
||||
|
||||
addr += f->blocksize;
|
||||
len -= f->blocksize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write flash page by page
|
||||
*/
|
||||
static int samd_flash_write(struct target_flash *f,
|
||||
target_addr dest, const void *src, size_t len)
|
||||
{
|
||||
target *t = f->t;
|
||||
|
||||
/* Write within a single page. This may be part or all of the page */
|
||||
target_mem_write(t, dest, src, len);
|
||||
|
||||
/* Unlock */
|
||||
samd_unlock_current_address(t);
|
||||
|
||||
/* Issue the write page command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE);
|
||||
|
||||
/* Poll for NVM Ready */
|
||||
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
|
||||
if (target_check_error(t))
|
||||
return -1;
|
||||
|
||||
/* Lock */
|
||||
samd_lock_current_address(t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the Device Service Unit to erase the entire flash
|
||||
*/
|
||||
bool samd_cmd_erase_all(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
/* Clear the DSU status bits */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT,
|
||||
SAMD_STATUSA_DONE | SAMD_STATUSA_PERR |
|
||||
SAMD_STATUSA_FAIL);
|
||||
|
||||
/* Erase all */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_CHIP_ERASE);
|
||||
|
||||
/* Poll for DSU Ready */
|
||||
uint32_t status;
|
||||
while (((status = target_mem_read32(t, SAMD_DSU_CTRLSTAT)) &
|
||||
(SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0)
|
||||
if (target_check_error(t))
|
||||
return false;
|
||||
|
||||
/* Test the protection error bit in Status A */
|
||||
if (status & SAMD_STATUSA_PERR) {
|
||||
tc_printf(t, "Erase failed due to a protection error.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Test the fail bit in Status A */
|
||||
if (status & SAMD_STATUSA_FAIL) {
|
||||
tc_printf(t, "Erase failed.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
tc_printf(t, "Erase successful!\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the NVM region lock bits in the User Row. This value is read
|
||||
* at startup as the default value for the lock bits, and hence does
|
||||
* not take effect until a reset.
|
||||
*
|
||||
* 0x0000 = Lock, 0xFFFF = Unlock (default)
|
||||
*/
|
||||
static bool samd_set_flashlock(target *t, uint16_t value, const char **argv)
|
||||
{
|
||||
(void)argv;
|
||||
uint32_t high = target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH);
|
||||
uint32_t low = target_mem_read32(t, SAMD_NVM_USER_ROW_LOW);
|
||||
|
||||
/* Write address of a word in the row to erase it */
|
||||
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
|
||||
target_mem_write32(t, SAMD_NVMC_ADDRESS, SAMD_NVM_USER_ROW_LOW >> 1);
|
||||
|
||||
/* Issue the erase command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEAUXROW);
|
||||
|
||||
/* Poll for NVM Ready */
|
||||
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
|
||||
if (target_check_error(t))
|
||||
return -1;
|
||||
|
||||
/* Modify the high byte of the user row */
|
||||
high = (high & 0x0000FFFF) | ((value << 16) & 0xFFFF0000);
|
||||
|
||||
/* Write back */
|
||||
target_mem_write32(t, SAMD_NVM_USER_ROW_LOW, low);
|
||||
target_mem_write32(t, SAMD_NVM_USER_ROW_HIGH, high);
|
||||
|
||||
/* Issue the page write command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEAUXPAGE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool samd_cmd_lock_flash(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return samd_set_flashlock(t, 0x0000, NULL);
|
||||
}
|
||||
|
||||
static bool samd_cmd_unlock_flash(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return samd_set_flashlock(t, 0xFFFF, NULL);
|
||||
}
|
||||
|
||||
static bool samd_set_bootprot(target *t, uint16_t value, const char **argv)
|
||||
{
|
||||
(void)argv;
|
||||
uint32_t high = target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH);
|
||||
uint32_t low = target_mem_read32(t, SAMD_NVM_USER_ROW_LOW);
|
||||
|
||||
/* Write address of a word in the row to erase it */
|
||||
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
|
||||
target_mem_write32(t, SAMD_NVMC_ADDRESS, SAMD_NVM_USER_ROW_LOW >> 1);
|
||||
|
||||
/* Issue the erase command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_ERASEAUXROW);
|
||||
|
||||
/* Poll for NVM Ready */
|
||||
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
|
||||
if (target_check_error(t))
|
||||
return -1;
|
||||
|
||||
/* Modify the low word of the user row */
|
||||
low = (low & 0xFFFFFFF8) | ((value << 0 ) & 0x00000007);
|
||||
|
||||
/* Write back */
|
||||
target_mem_write32(t, SAMD_NVM_USER_ROW_LOW, low);
|
||||
target_mem_write32(t, SAMD_NVM_USER_ROW_HIGH, high);
|
||||
|
||||
/* Issue the page write command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEAUXPAGE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool samd_cmd_lock_bootprot(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return samd_set_bootprot(t, 0, NULL);
|
||||
}
|
||||
|
||||
static bool samd_cmd_unlock_bootprot(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return samd_set_bootprot(t, 7, NULL);
|
||||
}
|
||||
|
||||
static bool samd_cmd_read_userrow(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
tc_printf(t, "User Row: 0x%08x%08x\n",
|
||||
target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH),
|
||||
target_mem_read32(t, SAMD_NVM_USER_ROW_LOW));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the 128-bit serial number from the NVM
|
||||
*/
|
||||
static bool samd_cmd_serial(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
tc_printf(t, "Serial Number: 0x");
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
tc_printf(t, "%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i)));
|
||||
}
|
||||
|
||||
tc_printf(t, "\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size (in bytes) of the current SAM D20's flash memory.
|
||||
*/
|
||||
static uint32_t samd_flash_size(target *t)
|
||||
{
|
||||
/* Read the Device ID */
|
||||
uint32_t did = target_mem_read32(t, SAMD_DSU_DID);
|
||||
|
||||
/* Mask off the device select bits */
|
||||
uint8_t devsel = did & SAMD_DID_DEVSEL_MASK;
|
||||
|
||||
/* Shift the maximum flash size (256KB) down as appropriate */
|
||||
return (0x40000 >> (devsel % 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the Memory Built In Self Test (MBIST)
|
||||
*/
|
||||
static bool samd_cmd_mbist(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
/* Write the memory parameters to the DSU */
|
||||
target_mem_write32(t, SAMD_DSU_ADDRESS, 0);
|
||||
target_mem_write32(t, SAMD_DSU_LENGTH, samd_flash_size(t));
|
||||
|
||||
/* Clear the fail bit */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_FAIL);
|
||||
|
||||
/* Write the MBIST command */
|
||||
target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_MBIST);
|
||||
|
||||
/* Poll for DSU Ready */
|
||||
uint32_t status;
|
||||
while (((status = target_mem_read32(t, SAMD_DSU_CTRLSTAT)) &
|
||||
(SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0)
|
||||
if (target_check_error(t))
|
||||
return false;
|
||||
|
||||
/* Test the protection error bit in Status A */
|
||||
if (status & SAMD_STATUSA_PERR) {
|
||||
tc_printf(t, "MBIST not run due to protection error.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Test the fail bit in Status A */
|
||||
if (status & SAMD_STATUSA_FAIL) {
|
||||
tc_printf(t, "MBIST Fail @ 0x%08x\n",
|
||||
target_mem_read32(t, SAMD_DSU_ADDRESS));
|
||||
} else {
|
||||
tc_printf(t, "MBIST Passed!\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Sets the security bit
|
||||
*/
|
||||
static bool samd_cmd_ssb(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
/* Issue the ssb command */
|
||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_SSB);
|
||||
|
||||
/* Poll for NVM Ready */
|
||||
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
|
||||
if (target_check_error(t))
|
||||
return -1;
|
||||
|
||||
tc_printf(t, "Set the security bit! "
|
||||
"You will need to issue 'monitor erase_mass' to clear this.\n");
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
info mem
|
||||
quit
|
|
@ -489,11 +489,13 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
|
|||
}
|
||||
/* Probe for APs on this DP */
|
||||
uint32_t last_base = 0;
|
||||
for(int i = 0; i < 256; i++) {
|
||||
int void_aps = 0;
|
||||
for(int i = 0; (i < 256) && (void_aps < 8); i++) {
|
||||
ADIv5_AP_t *ap = NULL;
|
||||
if (adiv5_ap_setup(i))
|
||||
ap = adiv5_new_ap(dp, i);
|
||||
if (ap == NULL) {
|
||||
void_aps++;
|
||||
adiv5_ap_cleanup(i);
|
||||
if (i == 0)
|
||||
return;
|
||||
|
|
|
@ -686,7 +686,10 @@ static int efm32_flash_erase(struct target_flash *f, target_addr addr, size_t le
|
|||
}
|
||||
|
||||
addr += f->blocksize;
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -829,7 +832,7 @@ static bool efm32_cmd_efm_info(target *t, int argc, const char **argv)
|
|||
|
||||
if (di_version == 2) {
|
||||
efm32_v2_di_miscchip_t miscchip = efm32_v2_read_miscchip(t, di_version);
|
||||
efm32_v2_di_pkgtype_t const* pkgtype;
|
||||
efm32_v2_di_pkgtype_t const* pkgtype = NULL;
|
||||
efm32_v2_di_tempgrade_t const* tempgrade;
|
||||
|
||||
for (size_t i = 0; i < (sizeof(efm32_v2_di_pkgtypes) /
|
||||
|
|
|
@ -310,7 +310,10 @@ static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t l
|
|||
while (len) {
|
||||
if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL)) {
|
||||
/* Different targets have different flash erase sizes */
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
addr += f->blocksize;
|
||||
} else {
|
||||
return 1;
|
||||
|
@ -345,7 +348,10 @@ static int kl_gen_flash_write(struct target_flash *f,
|
|||
|
||||
while (len) {
|
||||
if (kl_gen_command(f->t, write_cmd, dest, src)) {
|
||||
len -= kf->write_len;
|
||||
if (len > kf->write_len)
|
||||
len -= kf->write_len;
|
||||
else
|
||||
len = 0;
|
||||
dest += kf->write_len;
|
||||
src += kf->write_len;
|
||||
} else {
|
||||
|
|
|
@ -119,8 +119,10 @@ int lmi_flash_erase(struct target_flash *f, target_addr addr, size_t len)
|
|||
|
||||
if (target_check_error(t))
|
||||
return -1;
|
||||
|
||||
len -= BLOCK_SIZE;
|
||||
if (len > BLOCK_SIZE)
|
||||
len -= BLOCK_SIZE;
|
||||
else
|
||||
len = 0;
|
||||
addr += BLOCK_SIZE;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -267,7 +267,10 @@ static int msp432_flash_erase(struct target_flash *f, target_addr addr, size_t l
|
|||
|
||||
/* update len and addr */
|
||||
len -= f->blocksize;
|
||||
addr += f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -295,7 +298,7 @@ static int msp432_flash_write(struct target_flash *f, target_addr dest,
|
|||
regs[1] = dest; // Flash address to be write to in R1
|
||||
regs[2] = len; // Size of buffer to be flashed in R2
|
||||
|
||||
DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08" PRI_SIZET "\n", dest, len);
|
||||
DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08zu\n", dest, len);
|
||||
/* Call ROM */
|
||||
msp432_call_ROM(t, mf->FlashCtl_programMemory, regs);
|
||||
|
||||
|
|
|
@ -180,7 +180,10 @@ static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t le
|
|||
return -1;
|
||||
|
||||
addr += f->blocksize;
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Return to read-only */
|
||||
|
|
|
@ -308,7 +308,10 @@ static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len
|
|||
if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg))
|
||||
return -1;
|
||||
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
chunk += 8;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -393,7 +393,10 @@ sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len)
|
|||
if (sam4l_flash_command(t, page, FLASH_CMD_EP)) {
|
||||
return -1;
|
||||
}
|
||||
len -= SAM4L_PAGE_SIZE;
|
||||
if (len > SAM4L_PAGE_SIZE)
|
||||
len -= SAM4L_PAGE_SIZE;
|
||||
else
|
||||
len = 0;
|
||||
addr += SAM4L_PAGE_SIZE;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -598,7 +598,10 @@ static int samd_flash_erase(struct target_flash *f, target_addr addr, size_t len
|
|||
samd_lock_current_address(t);
|
||||
|
||||
addr += f->blocksize;
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -210,8 +210,10 @@ static int stm32f1_flash_erase(struct target_flash *f,
|
|||
DEBUG("stm32f1 flash erase: comm error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
addr += f->blocksize;
|
||||
}
|
||||
|
||||
|
|
|
@ -411,7 +411,10 @@ static int stm32f4_flash_erase(struct target_flash *f, target_addr addr,
|
|||
DEBUG("stm32f4 flash erase: comm error\n");
|
||||
return -1;
|
||||
}
|
||||
len -= f->blocksize;
|
||||
if (len > f->blocksize)
|
||||
len -= f->blocksize;
|
||||
else
|
||||
len = 0;
|
||||
sector++;
|
||||
if ((sf->bank_split) && (sector == sf->bank_split))
|
||||
sector = 16;
|
||||
|
|
|
@ -377,8 +377,10 @@ static int stm32lx_nvm_prog_erase(struct target_flash* f,
|
|||
while (len > 0) {
|
||||
/* Write first word of page to 0 */
|
||||
target_mem_write32(t, addr, 0);
|
||||
|
||||
len -= page_size;
|
||||
if (len > page_size)
|
||||
len -= page_size;
|
||||
else
|
||||
len = 0;
|
||||
addr += page_size;
|
||||
}
|
||||
|
||||
|
@ -439,7 +441,6 @@ static int stm32lx_nvm_prog_write(struct target_flash *f,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Erase a region of data flash using operations through the debug
|
||||
interface . The flash is erased for all pages from addr to
|
||||
addr+len, inclusive, on a word boundary. NVM register file
|
||||
|
@ -471,7 +472,10 @@ static int stm32lx_nvm_data_erase(struct target_flash *f,
|
|||
/* Write first word of page to 0 */
|
||||
target_mem_write32(t, addr, 0);
|
||||
|
||||
len -= page_size;
|
||||
if (len > page_size)
|
||||
len -= page_size;
|
||||
else
|
||||
len = 0;
|
||||
addr += page_size;
|
||||
}
|
||||
|
||||
|
|
|
@ -425,8 +425,10 @@ static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t
|
|||
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
|
||||
if(target_check_error(t))
|
||||
return -1;
|
||||
|
||||
len -= blocksize;
|
||||
if (len > blocksize)
|
||||
len -= blocksize;
|
||||
else
|
||||
len = 0;
|
||||
addr += blocksize;
|
||||
page++;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue