/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2005-2007 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 * * The AVR Dragon also uses the same protocol, so it is handled here * as well. */ #include "ac_cfg.h" #include #include #include #include #include #include #include #include "avrdude.h" #include "avr.h" #include "crc16.h" #include "pgm.h" #include "jtagmkII.h" #include "jtagmkII_private.h" #include "serial.h" #include "usbdevs.h" /* * Private data for this programmer. */ struct pdata { unsigned short command_sequence; /* Next cmd seqno to issue. */ /* * See jtagmkII_read_byte() for an explanation of the flash and * EEPROM page caches. */ unsigned char *flash_pagecache; unsigned long flash_pageaddr; unsigned int flash_pagesize; unsigned char *eeprom_pagecache; unsigned long eeprom_pageaddr; unsigned int eeprom_pagesize; int prog_enabled; /* Cached value of PROGRAMMING status. */ unsigned char serno[6]; /* JTAG ICE serial number. */ /* JTAG chain stuff */ unsigned char jtagchain[4]; /* The length of the device descriptor is firmware-dependent. */ size_t device_descriptor_length; }; #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) /* * The OCDEN fuse is bit 7 of the high fuse (hfuse). In order to * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, OCDEN * needs to be programmed. * * 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) #define RC(x) { x, #x }, static struct { unsigned int code; const char *descr; } jtagresults[] = { RC(RSP_DEBUGWIRE_SYNC_FAILED) RC(RSP_FAILED) RC(RSP_ILLEGAL_BREAKPOINT) RC(RSP_ILLEGAL_COMMAND) RC(RSP_ILLEGAL_EMULATOR_MODE) RC(RSP_ILLEGAL_JTAG_ID) RC(RSP_ILLEGAL_MCU_STATE) RC(RSP_ILLEGAL_MEMORY_TYPE) RC(RSP_ILLEGAL_MEMORY_RANGE) RC(RSP_ILLEGAL_PARAMETER) RC(RSP_ILLEGAL_POWER_STATE) RC(RSP_ILLEGAL_VALUE) RC(RSP_NO_TARGET_POWER) RC(RSP_SET_N_PARAMETERS) }; /* * pgm->flag is marked as "for private use of the programmer". * The following defines this programmer's use of that field. */ #define PGM_FL_IS_DW (0x0001) 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_reset(PROGRAMMER * pgm, unsigned char flags); static int jtagmkII_set_sck_period(PROGRAMMER * pgm, double v); static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value); static void jtagmkII_print_parms1(PROGRAMMER * pgm, const char * p); void jtagmkII_setup(PROGRAMMER * pgm) { if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { fprintf(stderr, "%s: jtagmkII_setup(): Out of memory allocating private data\n", progname); exit(1); } memset(pgm->cookie, 0, sizeof(struct pdata)); } void jtagmkII_teardown(PROGRAMMER * pgm) { free(pgm->cookie); } static unsigned long b4_to_u32(unsigned char *b) { unsigned long l; l = b[0]; l += (unsigned)b[1] << 8; l += (unsigned)b[2] << 16; l += (unsigned)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 += (unsigned)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 const char * jtagmkII_get_rc(unsigned int rc) { int i; static char msg[50]; for (i = 0; i < sizeof jtagresults / sizeof jtagresults[0]; i++) if (jtagresults[i].code == rc) return jtagresults[i].descr; sprintf(msg, "Unknown JTAG ICE mkII result code 0x%02x", rc); return msg; } 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_HV: fprintf(stderr, ": HVSP/PP"); break; case EMULATOR_MODE_SPI: fprintf(stderr, ": SPI"); break; case EMULATOR_MODE_JTAG_XMEGA: fprintf(stderr, ": JTAG/Xmega"); 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); } int jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len) { unsigned char *buf; if (verbose >= 3) fprintf(stderr, "\n%s: jtagmkII_send(): sending %zd 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, PDATA(pgm)->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 |= ((unsigned)c << 8); state++; break; case sSIZE1: case sSIZE2: case sSIZE3: case sSIZE4: msglen >>= 8; msglen |= ((unsigned)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); state = sSTART; headeridx = 0; } 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; } 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, PDATA(pgm)->command_sequence); if (r_seqno == PDATA(pgm)->command_sequence) { if (++(PDATA(pgm)->command_sequence) == 0xffff) PDATA(pgm)->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, PDATA(pgm)->command_sequence); } free(*msg); } return 0; } int jtagmkII_getsync(PROGRAMMER * pgm, int mode) { int tries; #define MAXTRIES 33 unsigned char buf[3], *resp, c = 0xff; int status; unsigned int fwver, hwver; 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) { fwver = ((unsigned)resp[8] << 8) | (unsigned)resp[7]; hwver = (unsigned)resp[9]; memcpy(PDATA(pgm)->serno, resp + 10, 6); 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]); fprintf(stderr, "Serial number: " "%02x:%02x:%02x:%02x:%02x:%02x\n", PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->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: %s\n", progname, jtagmkII_get_rc(c)); return -1; } PDATA(pgm)->device_descriptor_length = sizeof(struct device_descriptor); /* * There's no official documentation from Atmel about what firmware * revision matches what device descriptor length. The algorithm * below has been found empirically. * * The original JTAG ICE mkII has hardware version 0, the AVR Dragon * has hardware version 2 (on the slave MCU) and doesn't need the * firmware version checks (by now). */ #define FWVER(maj, min) ((maj << 8) | (min)) if (hwver == 0 && fwver < FWVER(3, 16)) { PDATA(pgm)->device_descriptor_length -= 2; fprintf(stderr, "%s: jtagmkII_getsync(): " "S_MCU firmware version might be too old to work correctly\n", progname); } else if (hwver == 0 && fwver < FWVER(4, 0)) { PDATA(pgm)->device_descriptor_length -= 2; } if (verbose >= 2 && mode != EMULATOR_MODE_SPI) fprintf(stderr, "%s: jtagmkII_getsync(): Using a %zu-byte device descriptor\n", progname, PDATA(pgm)->device_descriptor_length); if (mode == EMULATOR_MODE_SPI || mode == EMULATOR_MODE_HV) { PDATA(pgm)->device_descriptor_length = 0; if (hwver == 0 && fwver < FWVER(4, 14)) { fprintf(stderr, "%s: jtagmkII_getsync(): ISP functionality requires firmware " "version >= 4.14\n", progname); return -1; } } #undef FWVER /* Turn the ICE into JTAG or ISP mode as requested. */ buf[0] = mode; if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0) { if (mode == EMULATOR_MODE_SPI) { fprintf(stderr, "%s: jtagmkII_getsync(): " "ISP activation failed, trying debugWire\n", progname); buf[0] = EMULATOR_MODE_DEBUGWIRE; if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0) return -1; else { /* * We are supposed to send a CMND_RESET with the * MONCOM_DISABLE flag set right now, and then * restart from scratch. * * As this will make the ICE sign off from USB, so * we risk losing our USB connection, it's easier * to instruct the user to restart AVRDUDE rather * than trying to cope with all this inside the * program. */ (void)jtagmkII_reset(pgm, 0x04); jtagmkII_close(pgm); fprintf(stderr, "%s: Target prepared for ISP, signed off.\n" "%s: Please restart %s without power-cycling the target.\n", progname, progname, progname); exit(0); } } else { 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: %s\n", progname, jtagmkII_get_rc(c)); return -1; } return 0; } /* * 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: %s\n", progname, jtagmkII_get_rc(c)); return -1; } pgm->initialize(pgm, p); return 0; } /* * There is no chip erase functionality in debugWire mode. */ static int jtagmkII_chip_erase_dw(PROGRAMMER * pgm, AVRPART * p) { fprintf(stderr, "%s: Chip erase not supported in debugWire mode\n", progname); 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; u16_to_b2(sendbuf.dd.EECRAddress, p->eecr); 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) { PDATA(pgm)->flash_pagesize = m->page_size; u32_to_b4(sendbuf.dd.ulFlashSize, m->size); u16_to_b2(sendbuf.dd.uiFlashPageSize, PDATA(pgm)->flash_pagesize); u16_to_b2(sendbuf.dd.uiFlashpages, m->size / PDATA(pgm)->flash_pagesize); if (p->flags & AVRPART_HAS_DW) { memcpy(sendbuf.dd.ucFlashInst, p->flash_instr, FLASH_INSTR_SIZE); memcpy(sendbuf.dd.ucEepromInst, p->eeprom_instr, EEPROM_INSTR_SIZE); } } else if (strcmp(m->desc, "eeprom") == 0) { sendbuf.dd.ucEepromPageSize = PDATA(pgm)->eeprom_pagesize = m->page_size; } } sendbuf.dd.ucCacheType = (p->flags & AVRPART_HAS_PDI)? 0x02 /* ATxmega */: 0x00; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_set_devdescr(): " "Sending set device descriptor command: ", progname); jtagmkII_send(pgm, (unsigned char *)&sendbuf, PDATA(pgm)->device_descriptor_length + sizeof(unsigned char)); 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: %s\n", progname, jtagmkII_get_rc(c)); } } /* * Reset the target. */ static int jtagmkII_reset(PROGRAMMER * pgm, unsigned char flags) { int status; unsigned char buf[2], *resp, c; /* * In debugWire mode, don't reset. Do a forced stop, and tell the * ICE to stop any timers, too. */ if (pgm->flag & PGM_FL_IS_DW) { unsigned char parm[] = { 0 }; (void)jtagmkII_setparm(pgm, PAR_TIMERS_RUNNING, parm); } buf[0] = (pgm->flag & PGM_FL_IS_DW)? CMND_FORCED_STOP: CMND_RESET; buf[1] = (pgm->flag & PGM_FL_IS_DW)? 1: flags; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_reset(): Sending %s command: ", progname, (pgm->flag & PGM_FL_IS_DW)? "stop": "reset"); jtagmkII_send(pgm, buf, 2); 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: %s\n", progname, jtagmkII_get_rc(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 (PDATA(pgm)->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: %s\n", progname, jtagmkII_get_rc(c)); if (c == RSP_ILLEGAL_JTAG_ID) fprintf(stderr, "%s: JTAGEN fuse disabled?\n", progname); return -1; } PDATA(pgm)->prog_enabled = 1; return 0; } static int jtagmkII_program_disable(PROGRAMMER * pgm) { int status; unsigned char buf[1], *resp, c; if (!PDATA(pgm)->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: %s\n", progname, jtagmkII_get_rc(c)); return -1; } PDATA(pgm)->prog_enabled = 0; (void)jtagmkII_reset(pgm, 0x01); return 0; } static unsigned char jtagmkII_get_baud(long baud) { static struct { long baud; unsigned char val; } baudtab[] = { { 2400L, PAR_BAUD_2400 }, { 4800L, PAR_BAUD_4800 }, { 9600L, PAR_BAUD_9600 }, { 19200L, PAR_BAUD_19200 }, { 38400L, PAR_BAUD_38400 }, { 57600L, PAR_BAUD_57600 }, { 115200L, PAR_BAUD_115200 }, { 14400L, PAR_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; int ok; const char *ifname; ok = 0; if (pgm->flag & PGM_FL_IS_DW) { ifname = "debugWire"; if (p->flags & AVRPART_HAS_DW) ok = 1; } else { ifname = "JTAG"; if (p->flags & AVRPART_HAS_JTAG) ok = 1; } if (!ok) { fprintf(stderr, "%s: jtagmkII_initialize(): part %s has no %s interface\n", progname, p->desc, ifname); return -1; } if ((serdev->flags & SERDEV_FL_CANSETSPEED) && 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->flag & PGM_FL_IS_DW) && 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; } if (jtagmkII_setparm(pgm, PAR_DAISY_CHAIN_INFO, PDATA(pgm)->jtagchain) < 0) { fprintf(stderr, "%s: jtagmkII_initialize(): Failed to setup JTAG chain\n", progname); return -1; } /* * Must set the device descriptor before entering programming mode. */ jtagmkII_set_devdescr(pgm, p); /* * If this is an ATxmega device, change the emulator mode from JTAG * to JTAG_XMEGA. */ if (!(pgm->flag & PGM_FL_IS_DW) && (p->flags & AVRPART_HAS_PDI)) jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG_XMEGA); free(PDATA(pgm)->flash_pagecache); free(PDATA(pgm)->eeprom_pagecache); if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) { fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n", progname); return -1; } if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) { fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n", progname); free(PDATA(pgm)->flash_pagecache); return -1; } PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; if (jtagmkII_reset(pgm, 0x01) < 0) return -1; if (!(pgm->flag & PGM_FL_IS_DW)) { strcpy(hfuse.desc, "hfuse"); if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &b) < 0) return -1; if ((b & OCDEN) != 0) fprintf(stderr, "%s: jtagmkII_initialize(): warning: OCDEN fuse not programmed, " "single-byte EEPROM updates not possible\n", progname); } return 0; } static void jtagmkII_disable(PROGRAMMER * pgm) { free(PDATA(pgm)->flash_pagecache); PDATA(pgm)->flash_pagecache = NULL; free(PDATA(pgm)->eeprom_pagecache); PDATA(pgm)->eeprom_pagecache = NULL; if (!(pgm->flag & PGM_FL_IS_DW)) (void)jtagmkII_program_disable(pgm); } static void jtagmkII_enable(PROGRAMMER * pgm) { return; } static int jtagmkII_parseextparms(PROGRAMMER * pgm, LISTID extparms) { LNODEID ln; const char *extended_param; int rv = 0; for (ln = lfirst(extparms); ln; ln = lnext(ln)) { extended_param = ldata(ln); if (strncmp(extended_param, "jtagchain=", strlen("jtagchain=")) == 0) { unsigned int ub, ua, bb, ba; if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba) != 4) { fprintf(stderr, "%s: jtagmkII_parseextparms(): invalid JTAG chain '%s'\n", progname, extended_param); rv = -1; continue; } if (verbose >= 2) { fprintf(stderr, "%s: jtagmkII_parseextparms(): JTAG chain parsed as:\n" "%s %u units before, %u units after, %u bits before, %u bits after\n", progname, progbuf, ub, ua, bb, ba); } PDATA(pgm)->jtagchain[0] = ub; PDATA(pgm)->jtagchain[1] = ua; PDATA(pgm)->jtagchain[2] = bb; PDATA(pgm)->jtagchain[3] = ba; continue; } fprintf(stderr, "%s: jtagmkII_parseextparms(): invalid extended parameter '%s'\n", progname, extended_param); rv = -1; } return rv; } static int jtagmkII_open(PROGRAMMER * pgm, char * port) { long baud; if (verbose >= 2) fprintf(stderr, "%s: 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); serial_open(port, baud, &pgm->fd); /* * drain any extraneous input */ jtagmkII_drain(pgm, 0); jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG); return 0; } static int jtagmkII_open_dw(PROGRAMMER * pgm, char * port) { long baud; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_open_dw()\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); serial_open(port, baud, &pgm->fd); /* * drain any extraneous input */ jtagmkII_drain(pgm, 0); jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE); return 0; } static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port) { long baud; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_dragon_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_AVRDRAGON; #else fprintf(stderr, "avrdude was compiled without usb support.\n"); return -1; #endif } strcpy(pgm->port, port); serial_open(port, baud, &pgm->fd); /* * drain any extraneous input */ jtagmkII_drain(pgm, 0); jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG); return 0; } static int jtagmkII_dragon_open_dw(PROGRAMMER * pgm, char * port) { long baud; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_dragon_open_dw()\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_AVRDRAGON; #else fprintf(stderr, "avrdude was compiled without usb support.\n"); return -1; #endif } strcpy(pgm->port, port); serial_open(port, baud, &pgm->fd); /* * drain any extraneous input */ jtagmkII_drain(pgm, 0); jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE); return 0; } void jtagmkII_close(PROGRAMMER * pgm) { int status; unsigned char buf[1], *resp, c; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_close()\n", progname); if (PDATA(pgm)->device_descriptor_length) { /* When in JTAG mode, restart target. */ 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: %s\n", progname, jtagmkII_get_rc(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: %s\n", progname, jtagmkII_get_rc(c)); } serial_close(&pgm->fd); pgm->fd.ifd = -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 (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0) return -1; if (page_size == 0) page_size = 256; 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; PDATA(pgm)->flash_pageaddr = (unsigned long)-1L; page_size = PDATA(pgm)->flash_pagesize; } else if (strcmp(m->desc, "eeprom") == 0) { if (pgm->flag & PGM_FL_IS_DW) { /* * jtagmkII_paged_write() to EEPROM attempted while in * DW mode. Use jtagmkII_write_byte() instead. */ for (addr = 0; addr < n_bytes; addr++) { status = jtagmkII_write_byte(pgm, p, m, addr, m->buf[addr]); report_progress(addr, n_bytes, NULL); if (status < 0) { free(cmd); return -1; } } free(cmd); return n_bytes; } cmd[1] = MTYPE_EEPROM_PAGE; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; page_size = PDATA(pgm)->eeprom_pagesize; } 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++ < 4) { serial_recv_timeout *= 2; 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: %s\n", progname, jtagmkII_get_rc(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 (!(pgm->flag & PGM_FL_IS_DW) && 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; if (pgm->flag & PGM_FL_IS_DW) return -1; } 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++ < 4) { serial_recv_timeout *= 2; 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: %s\n", progname, jtagmkII_get_rc(resp[0])); free(resp); serial_recv_timeout = otimeout; return -1; } memcpy(m->buf + addr, resp + 1, status); free(resp); } serial_recv_timeout = otimeout; return n_bytes; } 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, unsupp; 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 (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0) return -1; cmd[0] = CMND_READ_MEMORY; unsupp = 0; if (strcmp(mem->desc, "flash") == 0) { cmd[1] = MTYPE_FLASH_PAGE; pagesize = mem->page_size; paddr = addr & ~(pagesize - 1); paddr_ptr = &PDATA(pgm)->flash_pageaddr; cache_ptr = PDATA(pgm)->flash_pagecache; } else if (strcmp(mem->desc, "eeprom") == 0) { if (pgm->flag & PGM_FL_IS_DW) { /* debugWire cannot use page access for EEPROM */ cmd[1] = MTYPE_EEPROM; } else { cmd[1] = MTYPE_EEPROM_PAGE; pagesize = mem->page_size; paddr = addr & ~(pagesize - 1); paddr_ptr = &PDATA(pgm)->eeprom_pageaddr; cache_ptr = PDATA(pgm)->eeprom_pagecache; } } else if (strcmp(mem->desc, "lfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 0; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 1; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 2; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "lock") == 0) { cmd[1] = MTYPE_LOCK_BITS; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "calibration") == 0) { cmd[1] = MTYPE_OSCCAL_BYTE; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "signature") == 0) { cmd[1] = MTYPE_SIGN_JTAG; if (pgm->flag & PGM_FL_IS_DW) { /* * In debugWire mode, there is no accessible memory area to read * the signature from, but the essential two bytes can be read * as a parameter from the ICE. */ unsigned char parm[4]; switch (addr) { case 0: *value = 0x1E; /* Atmel vendor ID */ break; case 1: case 2: if (jtagmkII_getparm(pgm, PAR_TARGET_SIGNATURE, parm) < 0) return -1; *value = parm[2 - addr]; break; default: fprintf(stderr, "%s: illegal address %lu for signature memory\n", progname, addr); return -1; } return 0; } } /* * If the respective memory area is not supported under debugWire, * leave here. */ if (unsupp) { *value = 42; return -1; } /* * 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); if (status < 0) resp = 0; 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: %s\n", progname, jtagmkII_get_rc(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: free(resp); return -1; } 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, unsupp = 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; PDATA(pgm)->flash_pageaddr = (unsigned long)-1L; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "eeprom") == 0) { cmd[1] = MTYPE_EEPROM; need_progmode = 0; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; } else if (strcmp(mem->desc, "lfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 0; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 1; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 2; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "lock") == 0) { cmd[1] = MTYPE_LOCK_BITS; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "calibration") == 0) { cmd[1] = MTYPE_OSCCAL_BYTE; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } else if (strcmp(mem->desc, "signature") == 0) { cmd[1] = MTYPE_SIGN_JTAG; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; } if (unsupp) return -1; 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: %s\n", progname, jtagmkII_get_rc(resp[0])); goto fail; } free(resp); return 0; fail: free(resp); return -1; } /* * 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. */ 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: %s\n", progname, jtagmkII_get_rc(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; case PAR_TIMERS_RUNNING: size = 1; break; case PAR_DAISY_CHAIN_INFO: size = 4; 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, %zu 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: %s\n", progname, jtagmkII_get_rc(c)); return -1; } return 0; } static void jtagmkII_display(PROGRAMMER * pgm, const 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, PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]); jtagmkII_print_parms1(pgm, p); return; } static void jtagmkII_print_parms1(PROGRAMMER * pgm, const char * p) { unsigned char vtarget[4], jtag_clock[4]; char clkbuf[20]; double clk; if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0) return; fprintf(stderr, "%sVtarget : %.1f V\n", p, b2_to_u16(vtarget) / 1000.0); if (!(pgm->flag & PGM_FL_IS_DW)) { if (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, "%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->open = jtagmkII_open; pgm->close = jtagmkII_close; pgm->read_byte = jtagmkII_read_byte; pgm->write_byte = jtagmkII_write_byte; /* * optional functions */ pgm->paged_write = jtagmkII_paged_write; pgm->paged_load = jtagmkII_paged_load; pgm->print_parms = jtagmkII_print_parms; pgm->set_sck_period = jtagmkII_set_sck_period; pgm->parseextparams = jtagmkII_parseextparms; pgm->setup = jtagmkII_setup; pgm->teardown = jtagmkII_teardown; pgm->page_size = 256; } void jtagmkII_dw_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "JTAGMKII_DW"); /* * 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_dw; pgm->open = jtagmkII_open_dw; pgm->close = jtagmkII_close; pgm->read_byte = jtagmkII_read_byte; pgm->write_byte = jtagmkII_write_byte; /* * optional functions */ pgm->paged_write = jtagmkII_paged_write; pgm->paged_load = jtagmkII_paged_load; pgm->print_parms = jtagmkII_print_parms; pgm->setup = jtagmkII_setup; pgm->teardown = jtagmkII_teardown; pgm->page_size = 256; pgm->flag = PGM_FL_IS_DW; } void jtagmkII_dragon_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "DRAGON_JTAG"); /* * 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->open = jtagmkII_dragon_open; pgm->close = jtagmkII_close; pgm->read_byte = jtagmkII_read_byte; pgm->write_byte = jtagmkII_write_byte; /* * optional functions */ pgm->paged_write = jtagmkII_paged_write; pgm->paged_load = jtagmkII_paged_load; pgm->print_parms = jtagmkII_print_parms; pgm->set_sck_period = jtagmkII_set_sck_period; pgm->parseextparams = jtagmkII_parseextparms; pgm->setup = jtagmkII_setup; pgm->teardown = jtagmkII_teardown; pgm->page_size = 256; } void jtagmkII_dragon_dw_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "DRAGON_DW"); /* * 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_dw; pgm->open = jtagmkII_dragon_open_dw; pgm->close = jtagmkII_close; pgm->read_byte = jtagmkII_read_byte; pgm->write_byte = jtagmkII_write_byte; /* * optional functions */ pgm->paged_write = jtagmkII_paged_write; pgm->paged_load = jtagmkII_paged_load; pgm->print_parms = jtagmkII_print_parms; pgm->setup = jtagmkII_setup; pgm->teardown = jtagmkII_teardown; pgm->page_size = 256; pgm->flag = PGM_FL_IS_DW; }