/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2005, 2007 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 JTAG ICE (mkI) programmer */ #include "ac_cfg.h" #include #include #include #include #include #include #include #include "avrdude.h" #include "libavrdude.h" #include "crc16.h" #include "jtagmkI.h" #include "jtagmkI_private.h" /* * Private data for this programmer. */ struct pdata { int initial_baudrate; /* * See jtagmkI_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. */ }; #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) /* * Table of baud rates supported by the mkI ICE, accompanied by their * internal parameter value. * * 19200 is the initial value of the ICE after powerup, and virtually * all connections then switch to 115200. As the table is also used * to try connecting at startup, we keep these two entries on top to * speedup the program start. */ const static struct { long baud; unsigned char val; } baudtab[] = { { 19200L, 0xfa }, { 115200L, 0xff }, { 9600L, 0xf4 }, { 38400L, 0xfd }, { 57600L, 0xfe }, /* { 14400L, 0xf8 }, */ /* not supported by serial driver */ }; static int jtagmkI_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char * value); static int jtagmkI_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data); static int jtagmkI_set_sck_period(const PROGRAMMER *pgm, double v); static int jtagmkI_getparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char * value); static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char value); static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp); static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon); static void jtagmkI_setup(PROGRAMMER * pgm) { if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { pmsg_error("out of memory allocating private data\n"); exit(1); } memset(pgm->cookie, 0, sizeof(struct pdata)); } static void jtagmkI_teardown(PROGRAMMER * pgm) { free(pgm->cookie); } static void u32_to_b3(unsigned char *b, unsigned long l) { b[2] = l & 0xff; b[1] = (l >> 8) & 0xff; b[0] = (l >> 16) & 0xff; } static void u16_to_b2(unsigned char *b, unsigned short l) { b[0] = l & 0xff; b[1] = (l >> 8) & 0xff; } static void jtagmkI_prmsg(const PROGRAMMER *pgm, unsigned char *data, size_t len) { int i; if (verbose >= 4) { msg_trace("Raw message:\n"); for (i = 0; i < len; i++) { msg_trace("0x%02x ", data[i]); if (i % 16 == 15) msg_trace("\n"); else msg_trace(" "); } if (i % 16 != 0) msg_trace("\n"); } switch (data[0]) { case RESP_OK: msg_info("OK\n"); break; case RESP_FAILED: msg_info("FAILED\n"); break; case RESP_BREAK: msg_info("breakpoint hit\n"); break; case RESP_INFO: msg_info("IDR dirty\n"); break; case RESP_SYNC_ERROR: msg_info("Synchronization lost\n"); break; case RESP_SLEEP: msg_info("sleep instruction hit\n"); break; case RESP_POWER: msg_info("target power lost\n"); default: msg_info("unknown message 0x%02x\n", data[0]); } msg_info("\n"); } static int jtagmkI_send(const PROGRAMMER *pgm, unsigned char *data, size_t len) { unsigned char *buf; msg_debug("\n"); pmsg_debug("jtagmkI_send(): sending %u bytes\n", (unsigned int) len); if ((buf = malloc(len + 2)) == NULL) { pmsg_error("out of memory"); exit(1); } memcpy(buf, data, len); buf[len] = ' '; /* "CRC" */ buf[len + 1] = ' '; /* EOP */ if (serial_send(&pgm->fd, buf, len + 2) != 0) { pmsg_error("unable to send command to serial port\n"); free(buf); return -1; } free(buf); return 0; } static int jtagmkI_recv(const PROGRAMMER *pgm, unsigned char *buf, size_t len) { if (serial_recv(&pgm->fd, buf, len) != 0) { msg_error("\n"); pmsg_error("unable to send command to serial port\n"); return -1; } if (verbose >= 3) { msg_debug("\n"); jtagmkI_prmsg(pgm, buf, len); } return 0; } static int jtagmkI_drain(const PROGRAMMER *pgm, int display) { return serial_drain(&pgm->fd, display); } static int jtagmkI_resync(const PROGRAMMER *pgm, int maxtries, int signon) { int tries; unsigned char buf[4], resp[9]; long otimeout = serial_recv_timeout; serial_recv_timeout = 200; pmsg_trace("jtagmkI_resync()\n"); jtagmkI_drain(pgm, 0); for (tries = 0; tries < maxtries; tries++) { /* Get the sign-on information. */ buf[0] = CMD_GET_SYNC; pmsg_notice2("jtagmkI_resync(): sending sync command: "); if (serial_send(&pgm->fd, buf, 1) != 0) { msg_error("\n"); pmsg_error("unable to send command to serial port\n"); serial_recv_timeout = otimeout; return -1; } if (serial_recv(&pgm->fd, resp, 1) == 0 && resp[0] == RESP_OK) { msg_notice2("got RESP_OK\n"); break; } if (signon) { /* * The following is black magic, the idea has been taken from * AVaRICE. * * Apparently, the ICE behaves differently right after a * power-up vs. when reconnecting to an ICE that has already * been worked with. The undocumented 'E' command (or * subcommand) occasionally helps in getting the connection into * sync. */ buf[0] = CMD_GET_SIGNON; buf[1] = 'E'; buf[2] = ' '; buf[3] = ' '; pmsg_notice2("jtagmkI_resync(): sending sign-on command: "); if (serial_send(&pgm->fd, buf, 4) != 0) { msg_error("\n"); pmsg_error("unable to send command to serial port\n"); serial_recv_timeout = otimeout; return -1; } if (serial_recv(&pgm->fd, resp, 9) == 0 && resp[0] == RESP_OK) { msg_notice2("got RESP_OK\n"); break; } } } if (tries >= maxtries) { pmsg_notice2("jtagmkI_resync(): " "timeout/error communicating with programmer\n"); serial_recv_timeout = otimeout; return -1; } serial_recv_timeout = otimeout; return 0; } static int jtagmkI_getsync(const PROGRAMMER *pgm) { unsigned char buf[1], resp[9]; if (jtagmkI_resync(pgm, 5, 1) < 0) { jtagmkI_drain(pgm, 0); return -1; } jtagmkI_drain(pgm, 0); pmsg_notice2("jtagmkI_getsync(): sending sign-on command; "); buf[0] = CMD_GET_SIGNON; jtagmkI_send(pgm, buf, 1); if (jtagmkI_recv(pgm, resp, 9) < 0) return -1; resp[8] = '\0'; msg_notice2("got %s\n", resp + 1); return 0; } /* * issue the 'chip erase' command to the AVR device */ static int jtagmkI_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char buf[1], resp[2]; buf[0] = CMD_CHIP_ERASE; pmsg_notice2("jtagmkI_chip_erase(): sending chip erase command: "); jtagmkI_send(pgm, buf, 1); if (jtagmkI_recv(pgm, resp, 2) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } pgm->initialize(pgm, p); return 0; } static void jtagmkI_set_devdescr(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char resp[2]; LNODEID ln; AVRMEM * m; struct { unsigned char cmd; struct device_descriptor dd; } sendbuf; memset(&sendbuf, 0, sizeof sendbuf); sendbuf.cmd = CMD_SET_DEVICE_DESCRIPTOR; sendbuf.dd.ucSPMCRAddress = p->spmcr; sendbuf.dd.ucRAMPZAddress = p->rampz; sendbuf.dd.ucIDRAddress = p->idr; 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(sendbuf.dd.uiFlashPageSize, PDATA(pgm)->flash_pagesize); } else if (strcmp(m->desc, "eeprom") == 0) { sendbuf.dd.ucEepromPageSize = PDATA(pgm)->eeprom_pagesize = m->page_size; } } pmsg_notice2("jtagmkI_set_devdescr(): " "Sending set device descriptor command: "); jtagmkI_send(pgm, (unsigned char *)&sendbuf, sizeof(sendbuf)); if (jtagmkI_recv(pgm, resp, 2) < 0) return; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); } else { msg_notice2("OK\n"); } } /* * Reset the target. */ static int jtagmkI_reset(const PROGRAMMER *pgm) { unsigned char buf[1], resp[2]; buf[0] = CMD_RESET; pmsg_notice2("jtagmkI_reset(): sending reset command: "); jtagmkI_send(pgm, buf, 1); if (jtagmkI_recv(pgm, resp, 2) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } return 0; } static int jtagmkI_program_enable_dummy(const PROGRAMMER *pgm, const AVRPART *p) { return 0; } static int jtagmkI_program_enable(const PROGRAMMER *pgm) { unsigned char buf[1], resp[2]; if (PDATA(pgm)->prog_enabled) return 0; buf[0] = CMD_ENTER_PROGMODE; pmsg_notice2("jtagmkI_program_enable(): " "Sending enter progmode command: "); jtagmkI_send(pgm, buf, 1); if (jtagmkI_recv(pgm, resp, 2) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } PDATA(pgm)->prog_enabled = 1; return 0; } static int jtagmkI_program_disable(const PROGRAMMER *pgm) { unsigned char buf[1], resp[2]; if (!PDATA(pgm)->prog_enabled) return 0; if (pgm->fd.ifd != -1) { buf[0] = CMD_LEAVE_PROGMODE; pmsg_notice2("jtagmkI_program_disable(): sending leave progmode command: "); jtagmkI_send(pgm, buf, 1); if (jtagmkI_recv(pgm, resp, 2) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } } PDATA(pgm)->prog_enabled = 0; return 0; } static unsigned char jtagmkI_get_baud(long baud) { 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 jtagmkI_initialize(const PROGRAMMER *pgm, const AVRPART *p) { AVRMEM hfuse; unsigned char cmd[1], resp[5]; unsigned char b; if (!(p->prog_modes & (PM_JTAGmkI | PM_JTAG))) { pmsg_error("part %s has no JTAG interface\n", p->desc); return -1; } if (!(p->prog_modes & PM_JTAGmkI)) pmsg_warning("part %s has JTAG interface, but may be too new\n", p->desc); jtagmkI_drain(pgm, 0); if ((serdev->flags & SERDEV_FL_CANSETSPEED) && PDATA(pgm)->initial_baudrate != pgm->baudrate) { if ((b = jtagmkI_get_baud(pgm->baudrate)) == 0) { pmsg_error("unsupported baudrate %d\n", pgm->baudrate); } else { pmsg_notice2("jtagmkI_initialize(): " "trying to set baudrate to %d\n", pgm->baudrate); if (jtagmkI_setparm(pgm, PARM_BITRATE, b) == 0) { PDATA(pgm)->initial_baudrate = pgm->baudrate; /* don't adjust again later */ serial_setparams(&pgm->fd, pgm->baudrate, SERIAL_8N1); } } } if (pgm->bitclock != 0.0) { pmsg_notice2("jtagmkI_initialize(): " "trying to set JTAG clock period to %.1f us\n", pgm->bitclock); if (jtagmkI_set_sck_period(pgm, pgm->bitclock) != 0) return -1; } cmd[0] = CMD_STOP; jtagmkI_send(pgm, cmd, 1); if (jtagmkI_recv(pgm, resp, 5) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_warning("timeout/error communicating with programmer (resp %c)\n", resp[0]); } else { msg_notice2("OK\n"); } /* * Must set the device descriptor before entering programming mode. */ jtagmkI_set_devdescr(pgm, p); jtagmkI_setparm(pgm, PARM_FLASH_PAGESIZE_LOW, PDATA(pgm)->flash_pagesize & 0xff); jtagmkI_setparm(pgm, PARM_FLASH_PAGESIZE_HIGH, PDATA(pgm)->flash_pagesize >> 8); jtagmkI_setparm(pgm, PARM_EEPROM_PAGESIZE, PDATA(pgm)->eeprom_pagesize & 0xff); free(PDATA(pgm)->flash_pagecache); free(PDATA(pgm)->eeprom_pagecache); if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) { pmsg_error("out of memory\n"); return -1; } if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) { pmsg_error("out of memory\n"); free(PDATA(pgm)->flash_pagecache); return -1; } PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; if (jtagmkI_reset(pgm) < 0) return -1; hfuse.desc = cache_string("hfuse"); if (jtagmkI_read_byte(pgm, p, &hfuse, 1, &b) < 0) return -1; if ((b & OCDEN) != 0) pmsg_warning("OCDEN fuse not programmed, " "single-byte EEPROM updates not possible\n"); return 0; } static void jtagmkI_disable(const PROGRAMMER *pgm) { free(PDATA(pgm)->flash_pagecache); PDATA(pgm)->flash_pagecache = NULL; free(PDATA(pgm)->eeprom_pagecache); PDATA(pgm)->eeprom_pagecache = NULL; (void)jtagmkI_program_disable(pgm); } static void jtagmkI_enable(PROGRAMMER *pgm, const AVRPART *p) { return; } static int jtagmkI_open(PROGRAMMER *pgm, const char *port) { size_t i; pmsg_notice2("jtagmkI_open()\n"); strcpy(pgm->port, port); PDATA(pgm)->initial_baudrate = -1L; for (i = 0; i < sizeof(baudtab) / sizeof(baudtab[0]); i++) { union pinfo pinfo; pinfo.serialinfo.baud = baudtab[i].baud; pinfo.serialinfo.cflags = SERIAL_8N1; pmsg_notice2("jtagmkI_open(): trying to sync at baud rate %ld:\n", pinfo.serialinfo.baud); if (serial_open(port, pinfo, &pgm->fd)==-1) { return -1; } /* * drain any extraneous input */ jtagmkI_drain(pgm, 0); if (jtagmkI_getsync(pgm) == 0) { PDATA(pgm)->initial_baudrate = baudtab[i].baud; pmsg_notice2("jtagmkI_open(): succeeded\n"); return 0; } serial_close(&pgm->fd); } pmsg_error("unable to synchronize to ICE\n"); pgm->fd.ifd = -1; return -1; } static void jtagmkI_close(PROGRAMMER * pgm) { unsigned char b; pmsg_notice2("jtagmkI_close()\n"); /* * Revert baud rate to what it used to be when we started. This * appears to make AVR Studio happier when it is about to access the * ICE later on. */ if ((serdev->flags & SERDEV_FL_CANSETSPEED) && PDATA(pgm)->initial_baudrate != pgm->baudrate) { if ((b = jtagmkI_get_baud(PDATA(pgm)->initial_baudrate)) == 0) { pmsg_error("unsupported baudrate %d\n", PDATA(pgm)->initial_baudrate); } else { pmsg_notice2("jtagmkI_close(): " "trying to set baudrate to %d\n", PDATA(pgm)->initial_baudrate); if (jtagmkI_setparm(pgm, PARM_BITRATE, b) == 0) { serial_setparams(&pgm->fd, pgm->baudrate, SERIAL_8N1); } } } if (pgm->fd.ifd != -1) { serial_close(&pgm->fd); } pgm->fd.ifd = -1; } static int jtagmkI_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes) { int block_size, send_size, tries; unsigned int maxaddr = addr + n_bytes; unsigned char cmd[6], *datacmd; unsigned char resp[2]; int is_flash = 0; long otimeout = serial_recv_timeout; #define MAXTRIES 3 pmsg_notice2("jtagmkI_paged_write(.., %s, %d, %d)\n", m->desc, page_size, n_bytes); if (jtagmkI_program_enable(pgm) < 0) return -1; if (page_size == 0) page_size = 256; if (page_size > 256) { pmsg_error("page size %d too large\n", page_size); return -1; } if ((datacmd = malloc(page_size + 1)) == NULL) { pmsg_error("out of memory\n"); return -1; } cmd[0] = CMD_WRITE_MEM; if (strcmp(m->desc, "flash") == 0) { cmd[1] = MTYPE_FLASH_PAGE; PDATA(pgm)->flash_pageaddr = (unsigned long)-1L; page_size = PDATA(pgm)->flash_pagesize; is_flash = 1; } else if (strcmp(m->desc, "eeprom") == 0) { cmd[1] = MTYPE_EEPROM_PAGE; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; page_size = PDATA(pgm)->eeprom_pagesize; } datacmd[0] = CMD_DATA; serial_recv_timeout = 1000; for (; addr < maxaddr; addr += page_size) { tries = 0; again: if (tries != 0 && jtagmkI_resync(pgm, 2000, 0) < 0) { pmsg_error("sync loss, retries exhausted\n"); return -1; } if (n_bytes < page_size) block_size = n_bytes; else block_size = page_size; pmsg_debug("jtagmkI_paged_write(): " "block_size at addr %d is %d\n", addr, block_size); /* We always write full pages. */ send_size = page_size; if (is_flash) { cmd[2] = send_size / 2 - 1; u32_to_b3(cmd + 3, addr / 2); } else { cmd[2] = send_size - 1; u32_to_b3(cmd + 3, addr); } pmsg_notice2("jtagmkI_paged_write(): " "sending write memory command: "); /* First part, send the write command. */ jtagmkI_send(pgm, cmd, 6); if (jtagmkI_recv(pgm, resp, 1) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_warning("timeout/error communicating with programmer (resp %c)\n", resp[0]); if (tries++ < MAXTRIES) goto again; serial_recv_timeout = otimeout; return -1; } else { msg_notice2("OK\n"); } /* * 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(datacmd + 1, 0xff, page_size); memcpy(datacmd + 1, m->buf + addr, block_size); /* Second, send the data command. */ jtagmkI_send(pgm, datacmd, send_size + 1); if (jtagmkI_recv(pgm, resp, 2) < 0) return -1; if (resp[1] != RESP_OK) { msg_notice2("\n"); pmsg_warning("timeout/error communicating with programmer (resp %c)\n", resp[0]); if (tries++ < MAXTRIES) goto again; serial_recv_timeout = otimeout; return -1; } else { msg_notice2("OK\n"); } } free(datacmd); serial_recv_timeout = otimeout; #undef MAXTRIES return n_bytes; } static int jtagmkI_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int n_bytes) { int block_size, read_size, is_flash = 0, tries; unsigned int maxaddr = addr + n_bytes; unsigned char cmd[6], resp[256 * 2 + 3]; long otimeout = serial_recv_timeout; #define MAXTRIES 3 pmsg_notice2("jtagmkI_paged_load(.., %s, %d, %d)\n", m->desc, page_size, n_bytes); if (jtagmkI_program_enable(pgm) < 0) return -1; page_size = m->readsize; cmd[0] = CMD_READ_MEM; if (strcmp(m->desc, "flash") == 0) { cmd[1] = MTYPE_FLASH_PAGE; is_flash = 1; } else if (strcmp(m->desc, "eeprom") == 0) { cmd[1] = MTYPE_EEPROM_PAGE; } if (page_size > (is_flash? 512: 256)) { pmsg_error("page size %d too large\n", page_size); return -1; } serial_recv_timeout = 1000; for (; addr < maxaddr; addr += page_size) { tries = 0; again: if (tries != 0 && jtagmkI_resync(pgm, 2000, 0) < 0) { pmsg_error("sync loss, retries exhausted\n"); return -1; } if (n_bytes < page_size) block_size = n_bytes; else block_size = page_size; pmsg_debug("jtagmkI_paged_load(): " "block_size at addr %d is %d\n", addr, block_size); if (is_flash) { read_size = 2 * ((block_size + 1) / 2); /* round up */ cmd[2] = read_size / 2 - 1; u32_to_b3(cmd + 3, addr / 2); } else { read_size = page_size; cmd[2] = page_size - 1; u32_to_b3(cmd + 3, addr); } pmsg_notice2("jtagmkI_paged_load(): sending read memory command: "); jtagmkI_send(pgm, cmd, 6); if (jtagmkI_recv(pgm, resp, read_size + 3) < 0) return -1; if (resp[read_size + 3 - 1] != RESP_OK) { msg_notice2("\n"); pmsg_warning("timeout/error communicating with programmer (resp %c)\n", resp[read_size + 3 - 1]); if (tries++ < MAXTRIES) goto again; serial_recv_timeout = otimeout; return -1; } else { msg_notice2("OK\n"); } memcpy(m->buf + addr, resp + 1, block_size); } serial_recv_timeout = otimeout; #undef MAXTRIES return n_bytes; } static int jtagmkI_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char * value) { unsigned char cmd[6]; unsigned char resp[256 * 2 + 3], *cache_ptr = NULL; unsigned long paddr = 0UL, *paddr_ptr = NULL; unsigned int pagesize = 0; int respsize = 3 + 1; int is_flash = 0; pmsg_notice2("jtagmkI_read_byte(.., %s, 0x%lx, ...)\n", mem->desc, addr); if (jtagmkI_program_enable(pgm) < 0) return -1; cmd[0] = CMD_READ_MEM; 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; is_flash = 1; } else if (strcmp(mem->desc, "eeprom") == 0) { 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; } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 1; } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 2; } else if (strcmp(mem->desc, "lock") == 0) { cmd[1] = MTYPE_LOCK_BITS; } else if (strcmp(mem->desc, "calibration") == 0) { cmd[1] = MTYPE_OSCCAL_BYTE; } else if (strcmp(mem->desc, "signature") == 0) { cmd[1] = MTYPE_SIGN_JTAG; } /* * To improve the read speed, we used paged reads for flash and * EEPROM, and cache the results in a page cache. * * Page cache validation is based on "{flash,eeprom}_pageaddr" * (holding the base address of the most recent cache fill * operation). This variable is set to (unsigned long)-1L when the * cache needs to be invalidated. */ if (pagesize && paddr == *paddr_ptr) { *value = cache_ptr[addr & (pagesize - 1)]; return 0; } if (pagesize) { if (is_flash) { cmd[2] = pagesize / 2 - 1; u32_to_b3(cmd + 3, paddr / 2); } else { cmd[2] = pagesize - 1; u32_to_b3(cmd + 3, paddr); } respsize = 3 + pagesize; } else { if (cmd[1] == MTYPE_FUSE_BITS) { /* * The mkI ICE has a bug where it doesn't read efuse correctly * when reading it as a single byte @offset 2, while reading all * fuses at once does work. */ cmd[2] = 3 - 1; u32_to_b3(cmd + 3, 0); respsize = 3 + 3; } else { cmd[2] = 1 - 1; u32_to_b3(cmd + 3, addr); } } jtagmkI_send(pgm, cmd, 6); if (jtagmkI_recv(pgm, resp, respsize) < 0) return -1; if (resp[respsize - 1] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[respsize - 1]); return -1; } else { msg_notice2("OK\n"); } if (pagesize) { *paddr_ptr = paddr; memcpy(cache_ptr, resp + 1, pagesize); *value = cache_ptr[addr & (pagesize - 1)]; } else if (cmd[1] == MTYPE_FUSE_BITS) { /* extract the desired fuse */ *value = resp[1 + addr]; } else *value = resp[1]; return 0; } static int jtagmkI_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, unsigned long addr, unsigned char data) { unsigned char cmd[6], datacmd[1 * 2 + 1]; unsigned char resp[1], writedata; int len, need_progmode = 1, need_dummy_read = 0; pmsg_notice2("jtagmkI_write_byte(.., %s, 0x%lx, ...)\n", mem->desc, addr); writedata = data; cmd[0] = CMD_WRITE_MEM; if (strcmp(mem->desc, "flash") == 0) { cmd[1] = MTYPE_SPM; need_progmode = 0; PDATA(pgm)->flash_pageaddr = (unsigned long)-1L; } else if (strcmp(mem->desc, "eeprom") == 0) { cmd[1] = MTYPE_EEPROM; need_progmode = 0; need_dummy_read = 1; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; } else if (strcmp(mem->desc, "lfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; need_dummy_read = 1; addr = 0; } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; need_dummy_read = 1; addr = 1; } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; need_dummy_read = 1; addr = 2; } else if (strcmp(mem->desc, "lock") == 0) { cmd[1] = MTYPE_LOCK_BITS; need_dummy_read = 1; } else if (strcmp(mem->desc, "calibration") == 0) { cmd[1] = MTYPE_OSCCAL_BYTE; need_dummy_read = 1; } else if (strcmp(mem->desc, "signature") == 0) { cmd[1] = MTYPE_SIGN_JTAG; } if (need_progmode) { if (jtagmkI_program_enable(pgm) < 0) return -1; } else { if (jtagmkI_program_disable(pgm) < 0) return -1; } cmd[2] = 1 - 1; if (cmd[1] == MTYPE_SPM) { /* * Flash is word-addressed, but we cannot handle flash anyway * here, as it needs to be written one page at a time ... */ u32_to_b3(cmd + 3, addr / 2); } else { u32_to_b3(cmd + 3, addr); } /* First part, send the write command. */ jtagmkI_send(pgm, cmd, 6); if (jtagmkI_recv(pgm, resp, 1) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } /* Now, send the data buffer. */ datacmd[0] = CMD_DATA; if (cmd[1] == MTYPE_SPM) { len = 3; if ((addr & 1) != 0) { datacmd[1] = 0; datacmd[2] = writedata; } else { datacmd[1] = writedata; datacmd[2] = 0; } } else { len = 2; datacmd[1] = writedata; } jtagmkI_send(pgm, datacmd, len); if (jtagmkI_recv(pgm, resp, 1) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } if(need_dummy_read) jtagmkI_recv(pgm, resp, 1); 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 jtagmkI_set_sck_period(const PROGRAMMER *pgm, double v) { unsigned char dur; v = 1 / v; /* convert to frequency */ if (v >= 1e6) dur = JTAG_BITRATE_1_MHz; else if (v >= 499e3) dur = JTAG_BITRATE_500_kHz; else if (v >= 249e3) dur = JTAG_BITRATE_250_kHz; else dur = JTAG_BITRATE_125_kHz; return jtagmkI_setparm(pgm, PARM_CLOCK, dur); } /* * Read an emulator parameter. The result is exactly one byte, * multi-byte parameters get two different parameter names for * their components. */ static int jtagmkI_getparm(const PROGRAMMER *pgm, const unsigned char parm, unsigned char * value) { unsigned char buf[2], resp[3]; pmsg_notice2("jtagmkI_getparm()\n"); buf[0] = CMD_GET_PARAM; buf[1] = parm; pmsg_notice2("jtagmkI_getparm(): " "Sending get parameter command (parm 0x%02x): ", parm); jtagmkI_send(pgm, buf, 2); if (jtagmkI_recv(pgm, resp, 3) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else if (resp[2] != RESP_OK) { msg_notice2("\n"); pmsg_error("unknown parameter 0x%02x\n", parm); return -1; } else { msg_notice2("OK, value 0x%02x\n", resp[1]); } *value = resp[1]; return 0; } /* * Write an emulator parameter. */ static int jtagmkI_setparm(const PROGRAMMER *pgm, unsigned char parm, unsigned char value) { unsigned char buf[3], resp[2]; pmsg_notice2("jtagmkI_setparm()\n"); buf[0] = CMD_SET_PARAM; buf[1] = parm; buf[2] = value; pmsg_notice2("jtagmkI_setparm(): " "Sending set parameter command (parm 0x%02x): ", parm); jtagmkI_send(pgm, buf, 3); if (jtagmkI_recv(pgm, resp, 2) < 0) return -1; if (resp[0] != RESP_OK) { msg_notice2("\n"); pmsg_error("timeout/error communicating with programmer (resp %c)\n", resp[0]); return -1; } else { msg_notice2("OK\n"); } return 0; } static void jtagmkI_display(const PROGRAMMER *pgm, const char *p) { unsigned char hw, fw; if (jtagmkI_getparm(pgm, PARM_HW_VERSION, &hw) < 0 || jtagmkI_getparm(pgm, PARM_SW_VERSION, &fw) < 0) return; msg_info("%sICE HW version: 0x%02x\n", p, hw); msg_info("%sICE FW version: 0x%02x\n", p, fw); jtagmkI_print_parms1(pgm, p, stderr); return; } static void jtagmkI_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) { unsigned char vtarget, jtag_clock; const char *clkstr; double clk; if (jtagmkI_getparm(pgm, PARM_OCD_VTARGET, &vtarget) < 0 || jtagmkI_getparm(pgm, PARM_CLOCK, &jtag_clock) < 0) return; switch ((unsigned)jtag_clock) { case JTAG_BITRATE_1_MHz: clkstr = "1 MHz"; clk = 1e6; break; case JTAG_BITRATE_500_kHz: clkstr = "500 kHz"; clk = 500e3; break; case JTAG_BITRATE_250_kHz: clkstr = "250 kHz"; clk = 250e3; break; case JTAG_BITRATE_125_kHz: clkstr = "125 kHz"; clk = 125e3; break; default: clkstr = "???"; clk = 1e6; } fmsg_out(fp, "%sVtarget : %.1f V\n", p, 6.25 * (unsigned)vtarget / 255.0); fmsg_out(fp, "%sJTAG clock : %s (%.1f us)\n", p, clkstr, 1.0e6 / clk); return; } static void jtagmkI_print_parms(const PROGRAMMER *pgm, FILE *fp) { jtagmkI_print_parms1(pgm, "", fp); } const char jtagmkI_desc[] = "Atmel JTAG ICE mkI"; void jtagmkI_initpgm(PROGRAMMER *pgm) { strcpy(pgm->type, "JTAGMKI"); /* * mandatory functions */ pgm->initialize = jtagmkI_initialize; pgm->display = jtagmkI_display; pgm->enable = jtagmkI_enable; pgm->disable = jtagmkI_disable; pgm->program_enable = jtagmkI_program_enable_dummy; pgm->chip_erase = jtagmkI_chip_erase; pgm->open = jtagmkI_open; pgm->close = jtagmkI_close; pgm->read_byte = jtagmkI_read_byte; pgm->write_byte = jtagmkI_write_byte; /* * optional functions */ pgm->paged_write = jtagmkI_paged_write; pgm->paged_load = jtagmkI_paged_load; pgm->print_parms = jtagmkI_print_parms; pgm->set_sck_period = jtagmkI_set_sck_period; pgm->setup = jtagmkI_setup; pgm->teardown = jtagmkI_teardown; pgm->page_size = 256; }