diff --git a/ChangeLog b/ChangeLog index 626062d7..334d134b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2012-11-28 Joerg Wunsch + + First support for Atmel JTAGICE3. Guessed from USB sniffer + traces made by Knut Schwichtenberg, and by similarity to + JTAGICEmkII. + Still quite incomplete, just megaAVR/JTAG is done by now. + * jtag3.c: New file. + * jtag3.h: (Dito.) + * jtag3_private.h: (Dito.) + * pgm_type.c: Add new programmers + * avrdude.conf.in: (Dito.) + * usbdevs.h: Add new parameters + * Makefile.am: Add new files + * usb_libusb.c: Handle separate event endpoint, and larger + (USB 2.0) packet sizes + 2012-11-26 Joerg Wunsch * jtagmkII.c: Change all the USB details (endpoint numbers, diff --git a/Makefile.am b/Makefile.am index f4befec9..0c06de0e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,6 +120,9 @@ libavrdude_a_SOURCES = \ jtagmkII.c \ jtagmkII.h \ jtagmkII_private.h \ + jtag3.c \ + jtag3.h \ + jtag3_private.h \ linux_ppdev.h \ lists.c \ lists.h \ diff --git a/NEWS b/NEWS index 367ef53c..39bc1731 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,8 @@ Current: X3(1), sck = DSR X3(2), mosi = DCD X3(3), reset = RI X3(4)) + diecimila (alias for arduino-ft232r) + - Atmel JTAGICE3 (megaAVR/JTAG only so far) + * Bugfixes - bug #34027: avrdude AT90S1200 Problem - bug #34518: loading intel hex files > 64k using record-type 4 diff --git a/avrdude.conf.in b/avrdude.conf.in index 4aee6bfa..ffd72fc7 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -891,6 +891,28 @@ programmer connection_type = usb; ; +programmer + id = "jtag3"; + desc = "Atmel AVR JTAGICE3 in JTAG mode"; + type = "jtagice3"; + connection_type = usb; +; + +programmer + id = "jtag3pdi"; + desc = "Atmel AVR JTAGICE3 in PDI mode"; + type = "jtagice3_pdi"; + connection_type = usb; +; + +programmer + id = "jtag3dw"; + desc = "Atmel AVR JTAGICE3 in debugWIRE mode"; + type = "jtagice3_dw"; + connection_type = usb; +; + + programmer id = "pavr"; desc = "Jason Kyle's pAVR Serial Programmer"; diff --git a/jtag3.c b/jtag3.c new file mode 100644 index 00000000..afad7af6 --- /dev/null +++ b/jtag3.c @@ -0,0 +1,1982 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2012 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, see . + */ + +/* $Id$ */ + +/* + * avrdude interface for Atmel JTAGICE3 programmer + */ + +#include "ac_cfg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avrdude.h" +#include "avr.h" +#include "crc16.h" +#include "pgm.h" +#include "jtag3.h" +#include "jtag3_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 jtag3_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. */ + + /* JTAG chain stuff */ + unsigned char jtagchain[4]; + + /* Start address of Xmega boot area */ + unsigned long boot_start; +}; + +#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) + +/* + * 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) +#define PGM_FL_IS_PDI (0x0002) +#define PGM_FL_IS_JTAG (0x0004) + +static int jtag3_open(PROGRAMMER * pgm, char * port); + +static int jtag3_command(PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen, + unsigned char **resp, const char *descr); + +static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p); +static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p); +static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char * value); +static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char data); +static int jtag3_reset(PROGRAMMER * pgm, unsigned char flags); +static int jtag3_set_sck_period(PROGRAMMER * pgm, double v); +static int jtag3_setparm(PROGRAMMER * pgm, unsigned char scope, + unsigned char section, unsigned char parm, + unsigned char *value, unsigned char length); +static void jtag3_print_parms1(PROGRAMMER * pgm, const char * p); +static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int page_size, + unsigned int addr, unsigned int n_bytes); +static unsigned char jtag3_memtype(PROGRAMMER * pgm, AVRPART * p, unsigned long addr); +static unsigned int jtag3_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr); + + +void jtag3_setup(PROGRAMMER * pgm) +{ + if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { + fprintf(stderr, + "%s: jtag3_setup(): Out of memory allocating private data\n", + progname); + exit(1); + } + memset(pgm->cookie, 0, sizeof(struct pdata)); +} + +void jtag3_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 unsigned long +b4_to_u32r(unsigned char *b) +{ + unsigned long l; + l = b[3]; + l += (unsigned)b[2] << 8; + l += (unsigned)b[1] << 16; + l += (unsigned)b[0] << 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 void +u32_to_b4r(unsigned char *b, unsigned long l) +{ + b[3] = l & 0xff; + b[2] = (l >> 8) & 0xff; + b[1] = (l >> 16) & 0xff; + b[0] = (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 void jtag3_print_data(unsigned char *b, size_t s) +{ + int i; + + if (s < 2) + return; + + for (i = 0; i < s; i++) { + fprintf(stderr, "0x%02x", b[i]); + if (i % 16 == 15) + putc('\n', stderr); + else + putc(' ', stderr); + } + if (i % 16 != 0) + putc('\n', stderr); +} + +static void jtag3_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, "%02x ", data[i]); + if (i % 16 == 15) + putc('\n', stderr); + else + putchar(' '); + } + if (i % 16 != 0) + putc('\n', stderr); + } + + switch (data[0]) { + case SCOPE_INFO: + fprintf(stderr, "[info] "); + break; + + case SCOPE_GENERAL: + fprintf(stderr, "[general] "); + break; + + case SCOPE_AVR_ISP: + fprintf(stderr, "[AVRISP] "); + jtag3_print_data(data + 1, len - 1); + return; + + case SCOPE_AVR: + fprintf(stderr, "[AVR] "); + break; + + default: + fprintf(stderr, "[scope 0x%02x] ", data[0]); + break; + } + + switch (data[1]) { + case RSP3_OK: + fprintf(stderr, "OK\n"); + break; + + case RSP3_FAILED: + fprintf(stderr, "FAILED"); + if (len > 3) + { + char reason[50]; + sprintf(reason, "0x%02x", data[3]); + switch (data[3]) + { + case RSP3_FAIL_NO_ANSWER: + strcpy(reason, "target does not answer"); + break; + + case RSP3_FAIL_NO_TARGET_POWER: + strcpy(reason, "no target power"); + break; + + case RSP3_FAIL_NOT_UNDERSTOOD: + strcpy(reason, "command not understood"); + break; + + case RSP3_FAIL_WRONG_MODE: + strcpy(reason, "wrong (programming) mode"); + break; + } + fprintf(stderr, ", reason: %s\n", reason); + } + else + { + fprintf(stderr, ", unspecified reason\n"); + } + break; + + case RSP3_DATA: + fprintf(stderr, "Data returned:\n"); + jtag3_print_data(data + 2, len - 2); + break; + + case RSP3_INFO: + fprintf(stderr, "Info returned:\n"); + for (i = 2; i < len; i++) { + if (isprint(data[i])) + putc(data[i], stderr); + else + fprintf(stderr, "\\%03o", data[i]); + } + putc('\n', stderr); + break; + + case RSP3_PC: + if (len < 7) + { + fprintf(stderr, "PC reply too short\n"); + } + else + { + unsigned long pc = (data[6] << 24) | (data[5] << 16) + | (data[4] << 8) | data[3]; + fprintf(stderr, "PC 0x%0lx\n", pc); + } + break; + +#if 0 + 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; + + putc('\n', stderr); +#endif + + default: + fprintf(stderr, "unknown message 0x%02x\n", data[1]); + } +} + + +int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len) +{ + unsigned char *buf; + + if (verbose >= 3) + fprintf(stderr, "\n%s: jtag3_send(): sending %lu bytes\n", + progname, (unsigned long)len); + + if ((buf = malloc(len + 4)) == NULL) + { + fprintf(stderr, "%s: jtag3_send(): out of memory", + progname); + return -1; + } + + buf[0] = TOKEN; + buf[1] = 0; /* dummy */ + u16_to_b2(buf + 2, PDATA(pgm)->command_sequence); + memcpy(buf + 4, data, len); + + if (serial_send(&pgm->fd, buf, len + 4) != 0) { + fprintf(stderr, + "%s: jtag3_send(): failed to send command to serial port\n", + progname); + exit(1); + } + + free(buf); + + return 0; +} + + +static int jtag3_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 jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) { + int rv; + unsigned char *buf = NULL; + + if (verbose >= 4) + fprintf(stderr, "%s: jtag3_recv():\n", progname); + + if ((buf = malloc(pgm->fd.usb.max_xfer)) == NULL) { + fprintf(stderr, "%s: jtag3_recv(): out of memory\n", + progname); + return -1; + } + + rv = serial_recv(&pgm->fd, buf, pgm->fd.usb.max_xfer); + + if (rv < 0) { + /* timeout in receive */ + if (verbose > 1) + fprintf(stderr, + "%s: jtag3_recv(): Timeout receiving packet\n", + progname); + free(buf); + return -1; + } + + *msg = buf; + + return rv; +} + +int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg) { + unsigned short r_seqno; + int rv; + + for (;;) { + if ((rv = jtag3_recv_frame(pgm, msg)) <= 0) + return rv; + + r_seqno = ((*msg)[2] << 8) | (*msg)[1]; + if (verbose >= 3) + fprintf(stderr, "%s: jtag3_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 + 3, rv); + rv -= 3; + + return rv; + } + if (r_seqno == 0xffff) { + if (verbose >= 3) + fprintf(stderr, "%s: jtag3_recv(): got asynchronous event\n", + progname); + } else { + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_recv(): " + "got wrong sequence number, %u != %u\n", + progname, r_seqno, PDATA(pgm)->command_sequence); + } + free(*msg); + } +} + +static int jtag3_command(PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen, + unsigned char **resp, const char *descr) +{ + int status; + unsigned char c; + + if (verbose >= 2) + fprintf(stderr, "%s: Sending %s command: ", + progname, descr); + jtag3_send(pgm, cmd, cmdlen); + + status = jtag3_recv(pgm, resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: %s command: timeout/error communicating with programmer (status %d)\n", + progname, descr, status); + } else if (verbose >= 3) { + putc('\n', stderr); + jtag3_prmsg(pgm, *resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", (*resp)[1], status); + + c = (*resp)[1]; + if ((c & RSP3_STATUS_MASK) != RSP3_OK) { + fprintf(stderr, + "%s: bad response to %s command: 0x%02x\n", + progname, descr, c); + free(*resp); + resp = 0; + return -1; + } + + return status; +} + + +int jtag3_getsync(PROGRAMMER * pgm, int mode) { + + unsigned char buf[3], *resp; + + if (verbose >= 3) + fprintf(stderr, "%s: jtag3_getsync()\n", progname); + + /* Get the sign-on information. */ + buf[0] = SCOPE_GENERAL; + buf[1] = CMD3_SIGN_ON; + buf[2] = 0; + + if (jtag3_command(pgm, buf, 3, &resp, "sign-on") < 0) + return -1; + + free(resp); + + return 0; +} + +/* + * issue the 'chip erase' command to the AVR device + */ +static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p) +{ + unsigned char buf[8], *resp; + + buf[0] = SCOPE_AVR; + buf[1] = CMD3_ERASE_MEMORY; + buf[2] = 0; + buf[3] = XMEGA_ERASE_CHIP; + buf[4] = buf[5] = buf[6] = buf[7] = 0; /* page address */ + + if (jtag3_command(pgm, buf, 8, &resp, "chip erase") < 0) + return -1; + + free(resp); + return 0; +} + +/* + * There is no chip erase functionality in debugWire mode. + */ +static int jtag3_chip_erase_dw(PROGRAMMER * pgm, AVRPART * p) +{ + + fprintf(stderr, "%s: Chip erase not supported in debugWire mode\n", + progname); + + return 0; +} + +/* + * Reset the target. + */ +static int jtag3_reset(PROGRAMMER * pgm, unsigned char flags) +{ +#if 0 + 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)jtag3_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: jtag3_reset(): Sending %s command: ", + progname, (pgm->flag & PGM_FL_IS_DW)? "stop": "reset"); + jtag3_send(pgm, buf, 2); + + status = jtag3_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtag3_reset(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtag3_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[1], status); + c = resp[1]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtag3_reset(): " + "bad response to reset command: %s\n", + progname, jtag3_get_rc(c)); + return -1; + } + +#endif + return 0; +} + +static int jtag3_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p) +{ + return 0; +} + +static int jtag3_program_enable(PROGRAMMER * pgm) +{ + unsigned char buf[3], *resp; + int use_ext_reset; + + if (PDATA(pgm)->prog_enabled) + return 0; + + for (use_ext_reset = 0; use_ext_reset <= 1; use_ext_reset++) { + buf[0] = SCOPE_AVR; + buf[1] = CMD3_ENTER_PROGMODE; + buf[2] = 0; + + if (jtag3_command(pgm, buf, 3, &resp, "enter progmode") >= 0) { + free(resp); + break; + } + + /* XXX activate external reset here */ + if (verbose > 0) + fprintf(stderr, + "%s: retrying with external reset applied\n", + progname); + } + + PDATA(pgm)->prog_enabled = 1; + + return 0; +} + +static int jtag3_program_disable(PROGRAMMER * pgm) +{ + unsigned char buf[3], *resp; + + if (!PDATA(pgm)->prog_enabled) + return 0; + + buf[0] = SCOPE_AVR; + buf[1] = CMD3_LEAVE_PROGMODE; + buf[2] = 0; + + if (jtag3_command(pgm, buf, 3, &resp, "enter progmode") < 0) + return -1; + + free(resp); + + PDATA(pgm)->prog_enabled = 0; + //(void)jtag3_reset(pgm, 0x01); + + return 0; +} + +/* + * initialize the AVR device and prepare it to accept commands + */ +static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p) +{ + AVRMEM hfuse; + unsigned char conn = 0, parm[4]; + const char *ifname; + unsigned char cmd[4], *resp, b; + int status; + + if (pgm->flag & PGM_FL_IS_DW) { + ifname = "debugWire"; + if (p->flags & AVRPART_HAS_DW) + conn = PARM3_CONN_DW; + } else if (pgm->flag & PGM_FL_IS_PDI) { + ifname = "PDI"; + if (p->flags & AVRPART_HAS_PDI) + conn = PARM3_CONN_PDI; + } else { + ifname = "JTAG"; + if (p->flags & AVRPART_HAS_JTAG) + conn = PARM3_CONN_JTAG; + } + + if (conn == 0) { + fprintf(stderr, "%s: jtag3_initialize(): part %s has no %s interface\n", + progname, p->desc, ifname); + return -1; + } + + if (p->flags & AVRPART_HAS_PDI) + parm[0] = PARM3_ARCH_XMEGA; + else if (p->flags & AVRPART_HAS_DW) + parm[0] = PARM3_ARCH_TINY; + else + parm[0] = PARM3_ARCH_MEGA; + if (jtag3_setparm(pgm, SCOPE_AVR, 0, PARM3_ARCH, parm, 1) < 0) + return -1; + + parm[0] = PARM3_SESS_PROGRAMMING; + if (jtag3_setparm(pgm, SCOPE_AVR, 0, PARM3_SESS_PURPOSE, parm, 1) < 0) + return -1; + + parm[0] = conn; + if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CONNECTION, parm, 1) < 0) + return -1; + + if (conn == PARM3_CONN_JTAG && pgm->bitclock != 0.0) + { + unsigned int clock = 1E-3 / pgm->bitclock; /* kHz */ + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_initialize(): " + "trying to set JTAG clock to %u kHz\n", + progname, clock); + parm[0] = clock & 0xff; + parm[1] = (clock >> 8) & 0xff; + if (jtag3_setparm(pgm, SCOPE_AVR, 1, + ((p->flags & AVRPART_HAS_PDI)? PARM3_CLK_XMEGA_JTAG: PARM3_CLK_MEGA_PROG), + parm, 2) < 0) + return -1; + } + if (conn == PARM3_CONN_PDI && pgm->bitclock != 0.0) + { + unsigned int clock = 1E-3 / pgm->bitclock; /* kHz */ + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_initialize(): " + "trying to set PDI clock to %u kHz\n", + progname, clock); + parm[0] = clock & 0xff; + parm[1] = (clock >> 8) & 0xff; + if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, parm, 2) < 0) + return -1; + } + if (conn == PARM3_CONN_JTAG) + { + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_initialize(): " + "trying to set JTAG daisy-chain info to %d,%d,%d,%d\n", + progname, + PDATA(pgm)->jtagchain[0], PDATA(pgm)->jtagchain[1], + PDATA(pgm)->jtagchain[2], PDATA(pgm)->jtagchain[3]); + if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_JTAGCHAIN, PDATA(pgm)->jtagchain, 4) < 0) + return -1; + } + + /* set device descriptor data */ + if ((p->flags & AVRPART_HAS_PDI)) + { + struct xmega_device_desc xd; + } + else + { + struct mega_device_desc md; + LNODEID ln; + AVRMEM * m; + + memset(&md, 0, sizeof md); + + 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; + u16_to_b2(md.flash_page_size, m->page_size); + u32_to_b4(md.flash_size, m->size); + // do we need it? just a wild guess + u32_to_b4(md.boot_address, (m->size - m->page_size * 4) / 2); + } else if (strcmp(m->desc, "eeprom") == 0) { + PDATA(pgm)->eeprom_pagesize = m->page_size; + md.eeprom_page_size = m->page_size; + u16_to_b2(md.eeprom_size, m->size); + } + } + + //md.sram_offset[2] = p->sram; // do we need it? + u16_to_b2(md.sram_offset, 0x200); + md.ocd_revision = 3; /* XXX! */ + md.always_one = 1; + md.allow_full_page_bitstream = (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0; + md.idr_address = p->idr; + + if (p->eecr == 0) + p->eecr = 0x1f; /* matches most "modern" mega/tiny AVRs */ + md.eearh_address = p->eecr + 3; + md.eearl_address = p->eecr + 2; + md.eecr_address = p->eecr; + md.eedr_address = p->eecr + 1; + md.spmcr_address = p->spmcr; + //md.osccal_address = p->osccal; // do we need it at all? + md.osccal_address = 0x46; /* XXX */ + + if (jtag3_setparm(pgm, SCOPE_AVR, 2, PARM3_DEVICEDESC, (unsigned char *)&md, sizeof md) < 0) + return -1; + } + + cmd[0] = SCOPE_AVR; + cmd[1] = CMD3_SIGN_ON; + cmd[2] = 0; + cmd[3] = 0; /* external reset */ + + if ((status = jtag3_command(pgm, cmd, 4, &resp, "AVR sign-on")) < 0) + return -1; + + /* + * Depending on the target connection, there are two different + * possible replies of the ICE. For a JTAG connection, the reply + * format is RSP3_DATA, followed by 4 bytes of the JTAG ID read from + * the device (followed by a trailing 0). For all other connections + * (except ISP which is handled completely differently, but that + * doesn't apply here anyway), the response is just RSP_OK. + */ + if (resp[1] == RSP3_DATA && status >= 7 && verbose >= 1) + /* JTAG ID has been returned */ + fprintf(stderr, "%s: JTAG ID returned: 0x%02x 0x%02x 0x%02x 0x%02x\n", + progname, resp[3], resp[4], resp[5], resp[6]); + + free(resp); + + free(PDATA(pgm)->flash_pagecache); + free(PDATA(pgm)->eeprom_pagecache); + if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) { + fprintf(stderr, "%s: jtag3_initialize(): Out of memory\n", + progname); + return -1; + } + if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) { + fprintf(stderr, "%s: jtag3_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 (jtag3_reset(pgm, 0x01) < 0) + return -1; + + if ((pgm->flag & PGM_FL_IS_JTAG) && !(p->flags & AVRPART_HAS_PDI)) { + strcpy(hfuse.desc, "hfuse"); + if (jtag3_read_byte(pgm, p, &hfuse, 1, &b) < 0) + return -1; + if ((b & OCDEN) != 0) + fprintf(stderr, + "%s: jtag3_initialize(): warning: OCDEN fuse not programmed, " + "single-byte EEPROM updates not possible\n", + progname); + } + + return 0; +} + +static void jtag3_disable(PROGRAMMER * pgm) +{ + + free(PDATA(pgm)->flash_pagecache); + PDATA(pgm)->flash_pagecache = NULL; + free(PDATA(pgm)->eeprom_pagecache); + PDATA(pgm)->eeprom_pagecache = NULL; + + /* + * jtag3_program_disable() doesn't do anything if the + * device is currently not in programming mode, so just + * call it unconditionally here. + */ + (void)jtag3_program_disable(pgm); +} + +static void jtag3_enable(PROGRAMMER * pgm) +{ + return; +} + +static int jtag3_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: jtag3_parseextparms(): invalid JTAG chain '%s'\n", + progname, extended_param); + rv = -1; + continue; + } + if (verbose >= 2) { + fprintf(stderr, + "%s: jtag3_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: jtag3_parseextparms(): invalid extended parameter '%s'\n", + progname, extended_param); + rv = -1; + } + + return rv; +} + + +static int jtag3_open(PROGRAMMER * pgm, char * port) +{ + long baud; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_open()\n", progname); + + /* + * 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_frame; + baud = USB_DEVICE_JTAGICE3; + pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3; + pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3; + pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3; + pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3; +#else + fprintf(stderr, "avrdude was compiled without usb support.\n"); + return -1; +#endif + } + + strcpy(pgm->port, port); + if (serial_open(port, baud, &pgm->fd)==-1) { + return -1; + } + + /* + * drain any extraneous input + */ + jtag3_drain(pgm, 0); + + if (jtag3_getsync(pgm, PARM3_CONN_JTAG) < 0) + return -1; + + return 0; +} + +static int jtag3_open_dw(PROGRAMMER * pgm, char * port) +{ + long baud; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_open_dw()\n", progname); + + /* + * 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_frame; + baud = USB_DEVICE_JTAGICE3; + pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3; + pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3; + pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3; + pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3; +#else + fprintf(stderr, "avrdude was compiled without usb support.\n"); + return -1; +#endif + } + + strcpy(pgm->port, port); + if (serial_open(port, baud, &pgm->fd)==-1) { + return -1; + } + + /* + * drain any extraneous input + */ + jtag3_drain(pgm, 0); + + if (jtag3_getsync(pgm, PARM3_CONN_DW) < 0) + return -1; + + return 0; +} + +static int jtag3_open_pdi(PROGRAMMER * pgm, char * port) +{ + long baud; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_open_pdi()\n", progname); + + /* + * 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_frame; + baud = USB_DEVICE_JTAGICE3; + pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3; + pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3; + pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3; + pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3; +#else + fprintf(stderr, "avrdude was compiled without usb support.\n"); + return -1; +#endif + } + + strcpy(pgm->port, port); + if (serial_open(port, baud, &pgm->fd)==-1) { + return -1; + } + + /* + * drain any extraneous input + */ + jtag3_drain(pgm, 0); + + if (jtag3_getsync(pgm, PARM3_CONN_PDI) < 0) + return -1; + + return 0; +} + + +void jtag3_close(PROGRAMMER * pgm) +{ + unsigned char buf[4], *resp; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_close()\n", progname); + +#if 0 + if (pgm->flag & PGM_FL_IS_PDI) { + /* When in PDI mode, restart target. */ + buf[0] = CMND_GO; + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_close(): Sending GO command: ", + progname); + jtag3_send(pgm, buf, 1); + + status = jtag3_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtag3_close(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + } else { + if (verbose >= 3) { + putc('\n', stderr); + jtag3_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[1], status); + c = resp[1]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtag3_close(): " + "bad response to GO command: %s\n", + progname, jtag3_get_rc(c)); + } + } + } +#endif + + buf[0] = SCOPE_AVR; + buf[1] = CMD3_SIGN_OFF; + buf[2] = buf[3] = 0; + + if (jtag3_command(pgm, buf, 3, &resp, "AVR sign-off") >= 0) + free(resp); + + buf[0] = SCOPE_GENERAL; + buf[1] = CMD3_SIGN_OFF; + + if (jtag3_command(pgm, buf, 4, &resp, "sign-off") >= 0) + free(resp); + + serial_close(&pgm->fd); + pgm->fd.ifd = -1; +} + +static int jtag3_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int addr) +{ +#if 0 + unsigned char cmd[6]; + unsigned char *resp; + int status, tries; + long otimeout = serial_recv_timeout; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_page_erase(.., %s, 0x%x)\n", + progname, m->desc, addr); + + if (!(p->flags & AVRPART_HAS_PDI)) { + fprintf(stderr, "%s: jtag3_page_erase: not an Xmega device\n", + progname); + return -1; + } + if ((pgm->flag & PGM_FL_IS_DW)) { + fprintf(stderr, "%s: jtag3_page_erase: not applicable to debugWIRE\n", + progname); + return -1; + } + + if (jtag3_program_enable(pgm) < 0) + return -1; + + cmd[0] = CMND_XMEGA_ERASE; + if (strcmp(m->desc, "flash") == 0) { + if (jtag3_memtype(pgm, p, addr) == MTYPE_FLASH) + cmd[1] = XMEGA_ERASE_APP_PAGE; + else + cmd[1] = XMEGA_ERASE_BOOT_PAGE; + } else if (strcmp(m->desc, "eeprom") == 0) { + cmd[1] = XMEGA_ERASE_EEPROM_PAGE; + } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) { + cmd[1] = XMEGA_ERASE_USERSIG; + } else if ( ( strcmp(m->desc, "boot") == 0 ) ) { + cmd[1] = XMEGA_ERASE_BOOT_PAGE; + } else { + cmd[1] = XMEGA_ERASE_APP_PAGE; + } + serial_recv_timeout = 100; + + /* + * Don't use jtag3_memaddr() here. While with all other + * commands, firmware 7+ doesn't require the NVM offsets being + * applied, the erase page commands make an exception, and do + * require the NVM offsets as part of the (page) address. + */ + u32_to_b4(cmd + 2, addr + m->offset); + + tries = 0; + + retry: + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_page_erase(): " + "Sending xmega erase command: ", + progname); + jtag3_send(pgm, cmd, sizeof cmd); + + status = jtag3_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + if (verbose >= 1) + fprintf(stderr, + "%s: jtag3_page_erase(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + if (tries++ < 4) { + serial_recv_timeout *= 2; + goto retry; + } + fprintf(stderr, + "%s: jtag3_page_erase(): fatal timeout/" + "error communicating with programmer (status %d)\n", + progname, status); + serial_recv_timeout = otimeout; + return -1; + } + if (verbose >= 3) { + putc('\n', stderr); + jtag3_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[1], status); + if (resp[1] != RSP_OK) { + fprintf(stderr, + "%s: jtag3_page_erase(): " + "bad response to xmega erase command: %s\n", + progname, jtag3_get_rc(resp[1])); + free(resp); + serial_recv_timeout = otimeout; + return -1; + } + free(resp); + + serial_recv_timeout = otimeout; + +#endif + return 0; +} + +static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int page_size, + unsigned int addr, unsigned int n_bytes) +{ + unsigned int block_size; + unsigned int maxaddr = addr + n_bytes; + unsigned char *cmd; + unsigned char *resp; + int status, dynamic_memtype = 0; + long otimeout = serial_recv_timeout; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_paged_write(.., %s, %d, %d)\n", + progname, m->desc, page_size, n_bytes); + + if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0) + return -1; + + if (page_size == 0) page_size = 256; + + if ((cmd = malloc(page_size + 13)) == NULL) { + fprintf(stderr, "%s: jtag3_paged_write(): Out of memory\n", + progname); + return -1; + } + + cmd[0] = SCOPE_AVR; + cmd[1] = CMD3_WRITE_MEMORY; + cmd[2] = 0; + if (strcmp(m->desc, "flash") == 0) { + PDATA(pgm)->flash_pageaddr = (unsigned long)-1L; + cmd[3] = jtag3_memtype(pgm, p, addr); + if (p->flags & AVRPART_HAS_PDI) + /* dynamically decide between flash/boot memtype */ + dynamic_memtype = 1; + } else if (strcmp(m->desc, "eeprom") == 0) { + if (pgm->flag & PGM_FL_IS_DW) { + /* + * jtag3_paged_write() to EEPROM attempted while in + * DW mode. Use jtag3_write_byte() instead. + */ + for (; addr < maxaddr; addr++) { + status = jtag3_write_byte(pgm, p, m, addr, m->buf[addr]); + if (status < 0) { + free(cmd); + return -1; + } + } + free(cmd); + return n_bytes; + } + cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE; + PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; + } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) { + cmd[3] = MTYPE_USERSIG; + } else if ( ( strcmp(m->desc, "boot") == 0 ) ) { + cmd[3] = MTYPE_BOOT_FLASH; + } else if ( p->flags & AVRPART_HAS_PDI ) { + cmd[3] = MTYPE_FLASH; + } else { + cmd[3] = MTYPE_SPM; + } + serial_recv_timeout = 100; + for (; addr < maxaddr; addr += page_size) { + if ((maxaddr - addr) < page_size) + block_size = maxaddr - addr; + else + block_size = page_size; + if (verbose >= 3) + fprintf(stderr, "%s: jtag3_paged_write(): " + "block_size at addr %d is %d\n", + progname, addr, block_size); + + if (dynamic_memtype) + cmd[3] = jtag3_memtype(pgm, p, addr); + + u32_to_b4(cmd + 8, page_size); + u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, m, addr)); + cmd[12] = 0; + + /* + * 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 + 13, 0xff, page_size); + memcpy(cmd + 13, m->buf + addr, block_size); + + if ((status = jtag3_command(pgm, cmd, page_size + 13, + &resp, "write memory")) < 0) { + free(cmd); + serial_recv_timeout = otimeout; + return -1; + } + + free(resp); + } + + free(cmd); + serial_recv_timeout = otimeout; + + return n_bytes; +} + +static int jtag3_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int page_size, + unsigned int addr, unsigned int n_bytes) +{ + unsigned int block_size; + unsigned int maxaddr = addr + n_bytes; + unsigned char cmd[12]; + unsigned char *resp; + int status, dynamic_memtype = 0; + long otimeout = serial_recv_timeout; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_paged_load(.., %s, %d, %d)\n", + progname, m->desc, page_size, n_bytes); + + if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0) + return -1; + + page_size = m->readsize; + + cmd[0] = SCOPE_AVR; + cmd[1] = CMD3_READ_MEMORY; + cmd[2] = 0; + + if (strcmp(m->desc, "flash") == 0) { + cmd[3] = jtag3_memtype(pgm, p, addr); + if (p->flags & AVRPART_HAS_PDI) + /* dynamically decide between flash/boot memtype */ + dynamic_memtype = 1; + } else if (strcmp(m->desc, "eeprom") == 0) { + cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE; + if (pgm->flag & PGM_FL_IS_DW) + return -1; + } else if ( ( strcmp(m->desc, "prodsig") == 0 ) ) { + cmd[3] = MTYPE_PRODSIG; + } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) { + cmd[3] = MTYPE_USERSIG; + } else if ( ( strcmp(m->desc, "boot") == 0 ) ) { + cmd[3] = MTYPE_BOOT_FLASH; + } else if ( p->flags & AVRPART_HAS_PDI ) { + cmd[3] = MTYPE_FLASH; + } else { + cmd[3] = MTYPE_SPM; + } + serial_recv_timeout = 100; + for (; addr < maxaddr; addr += page_size) { + if ((maxaddr - addr) < page_size) + block_size = maxaddr - addr; + else + block_size = page_size; + if (verbose >= 3) + fprintf(stderr, "%s: jtag3_paged_load(): " + "block_size at addr %d is %d\n", + progname, addr, block_size); + + if (dynamic_memtype) + cmd[3] = jtag3_memtype(pgm, p, addr); + + u32_to_b4(cmd + 8, block_size); + u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, m, addr)); + + if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0) + return -1; + + if (resp[1] != RSP3_DATA || + status < block_size + 4) { + fprintf(stderr, "%s: wrong/short reply to read memory command\n", + progname); + serial_recv_timeout = otimeout; + free(resp); + return -1; + } + memcpy(m->buf + addr, resp + 3, status - 4); + free(resp); + } + serial_recv_timeout = otimeout; + + return n_bytes; +} + +static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char * value) +{ + unsigned char cmd[12]; + unsigned char *resp, *cache_ptr = NULL; + int status, unsupp = 0; + unsigned long paddr = 0UL, *paddr_ptr = NULL; + unsigned int pagesize = 0; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_read_byte(.., %s, 0x%lx, ...)\n", + progname, mem->desc, addr); + + if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0) + return -1; + + cmd[0] = SCOPE_AVR; + cmd[1] = CMD3_READ_MEMORY; + cmd[2] = 0; + + addr += mem->offset; + cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE; + if (strcmp(mem->desc, "flash") == 0 || + strcmp(mem->desc, "application") == 0 || + strcmp(mem->desc, "apptable") == 0 || + strcmp(mem->desc, "boot") == 0) { + pagesize = PDATA(pgm)->flash_pagesize; + 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) || ( p->flags & AVRPART_HAS_PDI ) ) { + /* debugWire cannot use page access for EEPROM */ + cmd[3] = MTYPE_EEPROM; + } else { + cmd[3] = 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[3] = MTYPE_FUSE_BITS; + addr = 0; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "hfuse") == 0) { + cmd[3] = MTYPE_FUSE_BITS; + addr = 1; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "efuse") == 0) { + cmd[3] = MTYPE_FUSE_BITS; + addr = 2; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "lock") == 0) { + cmd[3] = MTYPE_LOCK_BITS; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) { + cmd[3] = MTYPE_FUSE_BITS; + } else if (strcmp(mem->desc, "usersig") == 0) { + cmd[3] = MTYPE_USERSIG; + } else if (strcmp(mem->desc, "prodsig") == 0) { + cmd[3] = MTYPE_PRODSIG; + } else if (strcmp(mem->desc, "calibration") == 0) { + cmd[3] = MTYPE_OSCCAL_BYTE; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "signature") == 0) { + cmd[3] = MTYPE_SIGN_JTAG; + + if (pgm->flag & PGM_FL_IS_DW) { +#if 0 + /* + * 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 (jtag3_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; +#endif + } + + } + + /* + * 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 + 8, pagesize); + u32_to_b4(cmd + 4, paddr); + } else { + u32_to_b4(cmd + 8, 1); + u32_to_b4(cmd + 4, addr); + } + + if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0) + return -1; + + if (resp[1] != RSP3_DATA || + status < (pagesize? pagesize: 1) + 4) { + fprintf(stderr, "%s: wrong/short reply to read memory command\n", + progname); + free(resp); + return -1; + } + + if (pagesize) { + *paddr_ptr = paddr; + memcpy(cache_ptr, resp + 3, pagesize); + *value = cache_ptr[addr & (pagesize - 1)]; + } else + *value = resp[3]; + + free(resp); + return 0; +} + +static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, + unsigned long addr, unsigned char data) +{ + unsigned char cmd[14]; + unsigned char *resp; + int status, need_progmode = 1, unsupp = 0; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_write_byte(.., %s, 0x%lx, ...)\n", + progname, mem->desc, addr); + + addr += mem->offset; + + cmd[0] = SCOPE_AVR; + cmd[1] = CMD3_WRITE_MEMORY; + cmd[2] = 0; + cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_SPM; + if (strcmp(mem->desc, "flash") == 0) { + 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[3] = MTYPE_EEPROM; + need_progmode = 0; + PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; + } else if (strcmp(mem->desc, "lfuse") == 0) { + cmd[3] = MTYPE_FUSE_BITS; + addr = 0; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "hfuse") == 0) { + cmd[3] = MTYPE_FUSE_BITS; + addr = 1; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "efuse") == 0) { + cmd[3] = MTYPE_FUSE_BITS; + addr = 2; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) { + cmd[3] = MTYPE_FUSE_BITS; + } else if (strcmp(mem->desc, "usersig") == 0) { + cmd[3] = MTYPE_USERSIG; + } else if (strcmp(mem->desc, "prodsig") == 0) { + cmd[3] = MTYPE_PRODSIG; + } else if (strcmp(mem->desc, "lock") == 0) { + cmd[3] = MTYPE_LOCK_BITS; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "calibration") == 0) { + cmd[3] = MTYPE_OSCCAL_BYTE; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } else if (strcmp(mem->desc, "signature") == 0) { + cmd[3] = MTYPE_SIGN_JTAG; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } + + if (unsupp) + return -1; + + if (need_progmode) { + if (jtag3_program_enable(pgm) < 0) + return -1; + } else { + if (jtag3_program_disable(pgm) < 0) + return -1; + } + + u32_to_b4(cmd + 8, 1); + u32_to_b4(cmd + 4, addr); + cmd[12] = 0; + cmd[13] = data; + + if ((status = jtag3_command(pgm, cmd, 14, &resp, "write memory")) < 0) + return -1; + + 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 jtag3_set_sck_period(PROGRAMMER * pgm, double v) +{ +#if 0 + 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 jtag3_setparm(pgm, PAR_OCD_JTAG_CLK, &dur); +#endif + return 0; +} + + +/* + * Read (an) emulator parameter(s). + */ +int jtag3_getparm(PROGRAMMER * pgm, unsigned char scope, + unsigned char section, unsigned char parm, + unsigned char *value, unsigned char length) +{ + int status; + unsigned char buf[6], *resp, c; + char descr[60]; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_getparm()\n", progname); + + buf[0] = scope; + buf[1] = CMD3_GET_PARAMETER; + buf[2] = 0; + buf[3] = section; + buf[4] = parm; + buf[5] = length; + + sprintf(descr, "get parameter (scope 0x%02x, section %d, parm %d)", + scope, section, parm); + + if ((status = jtag3_command(pgm, buf, 6, &resp, descr)) < 0) + return -1; + + c = resp[1]; + if (c != RSP3_DATA || status < 3) { + fprintf(stderr, + "%s: jtag3_getparm(): " + "bad response to %s\n", + progname, descr); + free(resp); + return -1; + } + + status -= 3; + memcpy(value, resp + 3, (length < status? length: status)); + free(resp); + + return 0; +} + +/* + * Write an emulator parameter. + */ +static int jtag3_setparm(PROGRAMMER * pgm, unsigned char scope, + unsigned char section, unsigned char parm, + unsigned char *value, unsigned char length) +{ + int status; + unsigned char *buf, *resp; + char descr[60]; + + if (verbose >= 2) + fprintf(stderr, "%s: jtag3_setparm()\n", progname); + + sprintf(descr, "set parameter (scope 0x%02x, section %d, parm %d)", + scope, section, parm); + + if ((buf = malloc(6 + length)) == NULL) + { + fprintf(stderr, "%s: jtag3_setparm(): Out of memory\n", + progname); + return -1; + } + + buf[0] = scope; + buf[1] = CMD3_SET_PARAMETER; + buf[2] = 0; + buf[3] = section; + buf[4] = parm; + buf[5] = length; + memcpy(buf + 6, value, length); + + status = jtag3_command(pgm, buf, length + 6, &resp, descr); + + free(buf); + free(resp); + + return status; +} + + +static void jtag3_display(PROGRAMMER * pgm, const char * p) +{ + unsigned char parms[5]; + unsigned char cmd[4], *resp, c; + int status; + + /* + * Ask for: + * PARM3_HW_VER (1 byte) + * PARM3_FW_MAJOR (1 byte) + * PARM3_FW_MINOR (1 byte) + * PARM3_FW_RELEASE (2 bytes) + */ + if (jtag3_getparm(pgm, SCOPE_GENERAL, 0, PARM3_HW_VER, parms, 5) < 0) + return; + + cmd[0] = SCOPE_INFO; + cmd[1] = CMD3_GET_INFO; + cmd[2] = 0; + cmd[3] = CMD3_INFO_SERIAL; + + if ((status = jtag3_command(pgm, cmd, 4, &resp, "get info (serial number)")) < 0) + return; + + c = resp[1]; + if (c != RSP3_INFO) { + fprintf(stderr, + "%s: jtag3_display(): response is not RSP3_INFO\n", + progname); + free(resp); + return; + } + memmove(resp, resp + 3, status - 3); + resp[status - 3] = 0; + + fprintf(stderr, "%sICE hardware version: %d\n", p, parms[0]); + fprintf(stderr, "%sICE firmware version: %d.%02d (rel. %d)\n", p, + parms[1], parms[2], + (parms[3] | (parms[4] << 8))); + fprintf(stderr, "%sSerial number : %s\n", p, resp); + free(resp); + + jtag3_print_parms1(pgm, p); +} + + +static void jtag3_print_parms1(PROGRAMMER * pgm, const char * p) +{ + unsigned char buf[2]; + + if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0) + return; + + fprintf(stderr, "%sVtarget : %.2f V\n", p, + b2_to_u16(buf) / 1000.0); + + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0) + return; + fprintf(stderr, "%sJTAG clock megaAVR/program: %u kHz\n", p, + b2_to_u16(buf)); + + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0) + return; + fprintf(stderr, "%sJTAG clock megaAVR/debug: %u kHz\n", p, + b2_to_u16(buf)); + + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0) + return; + fprintf(stderr, "%sJTAG clock Xmega: %u kHz\n", p, + b2_to_u16(buf)); + + if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0) + return; + fprintf(stderr, "%sPDI clock Xmega : %u kHz\n", p, + b2_to_u16(buf)); +} + +static void jtag3_print_parms(PROGRAMMER * pgm) +{ + jtag3_print_parms1(pgm, ""); +} + +static unsigned char jtag3_memtype(PROGRAMMER * pgm, AVRPART * p, unsigned long addr) +{ + if ( p->flags & AVRPART_HAS_PDI ) { + if (addr >= PDATA(pgm)->boot_start) + return MTYPE_BOOT_FLASH; + else + return MTYPE_FLASH; + } else { + return MTYPE_FLASH_PAGE; + } +} + +static unsigned int jtag3_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr) +{ +#if 0 + /* + * Xmega devices handled by V7+ firmware don't want to be told their + * m->offset within the write memory command. + */ + if (PDATA(pgm)->fwver >= 0x700 && (p->flags & AVRPART_HAS_PDI) != 0) { + if (addr >= PDATA(pgm)->boot_start) + /* + * all memories but "flash" are smaller than boot_start anyway, so + * no need for an extra check we are operating on "flash" + */ + return addr - PDATA(pgm)->boot_start; + else + /* normal flash, or anything else */ + return addr; + } + /* + * Old firmware, or non-Xmega device. Non-Xmega (and non-AVR32) + * devices always have an m->offset of 0, so we don't have to + * distinguish them here. + */ +#endif + return addr + m->offset; +} + + +const char jtag3_desc[] = "Atmel JTAGICE3"; + +void jtag3_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "JTAGICE3"); + + /* + * mandatory functions + */ + pgm->initialize = jtag3_initialize; + pgm->display = jtag3_display; + pgm->enable = jtag3_enable; + pgm->disable = jtag3_disable; + pgm->program_enable = jtag3_program_enable_dummy; + pgm->chip_erase = jtag3_chip_erase; + pgm->open = jtag3_open; + pgm->close = jtag3_close; + pgm->read_byte = jtag3_read_byte; + pgm->write_byte = jtag3_write_byte; + + /* + * optional functions + */ + pgm->paged_write = jtag3_paged_write; + pgm->paged_load = jtag3_paged_load; + pgm->page_erase = jtag3_page_erase; + pgm->print_parms = jtag3_print_parms; + pgm->set_sck_period = jtag3_set_sck_period; + pgm->parseextparams = jtag3_parseextparms; + pgm->setup = jtag3_setup; + pgm->teardown = jtag3_teardown; + pgm->page_size = 256; + pgm->flag = PGM_FL_IS_JTAG; +} + +const char jtag3_dw_desc[] = "Atmel JTAGICE3 in debugWire mode"; + +void jtag3_dw_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "JTAGICE3_DW"); + + /* + * mandatory functions + */ + pgm->initialize = jtag3_initialize; + pgm->display = jtag3_display; + pgm->enable = jtag3_enable; + pgm->disable = jtag3_disable; + pgm->program_enable = jtag3_program_enable_dummy; + pgm->chip_erase = jtag3_chip_erase_dw; + pgm->open = jtag3_open_dw; + pgm->close = jtag3_close; + pgm->read_byte = jtag3_read_byte; + pgm->write_byte = jtag3_write_byte; + + /* + * optional functions + */ + pgm->paged_write = jtag3_paged_write; + pgm->paged_load = jtag3_paged_load; + pgm->print_parms = jtag3_print_parms; + pgm->setup = jtag3_setup; + pgm->teardown = jtag3_teardown; + pgm->page_size = 256; + pgm->flag = PGM_FL_IS_DW; +} + +const char jtag3_pdi_desc[] = "Atmel JTAGICE3 in PDI mode"; + +void jtag3_pdi_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "JTAGICE3_PDI"); + + /* + * mandatory functions + */ + pgm->initialize = jtag3_initialize; + pgm->display = jtag3_display; + pgm->enable = jtag3_enable; + pgm->disable = jtag3_disable; + pgm->program_enable = jtag3_program_enable_dummy; + pgm->chip_erase = jtag3_chip_erase; + pgm->open = jtag3_open_pdi; + pgm->close = jtag3_close; + pgm->read_byte = jtag3_read_byte; + pgm->write_byte = jtag3_write_byte; + + /* + * optional functions + */ + pgm->paged_write = jtag3_paged_write; + pgm->paged_load = jtag3_paged_load; + pgm->page_erase = jtag3_page_erase; + pgm->print_parms = jtag3_print_parms; + pgm->setup = jtag3_setup; + pgm->teardown = jtag3_teardown; + pgm->page_size = 256; + pgm->flag = PGM_FL_IS_PDI; +} + diff --git a/jtag3.h b/jtag3.h new file mode 100644 index 00000000..107d5f32 --- /dev/null +++ b/jtag3.h @@ -0,0 +1,54 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2012 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, see . + */ + +/* $Id$ */ + +#ifndef jtag3_h +#define jtag3_h + +#ifdef __cplusplus +extern "C" { +#endif + +int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len); +int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg); +void jtag3_close(PROGRAMMER * pgm); +int jtag3_getsync(PROGRAMMER * pgm, int mode); +int jtag3_getparm(PROGRAMMER * pgm, unsigned char scope, + unsigned char section, unsigned char parm, + unsigned char *value, unsigned char length); +extern const char jtag3_desc[]; +extern const char jtag3_dw_desc[]; +extern const char jtag3_pdi_desc[]; +void jtag3_initpgm (PROGRAMMER * pgm); +void jtag3_dw_initpgm (PROGRAMMER * pgm); +void jtag3_pdi_initpgm (PROGRAMMER * pgm); + +/* + * These functions are referenced from stk500v2.c for JTAGICE3 in + * one of the STK500v2 modi. + */ +void jtag3_setup(PROGRAMMER * pgm); +void jtag3_teardown(PROGRAMMER * pgm); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/jtag3_private.h b/jtag3_private.h new file mode 100644 index 00000000..156eaf90 --- /dev/null +++ b/jtag3_private.h @@ -0,0 +1,271 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2012 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, see . + */ + +/* $Id$ */ + + +/* + * JTAGICE3 definitions + * Reverse-engineered from various USB traces. + */ + +#if !defined(JTAG3_PRIVATE_EXPORTED) +/* + * Communication with the JTAGICE3 uses three data endpoints: + * + * Endpoint 0x01 (OUT) and 0x82 (IN) are the usual conversation + * endpoints, with a maximal packet size of 512 octets. The + * JTAGICE3 does *not* work on older USB 1.1 hubs that would only + * allow for 64-octet max packet size. + * + * Endpoint 0x83 (IN) is also a bulk endpoint, with a max packetsize + * of 64 octets. This endpoint is used by the ICE to deliver events + * from the ICE. + * + * The request (host -> ICE, EP 0x01) format is: + * + * +--------------------------------------------- + * | 0 | 1 | 2 . 3 | 4 | 5 | 6 | ... + * | | | | | | | + * | token |dummy|serial# |scope| cmd |dummy| optional data + * | 0x0e | 0 | NNNN | SS | CC | 0 | ... + * +--------------------------------------------- + * + * Both dummy bytes are always 0. The "scope" identifier appears + * to distinguish commands (responses, events, parameters) roughly: + * + * 0x01 - general scope ("hello", "goodbye", firmware info, target + * voltage readout) + * 0x11 - scope for AVR in ISP mode (basically a wrapper around + * the AVRISPmkII commands, as usual) + * 0x12 - scope for AVR (JTAG, PDI, debugWIRE) + * + * The serial number is counted up. + * + * + * The response (ICE -> host, EP 0x82) format is: + * + * +--------------------------------------------------+ + * | 0 | 1 . 2 | 3 | 4 | ... | N | + * | | | | | | | + * | token |serial# |scope| rsp | optional data |dummy| + * | 0x0e | NNNN | SS | RR | ... | 0 | + * +--------------------------------------------------+ + * + * The response's serial number is mirrored from the request, but the + * dummy byte before the serial number is left out. However, another + * zero dummy byte is always attached to the end of the response data. + * Response codes are similar to the JTAGICEmkII, 0x80 is a generic + * "OK" response, other responses above 0x80 indicate various data + * responses (parameter read, memory read, PC value), and 0xa0 is a + * generic "failure" response. It appears the failure response gets + * another byte appended (probably indicating the reason) after the + * 0 dummy byte, but there's not enough analysis material so far. + * + * + * The event format (EP 0x83) is: + * + * +---------------------------------------- + * | 0 | 1 | 2 . 3 | 4 | 5 | ... + * | | | | | | + * | token |dummy|serial# |scope| evt | data + * | 0x0e | 0 | NNNN | SS | EV | ... + * +---------------------------------------- + */ +#define TOKEN 0x0e + +#endif /* JTAG3_PRIVATE_EXPORTED */ + +#define SCOPE_INFO 0x00 +#define SCOPE_GENERAL 0x01 +#define SCOPE_AVR_ISP 0x11 +#define SCOPE_AVR 0x12 + +/* Info scope */ +#define CMD3_GET_INFO 0x00 + +/* byte after GET_INFO is always 0, next is: */ +# define CMD3_INFO_NAME 0x80 /* JTAGICE3 */ +# define CMD3_INFO_SERIAL 0x81 /* J3xxxxxxxxxx */ + +/* Generic scope */ +#define CMD3_SET_PARAMETER 0x01 +#define CMD3_GET_PARAMETER 0x02 +#define CMD3_SIGN_ON 0x10 +#define CMD3_SIGN_OFF 0x11 /* takes one parameter? */ + +/* AVR ISP scope: no commands of its own */ + +/* AVR scope */ +//#define CMD3_SET_PARAMETER 0x01 +//#define CMD3_GET_PARAMETER 0x02 +//#define CMD3_SIGN_ON 0x10 /* an additional signon/-off pair */ +//#define CMD3_SIGN_OFF 0x11 +#define CMD3_ENTER_PROGMODE 0x15 +#define CMD3_LEAVE_PROGMODE 0x16 +#define CMD3_ERASE_MEMORY 0x20 +#define CMD3_READ_MEMORY 0x21 +#define CMD3_WRITE_MEMORY 0x23 +#define CMD3_READ_PC 0x35 + +/* ICE responses */ +#define RSP3_OK 0x80 +#define RSP3_INFO 0x81 +#define RSP3_PC 0x83 +#define RSP3_DATA 0x84 +#define RSP3_FAILED 0xA0 + +#define RSP3_STATUS_MASK 0xE0 + +/* possible failure codes that could be appended to RSP3_FAILED: */ +# define RSP3_FAIL_NO_ANSWER 0x20 +# define RSP3_FAIL_NO_TARGET_POWER 0x22 +# define RSP3_FAIL_WRONG_MODE 0x32 /* progmode vs. non-prog */ +# define RSP3_FAIL_NOT_UNDERSTOOD 0x91 + +/* ICE events */ +#define EVT3_BREAK 0x40 /* AVR scope */ +#define EVT3_SLEEP 0x11 /* General scope, also wakeup */ +#define EVT3_POWER 0x10 /* General scope */ + +/* memory types */ +#define MTYPE_SRAM 0x20 /* target's SRAM or [ext.] IO registers */ +#define MTYPE_EEPROM 0x22 /* EEPROM, what way? */ +#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_FLASH 0xc0 /* xmega (app.) flash - undocumented in AVR067 */ +#define MTYPE_BOOT_FLASH 0xc1 /* xmega boot flash - undocumented in AVR067 */ +#define MTYPE_USERSIG 0xc5 /* xmega user signature - undocumented in AVR067 */ +#define MTYPE_PRODSIG 0xc6 /* xmega production signature - undocumented in AVR067 */ + +/* + * Parameters are divided into sections, where the section number + * precedes each parameter address. There are distinct parameter + * sets for generic and AVR scope. + */ +#define PARM3_HW_VER 0x00 /* section 0, generic scope, 1 byte */ +#define PARM3_FW_MAJOR 0x01 /* section 0, generic scope, 1 byte */ +#define PARM3_FW_MINOR 0x02 /* section 0, generic scope, 1 byte */ +#define PARM3_FW_RELEASE 0x03 /* section 0, generic scope, 1 byte; + * always asked for by Atmel Studio, + * but never displayed there */ +#define PARM3_VTARGET 0x00 /* section 1, generic scope, 2 bytes, + * in millivolts */ +#define PARM3_DEVICEDESC 0x00 /* section 2, memory etc. configuration, + * 31 bytes for tiny/mega AVR, 47 bytes + * for Xmega; is also used in command + * 0x36 in JTAGICEmkII, starting with + * firmware 7.x */ + +#define PARM3_ARCH 0x00 /* section 0, AVR scope, 1 byte */ +# define PARM3_ARCH_TINY 1 /* also small megaAVR with ISP/DW only */ +# define PARM3_ARCH_MEGA 2 +# define PARM3_ARCH_XMEGA 3 + +#define PARM3_SESS_PURPOSE 0x01 /* section 0, AVR scope, 1 byte */ +# define PARM3_SESS_PROGRAMMING 1 +# define PARM3_SESS_DEBUGGING 2 + +#define PARM3_CONNECTION 0x00 /* section 1, AVR scope, 1 byte */ +# define PARM3_CONN_ISP 1 +# define PARM3_CONN_JTAG 4 +# define PARM3_CONN_DW 5 +# define PARM3_CONN_PDI 6 + + +#define PARM3_JTAGCHAIN 0x01 /* JTAG chain info, AVR scope (units + * before/after, bits before/after), 4 + * bytes */ + +#define PARM3_CLK_MEGA_PROG 0x20 /* section 1, AVR scope, 2 bytes (kHz) */ +#define PARM3_CLK_MEGA_DEBUG 0x21 /* section 1, AVR scope, 2 bytes (kHz) */ +#define PARM3_CLK_XMEGA_JTAG 0x30 /* section 1, AVR scope, 2 bytes (kHz) */ +#define PARM3_CLK_XMEGA_PDI 0x31 /* section 1, AVR scope, 2 bytes (kHz) */ + + + +/* Xmega erase memory types, for CMND_XMEGA_ERASE */ +#define XMEGA_ERASE_CHIP 0x00 +#define XMEGA_ERASE_APP 0x01 +#define XMEGA_ERASE_BOOT 0x02 +#define XMEGA_ERASE_EEPROM 0x03 +#define XMEGA_ERASE_APP_PAGE 0x04 +#define XMEGA_ERASE_BOOT_PAGE 0x05 +#define XMEGA_ERASE_EEPROM_PAGE 0x06 +#define XMEGA_ERASE_USERSIG 0x07 + +#if !defined(JTAG3_PRIVATE_EXPORTED) + +struct mega_device_desc { + unsigned char flash_page_size[2]; // in bytes + unsigned char flash_size[4]; // in bytes + unsigned char dummy1[4]; // always 0 + unsigned char boot_address[4]; // maximal (BOOTSZ = 3) bootloader + // address, in 16-bit words (!) + unsigned char sram_offset[2]; // pointing behind IO registers + unsigned char eeprom_size[2]; + unsigned char eeprom_page_size; + unsigned char ocd_revision; // see XML; basically: + // t13*, t2313*, t4313: 0 + // all other DW devices: 1 + // ATmega128(A): 1 (!) + // ATmega16*,162,169*,32*,64*: 2 + // ATmega2560/2561: 4 + // all other megaAVR devices: 3 + unsigned char always_one; // always = 1 + unsigned char allow_full_page_bitstream; // old AVRs, see XML + unsigned char dummy2[2]; // always 0 + // all IO addresses below are given + // in IO number space (without + // offset 0x20), even though e.g. + // OSCCAL always resides outside + unsigned char idr_address; // IDR, aka. OCDR + unsigned char eearh_address; // EEPROM access + unsigned char eearl_address; + unsigned char eecr_address; + unsigned char eedr_address; + unsigned char spmcr_address; + unsigned char osccal_address; +}; + + +/* Xmega device descriptor */ +struct xmega_device_desc { + unsigned char nvm_app_offset[4]; // NVM offset for application flash + unsigned char nvm_boot_offset[4]; // NVM offset for boot flash + unsigned char nvm_eeprom_offset[4]; // NVM offset for EEPROM + unsigned char nvm_fuse_offset[4]; // NVM offset for fuses + unsigned char nvm_lock_offset[4]; // NVM offset for lock bits + unsigned char nvm_user_sig_offset[4]; // NVM offset for user signature row + unsigned char nvm_prod_sig_offset[4]; // NVM offset for production sign. row + unsigned char nvm_data_offset[4]; // NVM offset for data memory (SRAM + IO) + unsigned char app_size[4]; // size of application flash + unsigned char boot_size[2]; // size of boot flash + unsigned char flash_page_size[2]; // flash page size + unsigned char eeprom_size[2]; // size of EEPROM + unsigned char eeprom_page_size; // EEPROM page size + unsigned char nvm_base_addr[2]; // IO space base address of NVM controller + unsigned char mcu_base_addr[2]; // IO space base address of MCU control +}; +#endif /* JTAG3_PRIVATE_EXPORTED */ diff --git a/pgm_type.c b/pgm_type.c index e0cc8311..4aadc001 100644 --- a/pgm_type.c +++ b/pgm_type.c @@ -37,6 +37,7 @@ #include "ft245r.h" #include "jtagmkI.h" #include "jtagmkII.h" +#include "jtag3.h" #include "par.h" #include "pickit2.h" #include "ppi.h" @@ -69,6 +70,9 @@ const PROGRAMMER_TYPE const programmers_types[] = { {"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc}, {"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc}, {"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc}, + {"jtagice3", jtag3_initpgm, jtag3_desc}, + {"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc}, + {"jtagice3_dw", jtag3_dw_initpgm, jtag3_dw_desc}, {"par", par_initpgm, par_desc}, {"pickit2", pickit2_initpgm, pickit2_desc}, {"serbb", serbb_initpgm, serbb_desc}, diff --git a/usb_libusb.c b/usb_libusb.c index 86d969c7..35bdbfa4 100644 --- a/usb_libusb.c +++ b/usb_libusb.c @@ -52,7 +52,7 @@ # undef interface #endif -static char usbbuf[USBDEV_MAX_XFER_MKII]; +static char usbbuf[USBDEV_MAX_XFER_3]; static int buflen = -1, bufptr; static int usb_interface; @@ -399,6 +399,32 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_ int i; unsigned char * p = buf; + /* If there's an event EP, and it has data pending, return it first. */ + if (fd->usb.eep != 0) + { + rv = usb_bulk_read(udev, fd->usb.eep, usbbuf, + fd->usb.max_xfer, 1); + if (rv > 4) + { + if (verbose >= 3) + { + unsigned short evtserial = (usbbuf[3] << 8) | usbbuf[2]; + fprintf(stderr, "Event serial # 0x%04x, replaced by 0xffff\n", + evtserial); + } + usbbuf[3] = usbbuf[2] = 0xff; + memcpy(buf, usbbuf + 2, rv - 2); + n = rv - 2; + goto printout; + } + else if (rv > 0) + { + fprintf(stderr, "Short event len = %d, ignored.\n", rv); + n = rv; + goto printout; + } + } + n = 0; do { @@ -426,6 +452,7 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_ if (nbytes < 0) return -1; + printout: if (verbose > 3) { i = n; diff --git a/usbdevs.h b/usbdevs.h index 6bbfbf16..e4523324 100644 --- a/usbdevs.h +++ b/usbdevs.h @@ -30,10 +30,17 @@ #define USB_DEVICE_AVRISPMKII 0x2104 #define USB_DEVICE_STK600 0x2106 #define USB_DEVICE_AVRDRAGON 0x2107 +#define USB_DEVICE_JTAGICE3 0x2110 /* JTAGICEmkII */ #define USBDEV_BULK_EP_WRITE_MKII 0x02 #define USBDEV_BULK_EP_READ_MKII 0x82 #define USBDEV_MAX_XFER_MKII 64 +/* JTAGICE3 */ +#define USBDEV_BULK_EP_WRITE_3 0x01 +#define USBDEV_BULK_EP_READ_3 0x82 +#define USBDEV_EVT_EP_READ_3 0x83 +#define USBDEV_MAX_XFER_3 512 + #endif /* usbdevs_h */