Add support for the JTAG ICE mkII in ISP mode.

* avrdude.conf.in (jtag2isp): New programmer entry.
* config_gram.y: Add K_JTAG_MKII_ISP.
* jtagmkII.c: Restructure and export some more functions.
* jtagmkII.h: Declare exported functions.
* jtagmkII_private.h: Prepare file to be included in stk500v2.c.
* lexer.l: Add jtagmkii_isp token.
* stk500v2.c: Implement glue to jtagmkII.c.
* stk500v2.h: Declare stk500v2_jtagmkII_initpgm().
* avrdude.1: Document the new programmer support.
* doc/avrdude.texi: (Ditto.)


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@643 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
joerg_wunsch
2006-09-06 20:06:07 +00:00
parent 26952bf8f0
commit f8796c29cc
12 changed files with 391 additions and 68 deletions

View File

@@ -54,6 +54,17 @@
#include "serial.h"
#include "usbdevs.h"
/*
* We need to import enough from the JTAG ICE mkII definitions to be
* able to talk to the ICE, query some parameters etc. The macro
* JTAGMKII_PRIVATE_EXPORTED limits the amount of definitions that
* jtagmkII_private.h will export, so to avoid conflicts with those
* names that are identical to the STK500v2 ones.
*/
#include "jtagmkII.h" // public interfaces from jtagmkII.c
#define JTAGMKII_PRIVATE_EXPORTED
#include "jtagmkII_private.h"
#define STK500V2_XTAL 7372800U
#if 0
@@ -91,7 +102,6 @@ static unsigned long eeprom_pageaddr;
static unsigned int eeprom_pagesize;
static unsigned char command_sequence = 1;
static int is_mk2; /* Is the device an AVRISP mkII? */
static enum
{
@@ -99,6 +109,7 @@ static enum
PGMTYPE_STK500,
PGMTYPE_AVRISP,
PGMTYPE_AVRISP_MKII,
PGMTYPE_JTAGICE_MKII,
}
pgmtype;
@@ -108,6 +119,36 @@ static const char *pgmname[] =
"STK500",
"AVRISP",
"AVRISP mkII",
"JTAG ICE mkII",
};
struct jtagispentry
{
unsigned char cmd;
unsigned short size;
#define SZ_READ_FLASH_EE USHRT_MAX
#define SZ_SPI_MULTI (USHRT_MAX - 1)
};
static struct jtagispentry jtagispcmds[] = {
{ CMD_SET_PARAMETER, 2 },
{ CMD_GET_PARAMETER, 3 },
{ CMD_OSCCAL, 2 },
{ CMD_LOAD_ADDRESS, 2 },
{ CMD_ENTER_PROGMODE_ISP, 2 },
{ CMD_LEAVE_PROGMODE_ISP, 2 },
{ CMD_CHIP_ERASE_ISP, 2 },
{ CMD_PROGRAM_FLASH_ISP, 2 },
{ CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_EEPROM_ISP, 2 },
{ CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
{ CMD_PROGRAM_FUSE_ISP, 3 },
{ CMD_READ_FUSE_ISP, 4 },
{ CMD_PROGRAM_LOCK_ISP, 3 },
{ CMD_READ_LOCK_ISP, 4 },
{ CMD_READ_SIGNATURE_ISP, 4 },
{ CMD_READ_OSCCAL_ISP, 4 },
{ CMD_SPI_MULTI, SZ_SPI_MULTI }
};
static int stk500v2_getparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value);
@@ -118,9 +159,17 @@ static int stk500v2_is_page_empty(unsigned int address, int page_size,
static unsigned int stk500v2_mode_for_pagesize(unsigned int pagesize);
#if defined(HAVE_LIBUSB)
static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v);
#endif
static unsigned short
b2_to_u16(unsigned char *b)
{
unsigned short l;
l = b[0];
l += (unsigned)b[1] << 8;
return l;
}
static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
{
@@ -132,13 +181,74 @@ static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
return 0;
}
static unsigned short get_jtagisp_return_size(unsigned char cmd)
{
int i;
for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
if (jtagispcmds[i].cmd == cmd)
return jtagispcmds[i].size;
return 0;
}
/*
* Send the data as a JTAG ICE mkII encapsulated ISP packet.
* Unlike what AVR067 says, the packet gets a length of our
* response buffer prepended, and replies with RSP_SPI_DATA
* if successful.
*/
static int stk500v2_jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
{
unsigned char *cmdbuf;
int rv;
unsigned short sz;
sz = get_jtagisp_return_size(data[0]);
if (sz == 0) {
fprintf(stderr, "%s: unsupported encapsulated ISP command: %#x\n",
progname, data[0]);
return -1;
}
if (sz == SZ_READ_FLASH_EE) {
/*
* For CMND_READ_FLASH_ISP and CMND_READ_EEPROM_ISP, extract the
* size of the return data from the request. Note that the
* request itself has the size in big endian format, while we are
* supposed to deliver it in little endian.
*/
sz = 3 + (data[1] << 8) + data[2];
} else if (sz == SZ_SPI_MULTI) {
/*
* CMND_SPI_MULTI has the Rx size encoded in its 3rd byte.
*/
sz = 3 + data[2];
}
if ((cmdbuf = malloc(len + 3)) == NULL) {
fprintf(stderr, "%s: out of memory for command packet\n",
progname);
exit(1);
}
cmdbuf[0] = CMND_ISP_PACKET;
cmdbuf[1] = sz & 0xff;
cmdbuf[2] = (sz >> 8) & 0xff;
memcpy(cmdbuf + 3, data, len);
rv = jtagmkII_send(pgm, cmdbuf, len + 3);
free(cmdbuf);
return rv;
}
static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
{
unsigned char buf[275 + 6]; // max MESSAGE_BODY of 275 bytes, 6 bytes overhead
int i;
if (is_mk2)
if (pgmtype == PGMTYPE_AVRISP_MKII)
return stk500v2_send_mk2(pgm, data, len);
else if (pgmtype == PGMTYPE_JTAGICE_MKII)
return stk500v2_jtagmkII_send(pgm, data, len);
buf[0] = MESSAGE_START;
buf[1] = command_sequence;
@@ -184,6 +294,44 @@ static int stk500v2_recv_mk2(PROGRAMMER * pgm, unsigned char msg[],
return rv;
}
static int stk500v2_jtagmkII_recv(PROGRAMMER * pgm, unsigned char msg[],
size_t maxsize)
{
int rv;
unsigned char *jtagmsg;
rv = jtagmkII_recv(pgm, &jtagmsg);
if (rv <= 0) {
fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): error in jtagmkII_recv()\n",
progname);
return -1;
}
if (rv > maxsize) {
fprintf(stderr,
"%s: stk500v2_jtagmkII_recv(): got %u bytes, have only room for %u bytes\n",
progname, (unsigned)rv, maxsize);
rv = maxsize;
}
switch (jtagmsg[0]) {
case RSP_SPI_DATA:
break;
case RSP_FAILED:
fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): failed\n",
progname);
return -1;
case RSP_ILLEGAL_MCU_STATE:
fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): illegal MCU state\n",
progname);
return -1;
default:
fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): unknown status %d\n",
progname, jtagmsg[0]);
return -1;
}
memcpy(msg, jtagmsg + 1, rv - 1);
return 0;
}
static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) {
enum states { sINIT, sSTART, sSEQNUM, sSIZE1, sSIZE2, sTOKEN, sDATA, sCSUM, sDONE } state = sSTART;
int msglen = 0;
@@ -195,8 +343,10 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize)
struct timeval tv;
double tstart, tnow;
if (is_mk2)
if (pgmtype == PGMTYPE_AVRISP_MKII)
return stk500v2_recv_mk2(pgm, msg, maxsize);
else if (pgmtype == PGMTYPE_JTAGICE_MKII)
return stk500v2_jtagmkII_recv(pgm, msg, maxsize);
DEBUG("STK500V2: stk500v2_recv(): ");
@@ -301,6 +451,9 @@ static int stk500v2_getsync(PROGRAMMER * pgm) {
DEBUG("STK500V2: stk500v2_getsync()\n");
if (pgmtype == PGMTYPE_JTAGICE_MKII)
return 0;
retry:
tries++;
@@ -702,7 +855,6 @@ static void stk500v2_disable(PROGRAMMER * pgm)
if (buf[1] != STATUS_CMD_OK) {
fprintf(stderr, "%s: stk500v2_disable(): failed to leave programming mode, got 0x%02x\n",
progname,buf[1]);
exit(1);
}
return;
@@ -769,6 +921,8 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port)
if (pgm->baudrate)
baud = pgm->baudrate;
pgmtype = PGMTYPE_UNKNOWN;
/*
* If the port name starts with "usb", divert the serial routines
* to the USB ones. The serial_open() function for USB overrides
@@ -779,7 +933,7 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port)
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev_frame;
baud = USB_DEVICE_AVRISPMKII;
is_mk2 = 1;
pgmtype = PGMTYPE_AVRISP_MKII;
pgm->set_sck_period = stk500v2_set_sck_period_mk2;
#else
fprintf(stderr, "avrdude was compiled without usb support.\n");
@@ -795,8 +949,6 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port)
*/
stk500v2_drain(pgm, 0);
pgmtype = PGMTYPE_UNKNOWN;
stk500v2_getsync(pgm);
stk500v2_drain(pgm, 0);
@@ -1707,7 +1859,6 @@ double avrispmkIIfreqs[] = {
65.0, 61.9, 59.0, 56.3, 53.6, 51.1
};
#if defined(HAVE_LIBUSB)
static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v)
{
int i;
@@ -1722,7 +1873,6 @@ static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v)
return stk500v2_setparm(pgm, PARAM_SCK_DURATION, i);
}
#endif /* HAVE_LIBUSB */
/*
* Return the "mode" value for the parallel and HVSP modes that
@@ -1837,10 +1987,6 @@ static void stk500v2_display(PROGRAMMER * pgm, char * p)
unsigned char maj, min, hdw, topcard;
const char *topcard_name, *pgmname;
stk500v2_getparm(pgm, PARAM_HW_VER, &hdw);
stk500v2_getparm(pgm, PARAM_SW_MAJOR, &maj);
stk500v2_getparm(pgm, PARAM_SW_MINOR, &min);
switch (pgmtype) {
case PGMTYPE_UNKNOWN: pgmname = "Unknown"; break;
case PGMTYPE_STK500: pgmname = "STK500"; break;
@@ -1848,9 +1994,14 @@ static void stk500v2_display(PROGRAMMER * pgm, char * p)
case PGMTYPE_AVRISP_MKII: pgmname = "AVRISP mkII"; break;
default: pgmname = "None";
}
fprintf(stderr, "%sProgrammer Model: %s\n", p, pgmname);
fprintf(stderr, "%sHardware Version: %d\n", p, hdw);
fprintf(stderr, "%sFirmware Version: %d.%02d\n", p, maj, min);
if (pgmtype != PGMTYPE_JTAGICE_MKII) {
fprintf(stderr, "%sProgrammer Model: %s\n", p, pgmname);
stk500v2_getparm(pgm, PARAM_HW_VER, &hdw);
stk500v2_getparm(pgm, PARAM_SW_MAJOR, &maj);
stk500v2_getparm(pgm, PARAM_SW_MINOR, &min);
fprintf(stderr, "%sHardware Version: %d\n", p, hdw);
fprintf(stderr, "%sFirmware Version: %d.%02d\n", p, maj, min);
}
if (pgmtype == PGMTYPE_STK500) {
stk500v2_getparm(pgm, PARAM_TOPCARD_DETECT, &topcard);
@@ -1874,10 +2025,17 @@ static void stk500v2_display(PROGRAMMER * pgm, char * p)
static void stk500v2_print_parms1(PROGRAMMER * pgm, char * p)
{
unsigned char vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration;
unsigned char vtarget_jtag[4];
stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget);
if (pgmtype == PGMTYPE_JTAGICE_MKII) {
jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget_jtag);
fprintf(stderr, "%sVtarget : %.1f V\n", p,
b2_to_u16(vtarget_jtag) / 1000.0);
} else {
stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget);
fprintf(stderr, "%sVtarget : %.1f V\n", p, vtarget / 10.0);
}
stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration);
fprintf(stderr, "%sVtarget : %.1f V\n", p, vtarget / 10.0);
if (pgmtype == PGMTYPE_STK500) {
stk500v2_getparm(pgm, PARAM_VADJUST, &vadjust);
@@ -1913,7 +2071,7 @@ static void stk500v2_print_parms1(PROGRAMMER * pgm, char * p)
fprintf(stderr, "%.3f %s\n", f, unit);
}
}
if (is_mk2)
if (pgmtype == PGMTYPE_AVRISP_MKII || pgmtype == PGMTYPE_JTAGICE_MKII)
fprintf(stderr, "%sSCK period : %.2f us\n", p,
(float) 1000000 / avrispmkIIfreqs[sck_duration]);
else
@@ -1930,6 +2088,72 @@ static void stk500v2_print_parms(PROGRAMMER * pgm)
}
/*
* Wrapper functions for the JTAG ICE mkII in ISP mode. This mode
* uses the normal JTAG ICE mkII packet stream to communicate with the
* ICE, but then encapsulates AVRISP mkII commands using
* CMND_ISP_PACKET.
*/
/*
* Open a JTAG ICE mkII in ISP mode.
*/
static int stk500v2_jtagmkII_open(PROGRAMMER * pgm, char * port)
{
long baud;
if (verbose >= 2)
fprintf(stderr, "%s: stk500v2_jtagmkII_open()\n", progname);
/*
* The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
* attaching. If the config file or command-line parameters specify
* a higher baud rate, we switch to it later on, after establishing
* the connection with the ICE.
*/
baud = 19200;
/*
* If the port name starts with "usb", divert the serial routines
* to the USB ones. The serial_open() function for USB overrides
* the meaning of the "baud" parameter to be the USB device ID to
* search for.
*/
if (strncmp(port, "usb", 3) == 0) {
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev;
baud = USB_DEVICE_JTAGICEMKII;
#else
fprintf(stderr, "avrdude was compiled without usb support.\n");
return -1;
#endif
}
strcpy(pgm->port, port);
pgm->fd = serial_open(port, baud);
/*
* drain any extraneous input
*/
stk500v2_drain(pgm, 0);
if (jtagmkII_getsync(pgm, EMULATOR_MODE_SPI) != 0) {
fprintf(stderr, "%s: failed to sync with the JTAG ICE mkII in ISP mode\n",
progname);
exit(1);
}
pgmtype = PGMTYPE_JTAGICE_MKII;
if (pgm->bitclock != 0.0) {
if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
return -1;
}
return 0;
}
void stk500v2_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "STK500V2");
@@ -2023,3 +2247,30 @@ void stk500hvsp_initpgm(PROGRAMMER * pgm)
pgm->set_sck_period = stk500v2_set_sck_period;
pgm->page_size = 256;
}
void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "JTAGMKII_ISP");
/*
* mandatory functions
*/
pgm->initialize = stk500v2_initialize;
pgm->display = stk500v2_display;
pgm->enable = stk500v2_enable;
pgm->disable = stk500v2_disable;
pgm->program_enable = stk500v2_program_enable;
pgm->chip_erase = stk500v2_chip_erase;
pgm->cmd = stk500v2_cmd;
pgm->open = stk500v2_jtagmkII_open;
pgm->close = jtagmkII_close;
/*
* optional functions
*/
pgm->paged_write = stk500v2_paged_write;
pgm->paged_load = stk500v2_paged_load;
pgm->print_parms = stk500v2_print_parms;
pgm->set_sck_period = stk500v2_set_sck_period_mk2;
pgm->page_size = 256;
}