From 9839579e66946bdf32423fe92660b86a50b057b6 Mon Sep 17 00:00:00 2001 From: joerg_wunsch Date: Tue, 10 May 2005 19:53:56 +0000 Subject: [PATCH] Oops, more files I forgot to add during the last commit. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@453 81a1dc3b-b13d-400b-aceb-764788c761c2 --- jtagmkII.c | 1833 ++++++++++++++++++++++++++++++++++++++++++++ jtagmkII.h | 28 + jtagmkII_private.h | 296 +++++++ 3 files changed, 2157 insertions(+) create mode 100644 jtagmkII.c create mode 100644 jtagmkII.h create mode 100644 jtagmkII_private.h diff --git a/jtagmkII.c b/jtagmkII.c new file mode 100644 index 00000000..dca287a7 --- /dev/null +++ b/jtagmkII.c @@ -0,0 +1,1833 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2005 Joerg Wunsch + * + * Derived from stk500 code which is: + * Copyright (C) 2002-2004 Brian S. Dean + * Copyright (C) 2005 Erik Walthinsen + * + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id$ */ + +/* + * avrdude interface for Atmel JTAG ICE mkII programmer + */ + +#include "ac_cfg.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "avr.h" +#include "crc16.h" +#include "pgm.h" +#include "jtagmkII_private.h" +#include "serial.h" + + +extern int verbose; +extern char * progname; +extern int do_cycles; + +/* + * XXX There should really be a programmer-specific private data + * pointer in struct PROGRAMMER. + */ +static unsigned short command_sequence; /* Next cmd seqno to issue. */ + +/* + * See jtagmkII_read_byte() for an explanation of the flash and + * EEPROM page caches. + */ +static unsigned char *flash_pagecache; +static unsigned long flash_pageaddr; +static unsigned int flash_pagesize; + +static unsigned char *eeprom_pagecache; +static unsigned long eeprom_pageaddr; +static unsigned int eeprom_pagesize; + +static int prog_enabled; /* Cached value of PROGRAMMING status. */ +static unsigned char serno[6]; /* JTAG ICE serial number. */ +/* + * The OCDEN fuse is bit 7 of the high fuse (hfuse). In order to + * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, we need to + * enable on-chip debugging, as these memory types are apparently + * emulated by running MCU instructions on the target MCU. We cache + * the original value here, so it can be restored before exiting. + * User-requested hfuse updates will always mask out the OCDEN fuse + * then, only updating the cached copy. + * + * OCDEN should probably rather be defined via the configuration, but + * if this ever changes to a different fuse byte for one MCU, quite + * some code here needs to be generalized anyway. + */ +#define OCDEN (1 << 7) +static unsigned char hfuse_backup; +static int internal_hfuse_handling; + +static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char * value); +static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char data); +static int jtagmkII_set_sck_period(PROGRAMMER * pgm, double v); +static int jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm, + unsigned char * value); +static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm, + unsigned char * value); +static void jtagmkII_print_parms1(PROGRAMMER * pgm, char * p); + +static unsigned long +b4_to_u32(unsigned char *b) +{ + unsigned long l; + l = b[0]; + l += b[1] << 8; + l += b[2] << 16; + l += b[3] << 24; + + return l; +} + +static void +u32_to_b4(unsigned char *b, unsigned long l) +{ + b[0] = l & 0xff; + b[1] = (l >> 8) & 0xff; + b[2] = (l >> 16) & 0xff; + b[3] = (l >> 24) & 0xff; +} + +static unsigned short +b2_to_u16(unsigned char *b) +{ + unsigned short l; + l = b[0]; + l += b[1] << 8; + + return l; +} + +static void +u16_to_b2(unsigned char *b, unsigned short l) +{ + b[0] = l & 0xff; + b[1] = (l >> 8) & 0xff; +} + +static void jtagmkII_print_memory(unsigned char *b, size_t s) +{ + int i; + + if (s < 2) + return; + + for (i = 0; i < s - 1; i++) { + fprintf(stderr, "0x%02x ", b[i + 1]); + if (i % 16 == 15) + putc('\n', stderr); + else + putc(' ', stderr); + } + if (i % 16 != 0) + putc('\n', stderr); +} + +static void jtagmkII_prmsg(PROGRAMMER * pgm, unsigned char * data, size_t len) +{ + int i; + + if (verbose >= 4) { + fprintf(stderr, "Raw message:\n"); + + for (i = 0; i < len; i++) { + fprintf(stderr, "0x%02x", data[i]); + if (i % 16 == 15) + putc('\n', stderr); + else + putchar(' '); + } + if (i % 16 != 0) + putc('\n', stderr); + } + + switch (data[0]) { + case RSP_OK: + fprintf(stderr, "OK\n"); + break; + + case RSP_FAILED: + fprintf(stderr, "FAILED\n"); + break; + + case RSP_ILLEGAL_BREAKPOINT: + fprintf(stderr, "Illegal breakpoint\n"); + break; + + case RSP_ILLEGAL_COMMAND: + fprintf(stderr, "Illegal command\n"); + break; + + case RSP_ILLEGAL_EMULATOR_MODE: + fprintf(stderr, "Illegal emulator mode"); + if (len > 1) + switch (data[1]) { + case EMULATOR_MODE_DEBUGWIRE: fprintf(stderr, ": DebugWire"); break; + case EMULATOR_MODE_JTAG: fprintf(stderr, ": JTAG"); break; + case EMULATOR_MODE_UNKNOWN: fprintf(stderr, ": Unknown"); break; + case EMULATOR_MODE_SPI: fprintf(stderr, ": SPI"); break; + } + putc('\n', stderr); + break; + + case RSP_ILLEGAL_JTAG_ID: + fprintf(stderr, "Illegal JTAG ID\n"); + break; + + case RSP_ILLEGAL_MCU_STATE: + fprintf(stderr, "Illegal MCU state"); + if (len > 1) + switch (data[1]) { + case STOPPED: fprintf(stderr, ": Stopped"); break; + case RUNNING: fprintf(stderr, ": Running"); break; + case PROGRAMMING: fprintf(stderr, ": Programming"); break; + } + putc('\n', stderr); + break; + + case RSP_ILLEGAL_MEMORY_TYPE: + fprintf(stderr, "Illegal memory type\n"); + break; + + case RSP_ILLEGAL_MEMORY_RANGE: + fprintf(stderr, "Illegal memory range\n"); + break; + + case RSP_ILLEGAL_PARAMETER: + fprintf(stderr, "Illegal parameter\n"); + break; + + case RSP_ILLEGAL_POWER_STATE: + fprintf(stderr, "Illegal power state\n"); + break; + + case RSP_ILLEGAL_VALUE: + fprintf(stderr, "Illegal value\n"); + break; + + case RSP_NO_TARGET_POWER: + fprintf(stderr, "No target power\n"); + break; + + case RSP_SIGN_ON: + fprintf(stderr, "Sign-on succeeded\n"); + /* Sign-on data will be printed below anyway. */ + break; + + case RSP_MEMORY: + fprintf(stderr, "memory contents:\n"); + jtagmkII_print_memory(data, len); + break; + + case RSP_PARAMETER: + fprintf(stderr, "parameter values:\n"); + jtagmkII_print_memory(data, len); + break; + + case RSP_SPI_DATA: + fprintf(stderr, "SPI data returned:\n"); + for (i = 1; i < len; i++) + fprintf(stderr, "0x%02x ", data[i]); + putc('\n', stderr); + break; + + case EVT_BREAK: + fprintf(stderr, "BREAK event"); + if (len >= 6) { + fprintf(stderr, ", PC = 0x%lx, reason ", b4_to_u32(data + 1)); + switch (data[5]) { + case 0x00: + fprintf(stderr, "unspecified"); + break; + case 0x01: + fprintf(stderr, "program break"); + break; + case 0x02: + fprintf(stderr, "data break PDSB"); + break; + case 0x03: + fprintf(stderr, "data break PDMSB"); + break; + default: + fprintf(stderr, "unknown: 0x%02x", data[5]); + } + } + putc('\n', stderr); + break; + + default: + fprintf(stderr, "unknown message 0x%02x\n", data[0]); + } + + putc('\n', stderr); +} + + +static int jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len) +{ + unsigned char *buf; + + if (verbose >= 3) + fprintf(stderr, "\n%s: jtagmkII_send(): sending %d bytes\n", + progname, len); + + if ((buf = malloc(len + 10)) == NULL) + { + fprintf(stderr, "%s: jtagmkII_send(): out of memory", + progname); + return -1; + } + + buf[0] = MESSAGE_START; + u16_to_b2(buf + 1, command_sequence); + u32_to_b4(buf + 3, len); + buf[7] = TOKEN; + memcpy(buf + 8, data, len); + + crcappend(buf, len + 8); + + if (serial_send(pgm->fd, buf, len + 10) != 0) { + fprintf(stderr, + "%s: jtagmkII_send(): failed to send command to serial port\n", + progname); + exit(1); + } + + free(buf); + + return 0; +} + + +static int jtagmkII_drain(PROGRAMMER * pgm, int display) +{ + return serial_drain(pgm->fd, display); +} + + +/* + * Receive one frame, return it in *msg. Received sequence number is + * returned in seqno. Any valid frame will be returned, regardless + * whether it matches the expected sequence number, including event + * notification frames (seqno == 0xffff). + * + * Caller must eventually free the buffer. + */ +static int jtagmkII_recv_frame(PROGRAMMER * pgm, unsigned char **msg, + unsigned short * seqno) { + enum states { sSTART, + /* NB: do NOT change the sequence of the following: */ + sSEQNUM1, sSEQNUM2, + sSIZE1, sSIZE2, sSIZE3, sSIZE4, + sTOKEN, + sDATA, + sCSUM1, sCSUM2, + /* end NB */ + sDONE + } state = sSTART; + unsigned long msglen = 0, l = 0; + int headeridx = 0; + int timeout = 0; + int ignorpkt = 0; + int rv; + unsigned char c, *buf = NULL, header[8]; + unsigned short r_seqno = 0; + unsigned short checksum = 0; + + struct timeval tv; + double timeoutval = 5; /* seconds */ + double tstart, tnow; + + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_recv():\n", progname); + + gettimeofday(&tv, NULL); + tstart = tv.tv_sec; + + while ( (state != sDONE ) && (!timeout) ) { + if (state == sDATA) { + rv = 0; + if (ignorpkt) { + /* skip packet's contents */ + for(l = 0; l < msglen; l++) + rv += serial_recv(pgm->fd, &c, 1); + } else { + rv += serial_recv(pgm->fd, buf + 8, msglen); + } + if (rv != 0) { + timedout: + /* timeout in receive */ + if (verbose > 1) + fprintf(stderr, + "%s: jtagmkII_recv(): Timeout receiving packet\n", + progname); + free(buf); + return -1; + } + } else { + if (serial_recv(pgm->fd, &c, 1) != 0) + goto timedout; + } + checksum ^= c; + + if (state < sDATA) + header[headeridx++] = c; + + switch (state) { + case sSTART: + if (c == MESSAGE_START) { + state = sSEQNUM1; + } else { + headeridx = 0; + } + break; + case sSEQNUM1: + case sSEQNUM2: + r_seqno >>= 8; + r_seqno |= (c << 8); + state++; + break; + case sSIZE1: + case sSIZE2: + case sSIZE3: + case sSIZE4: + msglen >>= 8; + msglen |= (c << 24); + state++; + break; + case sTOKEN: + if (c == TOKEN) { + state = sDATA; + if (msglen > MAX_MESSAGE) { + fprintf(stderr, + "%s: jtagmkII_recv(): msglen %lu exceeds max message " + "size %u, ignoring message\n", + progname, msglen, MAX_MESSAGE); + ignorpkt++; + } else if ((buf = malloc(msglen + 10)) == NULL) { + fprintf(stderr, "%s: jtagmkII_recv(): out of memory\n", + progname); + ignorpkt++; + } else { + memcpy(buf, header, 8); + } + } else { + state = sSTART; + headeridx = 0; + } + break; + case sDATA: + /* The entire payload has been read above. */ + l = msglen + 8; + state = sCSUM1; + break; + case sCSUM1: + case sCSUM2: + buf[l++] = c; + if (state == sCSUM2) { + if (crcverify(buf, msglen + 10)) { + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_recv(): CRC OK", + progname); + state = sDONE; + } else { + fprintf(stderr, "%s: jtagmkII_recv(): checksum error\n", + progname); + free(buf); + return -4; + } + } else + state++; + break; + default: + fprintf(stderr, "%s: jtagmkII_recv(): unknown state\n", + progname); + free(buf); + return -5; + } + + gettimeofday(&tv, NULL); + tnow = tv.tv_sec; + if (tnow - tstart > timeoutval) { + fprintf(stderr, "%s: jtagmkII_recv_frame(): timeout\n", + progname); + return -1; + } + + } + if (verbose >= 3) +fprintf(stderr, "\n"); + + *seqno = r_seqno; + *msg = buf; + + return msglen; +} + +static int jtagmkII_recv(PROGRAMMER * pgm, unsigned char **msg) { + unsigned short r_seqno; + int rv; + + for (;;) { + if ((rv = jtagmkII_recv_frame(pgm, msg, &r_seqno)) <= 0) + return rv; + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_recv(): " + "Got message seqno %d (command_sequence == %d)\n", + progname, r_seqno, command_sequence); + if (r_seqno == command_sequence) { + if (++command_sequence == 0xffff) + command_sequence = 0; + /* + * We move the payload to the beginning of the buffer, to make + * the job easier for the caller. We have to return the + * original pointer though, as the caller must free() it. + */ + memmove(*msg, *msg + 8, rv); + return rv; + } + if (r_seqno == 0xffff) { + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_recv(): got asynchronous event\n", + progname); + } else { + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_recv(): " + "got wrong sequence number, %u != %u\n", + progname, r_seqno, command_sequence); + } + free(*msg); + } + return 0; +} + + +static int jtagmkII_getsync(PROGRAMMER * pgm) { + int tries; +#define MAXTRIES 33 + unsigned char buf[3], *resp, c = 0xff; + int status; + + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_getsync()\n", progname); + + for (tries = 0; tries < MAXTRIES; tries++) { + + /* Get the sign-on information. */ + buf[0] = CMND_GET_SIGN_ON; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_getsync(): Sending sign-on command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + fprintf(stderr, "%s: jtagmkII_getsync(): sign-on command: " + "status %d\n", + progname, status); + } else if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + + if (status > 0) { + if ((c = resp[0]) == RSP_SIGN_ON) { + if (verbose >= 1 && status > 17) { + fprintf(stderr, "JTAG ICE mkII sign-on message:\n"); + fprintf(stderr, "Communications protocol version: %u\n", + (unsigned)resp[1]); + fprintf(stderr, "M_MCU:\n"); + fprintf(stderr, " boot-loader FW version: %u\n", + (unsigned)resp[2]); + fprintf(stderr, " firmware version: %u.%02u\n", + (unsigned)resp[4], (unsigned)resp[3]); + fprintf(stderr, " hardware version: %u\n", + (unsigned)resp[5]); + fprintf(stderr, "S_MCU:\n"); + fprintf(stderr, " boot-loader FW version: %u\n", + (unsigned)resp[6]); + fprintf(stderr, " firmware version: %u.%02u\n", + (unsigned)resp[8], (unsigned)resp[7]); + fprintf(stderr, " hardware version: %u\n", + (unsigned)resp[9]); + memcpy(serno, resp + 10, 6); + fprintf(stderr, "Serial number: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + serno[0], serno[1], serno[2], serno[3], serno[4], serno[5]); + resp[status - 1] = '\0'; + fprintf(stderr, "Device ID: %s\n", + resp + 16); + } + break; + } + free(resp); + } + } + if (tries >= MAXTRIES) { + if (status <= 0) + fprintf(stderr, + "%s: jtagmkII_getsync(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + else + fprintf(stderr, + "%s: jtagmkII_getsync(): " + "bad response to sign-on command: 0x%02x\n", + progname, c); + return -1; + } + + /* Turn the ICE into JTAG mode */ + buf[0] = EMULATOR_MODE_JTAG; + if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0) + return -1; + + /* GET SYNC forces the target into STOPPED mode */ + buf[0] = CMND_GET_SYNC; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_getsync(): Sending get sync command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_getsync(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_getsync(): " + "bad response to set parameter command: 0x%02x\n", + progname, c); + return -1; + } + + return 0; +} + +static int jtagmkII_cmd(PROGRAMMER * pgm, unsigned char cmd[4], + unsigned char res[4]) +{ + + fprintf(stderr, "%s: jtagmkII_command(): no direct SPI supported for JTAG\n", + progname); + return -1; +} + + +/* + * issue the 'chip erase' command to the AVR device + */ +static int jtagmkII_chip_erase(PROGRAMMER * pgm, AVRPART * p) +{ + int status; + unsigned char buf[1], *resp, c; + + buf[0] = CMND_CHIP_ERASE; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_chip_erase(): Sending chip erase command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_chip_erase(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_chip_erase(): " + "bad response to chip erase command: 0x%02x\n", + progname, c); + return -1; + } + + pgm->initialize(pgm, p); + + return 0; +} + +static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p) +{ + int status; + unsigned char *resp, c; + LNODEID ln; + AVRMEM * m; + struct { + unsigned char cmd; + struct device_descriptor dd; + } sendbuf; + + memset(&sendbuf, 0, sizeof sendbuf); + sendbuf.cmd = CMND_SET_DEVICE_DESCRIPTOR; + sendbuf.dd.ucSPMCRAddress = p->spmcr; + sendbuf.dd.ucRAMPZAddress = p->rampz; + sendbuf.dd.ucIDRAddress = p->idr; + sendbuf.dd.ucAllowFullPageBitstream = + (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0; + sendbuf.dd.EnablePageProgramming = + (p->flags & AVRPART_ENABLEPAGEPROGRAMMING) != 0; + for (ln = lfirst(p->mem); ln; ln = lnext(ln)) { + m = ldata(ln); + if (strcmp(m->desc, "flash") == 0) { + flash_pagesize = m->page_size; + u32_to_b4(sendbuf.dd.ulFlashSize, m->size); + u16_to_b2(sendbuf.dd.uiFlashPageSize, flash_pagesize); + u16_to_b2(sendbuf.dd.uiFlashpages, m->size / flash_pagesize); + } else if (strcmp(m->desc, "eeprom") == 0) { + sendbuf.dd.ucEepromPageSize = eeprom_pagesize = m->page_size; + } + } + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_set_devdescr(): " + "Sending set device descriptor command: ", + progname); + jtagmkII_send(pgm, (unsigned char *)&sendbuf, sizeof sendbuf); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_set_devdescr(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_set_devdescr(): " + "bad response to set device descriptor command: 0x%02x\n", + progname, c); + } +} + +/* + * Reset the target. + */ +static int jtagmkII_reset(PROGRAMMER * pgm) +{ + int status; + unsigned char buf[1], *resp, c; + + buf[0] = CMND_RESET; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_reset(): Sending reset command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_reset(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_reset(): " + "bad response to reset command: 0x%02x\n", + progname, c); + return -1; + } + + return 0; +} + +static int jtagmkII_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p) +{ + + return 0; +} + +static int jtagmkII_program_enable(PROGRAMMER * pgm) +{ + int status; + unsigned char buf[1], *resp, c; + + if (prog_enabled) + return 0; + + buf[0] = CMND_ENTER_PROGMODE; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_program_enable(): " + "Sending enter progmode command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_program_enable(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_program_enable(): " + "bad response to enter progmode command: 0x%02x\n", + progname, c); + return -1; + } + + prog_enabled = 1; + return 0; +} + +static int jtagmkII_program_disable(PROGRAMMER * pgm) +{ + int status; + unsigned char buf[1], *resp, c; + + if (!prog_enabled) + return 0; + + buf[0] = CMND_LEAVE_PROGMODE; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_program_disable(): " + "Sending leave progmode command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_program_disable(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_program_disable(): " + "bad response to leave progmode command: 0x%02x\n", + progname, c); + return -1; + } + + prog_enabled = 0; + (void)jtagmkII_reset(pgm); + + return 0; +} + +static unsigned char jtagmkII_get_baud(long baud) +{ + static struct { + long baud; + unsigned char val; + } baudtab[] = { + { 2400L, BAUD_2400 }, + { 4800L, BAUD_4800 }, + { 9600L, BAUD_9600 }, + { 19200L, BAUD_19200 }, + { 38400L, BAUD_38400 }, + { 57600L, BAUD_57600 }, + { 115200L, BAUD_115200 }, + { 14400L, BAUD_14400 }, + }; + int i; + + for (i = 0; i < sizeof baudtab / sizeof baudtab[0]; i++) + if (baud == baudtab[i].baud) + return baudtab[i].val; + + return 0; +} + +/* + * initialize the AVR device and prepare it to accept commands + */ +static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p) +{ + AVRMEM hfuse; + unsigned char b; + + if (!(p->flags & AVRPART_HAS_JTAG)) { + fprintf(stderr, "%s: jtagmkII_initialize(): part %s has no JTAG interface\n", + progname, p->desc); + return -1; + } + + if (pgm->baudrate && pgm->baudrate != 19200) { + if ((b = jtagmkII_get_baud(pgm->baudrate)) == 0) { + fprintf(stderr, "%s: jtagmkII_initialize(): unsupported baudrate %d\n", + progname, pgm->baudrate); + } else { + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_initialize(): " + "trying to set baudrate to %d\n", + progname, pgm->baudrate); + if (jtagmkII_setparm(pgm, PAR_BAUD_RATE, &b) == 0) + serial_setspeed(pgm->fd, pgm->baudrate); + } + } + if (pgm->bitclock != 0.0) { + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_initialize(): " + "trying to set JTAG clock period to %.1f us\n", + progname, pgm->bitclock); + if (jtagmkII_set_sck_period(pgm, pgm->bitclock) != 0) + return -1; + } + + /* + * Must set the device descriptor before entering programming mode. + */ + jtagmkII_set_devdescr(pgm, p); + + free(flash_pagecache); + free(eeprom_pagecache); + if ((flash_pagecache = malloc(flash_pagesize)) == NULL) { + fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n", + progname); + return -1; + } + if ((eeprom_pagecache = malloc(eeprom_pagesize)) == NULL) { + fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n", + progname); + free(flash_pagecache); + return -1; + } + flash_pageaddr = eeprom_pageaddr = (unsigned long)-1L; + + if (jtagmkII_reset(pgm) < 0) + return -1; + + internal_hfuse_handling = 1; + strcpy(hfuse.desc, "hfuse"); + if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &hfuse_backup) < 0) { + internal_hfuse_handling = 0; + return -1; + } + b = hfuse_backup; + b &= ~OCDEN; + if (jtagmkII_write_byte(pgm, p, &hfuse, 1, b) < 0) { + internal_hfuse_handling = 0; + return -1; + } + internal_hfuse_handling = 0; + + return 0; +} + + +static void jtagmkII_disable(PROGRAMMER * pgm) +{ + + free(flash_pagecache); + flash_pagecache = NULL; + free(eeprom_pagecache); + eeprom_pagecache = NULL; + + (void)jtagmkII_program_disable(pgm); +} + +static void jtagmkII_enable(PROGRAMMER * pgm) +{ + return; +} + + +static int jtagmkII_open(PROGRAMMER * pgm, char * port) +{ + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_open()\n", progname); + + strcpy(pgm->port, port); + /* + * 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. + */ + pgm->fd = serial_open(port, 19200); + + /* + * drain any extraneous input + */ + jtagmkII_drain(pgm, 0); + + jtagmkII_getsync(pgm); + + return 0; +} + + +static void jtagmkII_close(PROGRAMMER * pgm) +{ + int status; + unsigned char buf[1], *resp, c; + AVRMEM hfuse; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_close()\n", progname); + + internal_hfuse_handling = 1; + strcpy(hfuse.desc, "hfuse"); + (void)jtagmkII_write_byte(pgm, NULL, &hfuse, 1, hfuse_backup); + internal_hfuse_handling = 0; + + buf[0] = CMND_RESET; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_close(): Sending restore target command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_close(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + } else { + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_close(): " + "bad response to restore target command: 0x%02x\n", + progname, c); + } + } + + buf[0] = CMND_GO; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_close(): Sending GO command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_close(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + } else { + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_close(): " + "bad response to GO command: 0x%02x\n", + progname, c); + } + } + + buf[0] = CMND_SIGN_OFF; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_close(): Sending sign-off command: ", + progname); + jtagmkII_send(pgm, buf, 1); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_close(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_close(): " + "bad response to sign-off command: 0x%02x\n", + progname, c); + } + + serial_close(pgm->fd); + pgm->fd = -1; +} + + +static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int n_bytes) +{ + int addr, block_size; + unsigned char *cmd; + unsigned char *resp; + int status, tries; + long otimeout = serial_recv_timeout; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_paged_write(.., %s, %d, %d)\n", + progname, m->desc, page_size, n_bytes); + + if (jtagmkII_program_enable(pgm) < 0) + return -1; + + if ((cmd = malloc(page_size + 10)) == NULL) { + fprintf(stderr, "%s: jtagmkII_paged_write(): Out of memory\n", + progname); + return -1; + } + + cmd[0] = CMND_WRITE_MEMORY; + if (strcmp(m->desc, "flash") == 0) { + cmd[1] = MTYPE_FLASH_PAGE; + flash_pageaddr = (unsigned long)-1L; + page_size = flash_pagesize; + } else if (strcmp(m->desc, "eeprom") == 0) { + cmd[1] = MTYPE_EEPROM_PAGE; + eeprom_pageaddr = (unsigned long)-1L; + page_size = eeprom_pagesize; + } + + if (page_size == 0) page_size = 256; + + serial_recv_timeout = 100; + for (addr = 0; addr < n_bytes; addr += page_size) { + report_progress(addr, n_bytes,NULL); + + if ((n_bytes-addr) < page_size) + block_size = n_bytes - addr; + else + block_size = page_size; + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_paged_write(): " + "block_size at addr %d is %d\n", + progname, addr, block_size); + + u32_to_b4(cmd + 2, page_size); + u32_to_b4(cmd + 6, addr); + + /* + * The JTAG ICE will refuse to write anything but a full page, at + * least for the flash ROM. If a partial page has been requested, + * set the remainder to 0xff. (Maybe we should rather read back + * the existing contents instead before? Doesn't matter much, as + * bits cannot be written to 1 anyway.) + */ + memset(cmd + 10, 0xff, page_size); + memcpy(cmd + 10, m->buf + addr, block_size); + + tries = 0; + + retry: + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_paged_write(): " + "Sending write memory command: ", + progname); + jtagmkII_send(pgm, cmd, page_size + 10); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + if (verbose >= 1) + fprintf(stderr, + "%s: jtagmkII_paged_write(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + if (tries++ < 3) + goto retry; + fprintf(stderr, + "%s: jtagmkII_paged_write(): fatal timeout/" + "error communicating with programmer (status %d)\n", + progname, status); + free(cmd); + serial_recv_timeout = otimeout; + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + if (resp[0] != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_paged_write(): " + "bad response to write memory command: 0x%02x\n", + progname, resp[0]); + free(resp); + free(cmd); + serial_recv_timeout = otimeout; + return -1; + } + free(resp); + } + + free(cmd); + serial_recv_timeout = otimeout; + + return n_bytes; +} + +static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int n_bytes) +{ + int addr, block_size; + unsigned char cmd[10]; + unsigned char *resp; + int status, tries; + long otimeout = serial_recv_timeout; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_paged_load(.., %s, %d, %d)\n", + progname, m->desc, page_size, n_bytes); + + if (jtagmkII_program_enable(pgm) < 0) + return -1; + + page_size = m->readsize; + + cmd[0] = CMND_READ_MEMORY; + if (strcmp(m->desc, "flash") == 0) { + cmd[1] = MTYPE_FLASH_PAGE; + } else if (strcmp(m->desc, "eeprom") == 0) { + cmd[1] = MTYPE_EEPROM_PAGE; + } + + serial_recv_timeout = 100; + for (addr = 0; addr < n_bytes; addr += page_size) { + report_progress(addr, n_bytes,NULL); + + if ((n_bytes-addr) < page_size) + block_size = n_bytes - addr; + else + block_size = page_size; + if (verbose >= 3) + fprintf(stderr, "%s: jtagmkII_paged_load(): " + "block_size at addr %d is %d\n", + progname, addr, block_size); + + u32_to_b4(cmd + 2, block_size); + u32_to_b4(cmd + 6, addr); + + tries = 0; + + retry: + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_paged_load(): Sending read memory command: ", + progname); + jtagmkII_send(pgm, cmd, 10); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + if (verbose >= 1) + fprintf(stderr, + "%s: jtagmkII_paged_load(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + if (tries++ < 3) + goto retry; + fprintf(stderr, + "%s: jtagmkII_paged_load(): fatal timeout/" + "error communicating with programmer (status %d)\n", + progname, status); + serial_recv_timeout = otimeout; + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + if (resp[0] != RSP_MEMORY) { + fprintf(stderr, + "%s: jtagmkII_paged_load(): " + "bad response to read memory command: 0x%02x\n", + progname, resp[0]); + free(resp); + serial_recv_timeout = otimeout; + return -1; + } + memcpy(m->buf + addr, resp + 1, status); + free(resp); + } + serial_recv_timeout = otimeout; + + return 0; +} + +static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char * value) +{ + unsigned char cmd[10]; + unsigned char *resp = NULL, *cache_ptr = NULL; + int status, tries; + unsigned long paddr = 0UL, *paddr_ptr = NULL; + unsigned int pagesize = 0; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_read_byte(.., %s, 0x%lx, ...)\n", + progname, mem->desc, addr); + + if (jtagmkII_program_enable(pgm) < 0) + return -1; + + cmd[0] = CMND_READ_MEMORY; + + if (strcmp(mem->desc, "flash") == 0) { + cmd[1] = MTYPE_FLASH_PAGE; + pagesize = mem->page_size; + paddr = addr & ~(pagesize - 1); + paddr_ptr = &flash_pageaddr; + cache_ptr = flash_pagecache; + } else if (strcmp(mem->desc, "eeprom") == 0) { + cmd[1] = MTYPE_EEPROM_PAGE; + pagesize = mem->page_size; + paddr = addr & ~(pagesize - 1); + paddr_ptr = &eeprom_pageaddr; + cache_ptr = eeprom_pagecache; + } else if (strcmp(mem->desc, "lfuse") == 0) { + cmd[1] = MTYPE_FUSE_BITS; + addr = 0; + } else if (strcmp(mem->desc, "hfuse") == 0) { + cmd[1] = MTYPE_FUSE_BITS; + addr = 1; + if (!internal_hfuse_handling) { + *value = hfuse_backup; + return 0; + } + } else if (strcmp(mem->desc, "efuse") == 0) { + cmd[1] = MTYPE_FUSE_BITS; + addr = 2; + } else if (strcmp(mem->desc, "lock") == 0) { + cmd[1] = MTYPE_LOCK_BITS; + } else if (strcmp(mem->desc, "calibration") == 0) { + cmd[1] = MTYPE_OSCCAL_BYTE; + } else if (strcmp(mem->desc, "signature") == 0) { + cmd[1] = MTYPE_SIGN_JTAG; + } + + /* + * To improve the read speed, we used paged reads for flash and + * EEPROM, and cache the results in a page cache. + * + * Page cache validation is based on "{flash,eeprom}_pageaddr" + * (holding the base address of the most recent cache fill + * operation). This variable is set to (unsigned long)-1L when the + * cache needs to be invalidated. + */ + if (pagesize && paddr == *paddr_ptr) { + *value = cache_ptr[addr & (pagesize - 1)]; + return 0; + } + + if (pagesize) { + u32_to_b4(cmd + 2, pagesize); + u32_to_b4(cmd + 6, paddr); + } else { + u32_to_b4(cmd + 2, 1); + u32_to_b4(cmd + 6, addr); + } + + tries = 0; + retry: + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_read_byte(): Sending read memory command: ", + progname); + jtagmkII_send(pgm, cmd, 10); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + if (verbose >= 1) + fprintf(stderr, + "%s: jtagmkII_read_byte(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + if (tries++ < 3) + goto retry; + fprintf(stderr, + "%s: jtagmkII_read_byte(): " + "fatal timeout/error communicating with programmer (status %d)\n", + progname, status); + goto fail; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + if (resp[0] != RSP_MEMORY) { + fprintf(stderr, + "%s: jtagmkII_read_byte(): " + "bad response to read memory command: 0x%02x\n", + progname, resp[0]); + goto fail; + } + + if (pagesize) { + *paddr_ptr = paddr; + memcpy(cache_ptr, resp + 1, pagesize); + *value = cache_ptr[addr & (pagesize - 1)]; + } else + *value = resp[1]; + + free(resp); + return 0; + +fail: + /* + * XXX should return an error status here, but that would cause + * the generic methods to retry the request using the SPI method, + * which is complete nonsense for JTAG. + */ + *value = 42; + free(resp); + return 0; +} + +static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char data) +{ + unsigned char cmd[11]; + unsigned char *resp = NULL, writedata; + int status, tries, need_progmode = 1, is_hfuse = 0; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_write_byte(.., %s, 0x%lx, ...)\n", + progname, mem->desc, addr); + + writedata = data; + cmd[0] = CMND_WRITE_MEMORY; + if (strcmp(mem->desc, "flash") == 0) { + cmd[1] = MTYPE_SPM; + need_progmode = 0; + flash_pageaddr = (unsigned long)-1L; + } else if (strcmp(mem->desc, "eeprom") == 0) { + cmd[1] = MTYPE_EEPROM; + need_progmode = 0; + eeprom_pageaddr = (unsigned long)-1L; + } else if (strcmp(mem->desc, "lfuse") == 0) { + cmd[1] = MTYPE_FUSE_BITS; + addr = 0; + } else if (strcmp(mem->desc, "hfuse") == 0) { + cmd[1] = MTYPE_FUSE_BITS; + addr = 1; + if (!internal_hfuse_handling) { + is_hfuse = 1; + writedata &= ~OCDEN; + } + } else if (strcmp(mem->desc, "efuse") == 0) { + cmd[1] = MTYPE_FUSE_BITS; + addr = 2; + } else if (strcmp(mem->desc, "lock") == 0) { + cmd[1] = MTYPE_LOCK_BITS; + } else if (strcmp(mem->desc, "calibration") == 0) { + cmd[1] = MTYPE_OSCCAL_BYTE; + } else if (strcmp(mem->desc, "signature") == 0) { + cmd[1] = MTYPE_SIGN_JTAG; + } + + if (need_progmode) { + if (jtagmkII_program_enable(pgm) < 0) + return -1; + } else { + if (jtagmkII_program_disable(pgm) < 0) + return -1; + } + + u32_to_b4(cmd + 2, 1); + u32_to_b4(cmd + 6, addr); + cmd[10] = writedata; + + tries = 0; + retry: + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_write_byte(): Sending write memory command: ", + progname); + jtagmkII_send(pgm, cmd, 11); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + if (verbose > 1) + fprintf(stderr, + "%s: jtagmkII_write_byte(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + if (tries++ < 3) + goto retry; + fprintf(stderr, + "%s: jtagmkII_write_byte(): " + "fatal timeout/error communicating with programmer (status %d)\n", + progname, status); + goto fail; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + if (resp[0] != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_write_byte(): " + "bad response to write memory command: 0x%02x\n", + progname, resp[0]); + goto fail; + } + + if (is_hfuse && !internal_hfuse_handling) + hfuse_backup = data; + free(resp); + return 0; + +fail: + /* + * XXX should return an error status here, but that would cause + * the generic methods to retry the request using the SPI method, + * which is complete nonsense for JTAG. + */ + free(resp); + return 0; +} + + +/* + * Set the JTAG clock. The actual frequency is quite a bit of + * guesswork, based on the values claimed by AVR Studio. Inside the + * JTAG ICE, the value is the delay count of a delay loop between the + * JTAG clock edges. A count of 0 bypasses the delay loop. + * + * As the STK500 expresses it as a period length (and we actualy do + * program a period length as well), we rather call it by that name. + */ +static int jtagmkII_set_sck_period(PROGRAMMER * pgm, double v) +{ + unsigned char dur; + + v = 1 / v; /* convert to frequency */ + if (v >= 6.4e6) + dur = 0; + else if (v >= 2.8e6) + dur = 1; + else if (v >= 20.9e3) + dur = (unsigned char)(5.35e6 / v); + else + dur = 255; + + return jtagmkII_setparm(pgm, PAR_OCD_JTAG_CLK, &dur); +} + + +/* + * Read an emulator parameter. As the maximal parameter length is 4 + * bytes by now, we always copy out 4 bytes to *value, so the caller + * must have allocated sufficient space. + */ +static int jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm, + unsigned char * value) +{ + int status; + unsigned char buf[2], *resp, c; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_getparm()\n", progname); + + buf[0] = CMND_GET_PARAMETER; + buf[1] = parm; + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_getparm(): " + "Sending get parameter command (parm 0x%02x): ", + progname, parm); + jtagmkII_send(pgm, buf, 2); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_getparm(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + if (c != RSP_PARAMETER) { + fprintf(stderr, + "%s: jtagmkII_getparm(): " + "bad response to get parameter command: 0x%02x\n", + progname, c); + free(resp); + return -1; + } + + memcpy(value, resp + 1, 4); + free(resp); + + return 0; +} + +/* + * Write an emulator parameter. + */ +static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm, + unsigned char * value) +{ + int status; + /* + * As the maximal parameter length is 4 bytes, we use a fixed-length + * buffer, as opposed to malloc()ing it. + */ + unsigned char buf[2 + 4], *resp, c; + size_t size; + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_setparm()\n", progname); + + switch (parm) { + case PAR_HW_VERSION: size = 2; break; + case PAR_FW_VERSION: size = 4; break; + case PAR_EMULATOR_MODE: size = 1; break; + case PAR_BAUD_RATE: size = 1; break; + case PAR_OCD_VTARGET: size = 2; break; + case PAR_OCD_JTAG_CLK: size = 1; break; + default: + fprintf(stderr, "%s: jtagmkII_setparm(): unknown parameter 0x%02x\n", + progname, parm); + return -1; + } + + buf[0] = CMND_SET_PARAMETER; + buf[1] = parm; + memcpy(buf + 2, value, size); + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_setparm(): " + "Sending set parameter command (parm 0x%02x, %u bytes): ", + progname, parm, size); + jtagmkII_send(pgm, buf, size + 2); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_setparm(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_setparm(): " + "bad response to set parameter command: 0x%02x\n", + progname, c); + return -1; + } + + return 0; +} + + +static void jtagmkII_display(PROGRAMMER * pgm, char * p) +{ + unsigned char hw[4], fw[4]; + + if (jtagmkII_getparm(pgm, PAR_HW_VERSION, hw) < 0 || + jtagmkII_getparm(pgm, PAR_FW_VERSION, fw) < 0) + return; + + fprintf(stderr, "%sM_MCU hardware version: %d\n", p, hw[0]); + fprintf(stderr, "%sM_MCU firmware version: %d.%02d\n", p, fw[1], fw[0]); + fprintf(stderr, "%sS_MCU hardware version: %d\n", p, hw[1]); + fprintf(stderr, "%sS_MCU firmware version: %d.%02d\n", p, fw[3], fw[2]); + fprintf(stderr, "%sSerial number: %02x:%02x:%02x:%02x:%02x:%02x\n", + p, serno[0], serno[1], serno[2], serno[3], serno[4], serno[5]); + + jtagmkII_print_parms1(pgm, p); + + return; +} + + +static void jtagmkII_print_parms1(PROGRAMMER * pgm, char * p) +{ + unsigned char vtarget[4], jtag_clock[4]; + char clkbuf[20]; + double clk; + + if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0 || + jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0) + return; + + if (jtag_clock[0] == 0) { + strcpy(clkbuf, "6.4 MHz"); + clk = 6.4e6; + } else if (jtag_clock[0] == 1) { + strcpy(clkbuf, "2.8 MHz"); + clk = 2.8e6; + } else if (jtag_clock[0] <= 5) { + sprintf(clkbuf, "%.1f MHz", 5.35 / (double)jtag_clock[0]); + clk = 5.35e6 / (double)jtag_clock[0]; + } else { + sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]); + clk = 5.35e6 / (double)jtag_clock[0]; + } + + fprintf(stderr, "%sVtarget : %.1f V\n", p, + b2_to_u16(vtarget) / 1000.0); + fprintf(stderr, "%sJTAG clock : %s (%.1f us)\n", p, clkbuf, + 1.0e6 / clk); + + return; +} + + +static void jtagmkII_print_parms(PROGRAMMER * pgm) +{ + jtagmkII_print_parms1(pgm, ""); +} + + +void jtagmkII_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "JTAGMKII"); + + /* + * mandatory functions + */ + pgm->initialize = jtagmkII_initialize; + pgm->display = jtagmkII_display; + pgm->enable = jtagmkII_enable; + pgm->disable = jtagmkII_disable; + pgm->program_enable = jtagmkII_program_enable_dummy; + pgm->chip_erase = jtagmkII_chip_erase; + pgm->cmd = jtagmkII_cmd; + pgm->open = jtagmkII_open; + pgm->close = jtagmkII_close; + + /* + * optional functions + */ + pgm->paged_write = jtagmkII_paged_write; + pgm->paged_load = jtagmkII_paged_load; + pgm->read_byte = jtagmkII_read_byte; + pgm->write_byte = jtagmkII_write_byte; + pgm->print_parms = jtagmkII_print_parms; + pgm->set_sck_period = jtagmkII_set_sck_period; + pgm->page_size = 256; +} diff --git a/jtagmkII.h b/jtagmkII.h new file mode 100644 index 00000000..c8b6e0aa --- /dev/null +++ b/jtagmkII.h @@ -0,0 +1,28 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2002-2004 Brian S. Dean + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id$ */ + +#ifndef jtagmkII_h +#define jtagmkII_h + +void jtagmkII_initpgm (PROGRAMMER * pgm); + +#endif + diff --git a/jtagmkII_private.h b/jtagmkII_private.h new file mode 100644 index 00000000..6558a824 --- /dev/null +++ b/jtagmkII_private.h @@ -0,0 +1,296 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2005 Joerg Wunsch + * + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id$ */ + + +/* + * JTAG ICE mkII definitions + * Taken from Appnote AVR067 + */ + +/* + * Communication with the JTAG ICE works in frames. The protocol + * somewhat resembles the STK500v2 protocol, yet it is sufficiently + * different to prevent a direct code reuse. :-( + * + * Frame format: + * + * +---------------------------------------------------------------+ + * | 0 | 1 . 2 | 3 . 4 . 5 . 6 | 7 | ... | N-1 . N | + * | | | | | | | + * | start | LSB MSB | LSB ....... MSB | token | msg | LSB MSB | + * | 0x1B | sequence# | message size | 0x0E | | CRC16 | + * +---------------------------------------------------------------+ + * + * Each request message will be returned by a response with a matching + * sequence #. Sequence # 0xffff is reserved for asynchronous event + * notifications that will be sent by the ICE without a request + * message (e.g. when the target hit a breakpoint). + * + * The message size excludes the framing overhead (10 bytes). + * + * The first byte of the message is always the request or response + * code, which is roughly classified as: + * + * . Messages (commands) use 0x00 through 0x3f. (The documentation + * claims that messages start at 0x01, but actually CMND_SIGN_OFF is + * 0x00.) + * . Internal commands use 0x40 through 0x7f (not documented). + * . Success responses use 0x80 through 0x9f. + * . Failure responses use 0xa0 through 0xbf. + * . Events use 0xe0 through 0xff. + */ +#define MESSAGE_START 0x1b +#define TOKEN 0x0e + +/* + * Max message size we are willing to accept. Prevents us from trying + * to allocate too much VM in case we received a nonsensical packet + * length. We have to allocate the buffer as soon as we've got the + * length information (and thus have to trust that information by that + * time at first), as the final CRC check can only be done once the + * entire packet came it. + */ +#define MAX_MESSAGE 100000 + +/* ICE command codes */ +#define CMND_CHIP_ERASE 0x13 +#define CMND_CLEAR_EVENTS 0x22 +#define CMND_CLR_BREAK 0x1A +#define CMND_ENTER_PROGMODE 0x14 +#define CMND_ERASEPAGE_SPM 0x0D +#define CMND_FORCED_STOP 0x0A +#define CMND_GET_BREAK 0x12 +#define CMND_GET_PARAMETER 0x03 +#define CMND_GET_SIGN_ON 0x01 +#define CMND_GET_SYNC 0x0f +#define CMND_GO 0x08 +#define CMND_LEAVE_PROGMODE 0x15 +#define CMND_READ_MEMORY 0x05 +#define CMND_READ_PC 0x07 +#define CMND_RESET 0x0B +#define CMND_RESTORE_TARGET 0x23 +#define CMND_RUN_TO_ADDR 0x1C +#define CMND_SELFTEST 0x10 +#define CMND_SET_BREAK 0x11 +#define CMND_SET_DEVICE_DESCRIPTOR 0x0C +#define CMND_SET_N_PARAMETERS 0x16 +#define CMND_SET_PARAMETER 0x02 +#define CMND_SIGN_OFF 0x00 +#define CMND_SINGLE_STEP 0x09 +#define CMND_SPI_CMD 0x1D +#define CMND_WRITE_MEMORY 0x04 +#define CMND_WRITE_PC 0x06 + +/* ICE responses */ +#define RSP_DEBUGWIRE_SYNC_FAILED 0xAC +#define RSP_FAILED 0xA0 +#define RSP_GET_BREAK 0x83 +#define RSP_ILLEGAL_BREAKPOINT 0xA8 +#define RSP_ILLEGAL_COMMAND 0xAA +#define RSP_ILLEGAL_EMULATOR_MODE 0xA4 +#define RSP_ILLEGAL_JTAG_ID 0xA9 +#define RSP_ILLEGAL_MCU_STATE 0xA5 +#define RSP_ILLEGAL_MEMORY_TYPE 0xA2 +#define RSP_ILLEGAL_MEMORY_RANGE 0xA3 +#define RSP_ILLEGAL_PARAMETER 0xA1 +#define RSP_ILLEGAL_POWER_STATE 0xAD +#define RSP_ILLEGAL_VALUE 0xA6 +#define RSP_MEMORY 0x82 +#define RSP_NO_TARGET_POWER 0xAB +#define RSP_OK 0x80 +#define RSP_PARAMETER 0x81 +#define RSP_PC 0x84 +#define RSP_SELFTEST 0x85 +#define RSP_SET_N_PARAMETERS 0xA7 +#define RSP_SIGN_ON 0x86 +#define RSP_SPI_DATA 0x88 + +/* ICE events */ +#define EVT_BREAK 0xE0 +#define EVT_DEBUG 0xE6 +#define EVT_ERROR_PHY_FORCE_BREAK_TIMEOUT 0xE2 +#define EVT_ERROR_PHY_MAX_BIT_LENGTH_DIFF 0xED +#define EVT_ERROR_PHY_OPT_RECEIVE_TIMEOUT 0xF9 +#define EVT_ERROR_PHY_OPT_RECEIVED_BREAK 0xFA +#define EVT_ERROR_PHY_RECEIVED_BREAK 0xF8 +#define EVT_ERROR_PHY_RECEIVE_TIMEOUT 0xF7 +#define EVT_ERROR_PHY_RELEASE_BREAK_TIMEOUT 0xE3 +#define EVT_ERROR_PHY_SYNC_OUT_OF_RANGE 0xF5 +#define EVT_ERROR_PHY_SYNC_TIMEOUT 0xF0 +#define EVT_ERROR_PHY_SYNC_TIMEOUT_BAUD 0xF4 +#define EVT_ERROR_PHY_SYNC_WAIT_TIMEOUT 0xF6 +#define EVT_RESULT_PHY_NO_ACTIVITY 0xFB +#define EVT_EXT_RESET 0xE7 +#define EVT_ICE_POWER_ERROR_STATE 0xEA +#define EVT_ICE_POWER_OK 0xEB +#define EVT_IDR_DIRTY 0xEC +#define EVT_NONE 0xEF +#define EVT_PDSB_BREAK 0xF2 +#define EVT_PDSMB_BREAK 0xF3 +#define EVT_PROGRAM_BREAK 0xF1 +#define EVT_RUN 0xE1 +#define EVT_TARGET_POWER_OFF 0xE5 +#define EVT_TARGET_POWER_ON 0xE4 +#define EVT_TARGET_SLEEP 0xE8 +#define EVT_TARGET_WAKEUP 0xE9 + +/* memory types for CMND_{READ,WRITE}_MEMORY */ +#define MTYPE_IO_SHADOW 0x30 /* cached IO registers? */ +#define MTYPE_SRAM 0x20 /* target's SRAM or [ext.] IO registers */ +#define MTYPE_EEPROM 0x22 /* EEPROM, what way? */ +#define MTYPE_EVENT 0x60 /* ICE event memory */ +#define MTYPE_SPM 0xA0 /* flash through LPM/SPM */ +#define MTYPE_FLASH_PAGE 0xB0 /* flash in programming mode */ +#define MTYPE_EEPROM_PAGE 0xB1 /* EEPROM in programming mode */ +#define MTYPE_FUSE_BITS 0xB2 /* fuse bits in programming mode */ +#define MTYPE_LOCK_BITS 0xB3 /* lock bits in programming mode */ +#define MTYPE_SIGN_JTAG 0xB4 /* signature in programming mode */ +#define MTYPE_OSCCAL_BYTE 0xB5 /* osccal cells in programming mode */ +#define MTYPE_CAN 0xB6 /* CAN mailbox */ + +/* (some) ICE parameters, for CMND_{GET,SET}_PARAMETER */ +#define PAR_HW_VERSION 0x01 +#define PAR_FW_VERSION 0x02 +#define PAR_EMULATOR_MODE 0x03 +# define EMULATOR_MODE_DEBUGWIRE 0x00 +# define EMULATOR_MODE_JTAG 0x01 +# define EMULATOR_MODE_UNKNOWN 0x02 +# define EMULATOR_MODE_SPI 0x03 +#define PAR_IREG 0x04 +#define PAR_BAUD_RATE 0x05 +# define BAUD_2400 0x01 +# define BAUD_4800 0x02 +# define BAUD_9600 0x03 +# define BAUD_19200 0x04 /* default */ +# define BAUD_38400 0x05 +# define BAUD_57600 0x06 +# define BAUD_115200 0x07 +# define BAUD_14400 0x08 +#define PAR_OCD_VTARGET 0x06 +#define PAR_OCD_JTAG_CLK 0x07 +#define PAR_OCD_BREAK_CAUSE 0x08 +#define PAR_TIMERS_RUNNING 0x09 +#define PAR_BREAK_ON_CHANGE_FLOW 0x0A +#define PAR_BREAK_ADDR1 0x0B +#define PAR_BREAK_ADDR2 0x0C +#define PAR_COMBBREAKCTRL 0x0D +#define PAR_JTAGID 0x0E +#define PAR_UNITS_BEFORE 0x0F +#define PAR_UNITS_AFTER 0x10 +#define PAR_BIT_BEFORE 0x11 +#define PAR_BIT_ATER 0x12 +#define PAR_EXTERNAL_RESET 0x13 +#define PAR_FLASH_PAGE_SIZE 0x14 +#define PAR_EEPROM_PAGE_SIZE 0x15 +#define PAR_UNUSED1 0x16 +#define PAR_PSB0 0x17 +#define PAR_PSB1 0x18 +#define PAR_PROTOCOL_DEBUG_EVENT 0x19 +#define PAR_MCU_STATE 0x1A +# define STOPPED 0x00 +# define RUNNING 0x01 +# define PROGRAMMING 0x02 +#define PAR_DAISY_CHAIN_INFO 0x1B +#define PAR_BOOT_ADDRESS 0x1C +#define PAR_TARGET_SIGNATURE 0x1D +#define PAR_DEBUGWIRE_BAUDRATE 0x1E +#define PAR_PROGRAM_ENTRY_POINT 0x1F +#define PAR_PACKET_PARSING_ERRORS 0x40 +#define PAR_VALID_PACKETS_RECEIVED 0x41 +#define PAR_INTERCOMMUNICATION_TX_FAILURES 0x42 +#define PAR_INTERCOMMUNICATION_RX_FAILURES 0x43 +#define PAR_CRC_ERRORS 0x44 +#define PAR_POWER_SOURCE 0x45 +# define POWER_EXTERNAL 0x00 +# define POWER_USB 0x01 +#define PAR_CAN_FLAG 0x22 +# define DONT_READ_CAN_MAILBOX 0x00 +# define READ_CAN_MAILBOX 0x01 +#define PAR_ENABLE_IDR_IN_RUN_MODE 0x23 +# define ACCESS_OSCCAL 0x00 +# define ACCESS_IDR 0x01 +#define PAR_ALLOW_PAGEPROGRAMMING_IN_SCANCHAIN 0x24 +# define PAGEPROG_NOT_ALLOWED 0x00 +# define PAGEPROG_ALLOWED 0x01 + +/* + * In appnote AVR067, struct device_descriptor is written with + * int/long field types. We cannot use them directly, as they were + * neither properly aligned for portability, nor did they care for + * endianess issues. We thus use arrays of unsigned chars, plus + * conversion macros. + */ +struct device_descriptor +{ + unsigned char ucReadIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */ + unsigned char ucReadIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */ + unsigned char ucWriteIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */ + unsigned char ucWriteIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */ + unsigned char ucReadExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */ + unsigned char ucReadIOExtShadow[52]; /*LSB = IOloc 96, MSB = IOloc511 */ + unsigned char ucWriteExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */ + unsigned char ucWriteIOExtShadow[52];/*LSB = IOloc 96, MSB = IOloc511 */ + unsigned char ucIDRAddress; /*IDR address */ + unsigned char ucSPMCRAddress; /*SPMCR Register address and dW BasePC */ + unsigned char ucRAMPZAddress; /*RAMPZ Register address in SRAM I/O */ + /*space */ + unsigned char uiFlashPageSize[2]; /*Device Flash Page Size, Size = */ + /*2 exp ucFlashPageSize */ + unsigned char ucEepromPageSize; /*Device Eeprom Page Size in bytes */ + unsigned char ulBootAddress[4]; /*Device Boot Loader Start Address */ + unsigned char uiUpperExtIOLoc[2]; /*Topmost (last) extended I/O */ + /*location, 0 if no external I/O */ + unsigned char ulFlashSize[4]; /*Device Flash Size */ + unsigned char ucEepromInst[20]; /*Instructions for W/R EEPROM */ + unsigned char ucFlashInst[3]; /*Instructions for W/R FLASH */ + unsigned char ucSPHaddr; /* stack pointer high */ + unsigned char ucSPLaddr; /* stack pointer low */ + /* new as of 16-02-2004 */ + unsigned char uiFlashpages[2]; /* number of pages in flash */ + unsigned char ucDWDRAddress; /* DWDR register address */ + unsigned char ucDWBasePC; /* base/mask value of the PC */ + /* new as of 30-04-2004 */ + unsigned char ucAllowFullPageBitstream; /* FALSE on ALL new */ + /*parts */ + unsigned char uiStartSmallestBootLoaderSection[2]; /* */ + /* new as of 18-10-2004 */ + unsigned char EnablePageProgramming; /* For JTAG parts only, */ + /* default TRUE */ + unsigned char ucCacheType; /* CacheType_Normal 0x00, */ + /* CacheType_CAN 0x01, */ + /* CacheType_HEIMDALL 0x02 */ + /* new as of 27-10-2004 */ + unsigned char uiSramStartAddr[2]; /* Start of SRAM */ + unsigned char ucResetType; /* Selects reset type. ResetNormal = 0x00 */ + /* ResetAT76CXXX = 0x01 */ + unsigned char ucPCMaskExtended; /* For parts with extended PC */ + unsigned char ucPCMaskHigh; /* PC high mask */ + unsigned char ucEindAddress; /* Selects reset type. [EIND address...] */ + /* Does not work yet, M_MCU f/w rev 3.11, S_MCU f/w rev 3.16 */ + /* unsigned char EECRAddress[2]; */ /* EECR IO address */ +}; + +#define fill_b4(u) \ +{ ((u) & 0xffUL), (((u) & 0xff00UL) >> 8), \ + (((u) & 0xff0000UL) >> 16), (((u) & 0xff000000UL) >> 24) } +#define fill_b2(u) \ +{ ((u) & 0xff), (((u) & 0xff00) >> 8) }