diff --git a/avrdude.conf.in b/avrdude.conf.in index 824cc675..0ea49cf2 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -67,6 +67,8 @@ # idr = ; # IO addr of IDR (OCD) reg. # rampz = ; # IO addr of RAMPZ reg. # spmcr = ; # mem addr of SPMC[S]R reg. +# eecr = ; # mem addr of EECR reg. +# # (only when != 0x3c) # # memory # paged = ; # yes / no @@ -2051,6 +2053,7 @@ part idr = 0x31; spmcr = 0x57; rampz = 0x3b; + eecr = 0x3f; memory "eeprom" paged = no; /* leave this "no" */ diff --git a/avrpart.c b/avrpart.c index 78e112ce..612da347 100644 --- a/avrpart.c +++ b/avrpart.c @@ -366,7 +366,7 @@ AVRPART * avr_new_part(void) p->desc[0] = 0; p->reset_disposition = RESET_DEDICATED; p->retry_pulse = PIN_AVR_SCK; - p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK; + p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING; p->config_file[0] = 0; p->lineno = 0; diff --git a/avrpart.h b/avrpart.h index 138a6ebb..8cd644c3 100644 --- a/avrpart.h +++ b/avrpart.h @@ -111,6 +111,7 @@ typedef struct avrpart { unsigned char idr; /* JTAG ICE mkII XML file parameter */ unsigned char rampz; /* JTAG ICE mkII XML file parameter */ unsigned char spmcr; /* JTAG ICE mkII XML file parameter */ + unsigned short eecr; /* JTAC ICE mkII XML file parameter */ OPCODE * op[AVR_OP_MAX]; /* opcodes */ diff --git a/config_gram.y b/config_gram.y index f7fe7713..88c65148 100644 --- a/config_gram.y +++ b/config_gram.y @@ -154,6 +154,7 @@ static int parse_cmdbits(OPCODE * op); %token K_IDR /* address of OCD register in IO space */ %token K_RAMPZ /* address of RAMPZ reg. in IO space */ %token K_SPMCR /* address of SPMC[S]R in memory space */ +%token K_EECR /* address of EECR in memory space */ %token TKN_COMMA %token TKN_EQUAL @@ -637,6 +638,12 @@ part_parm : free_token($3); } | + K_EECR TKN_EQUAL TKN_NUMBER + { + current_part->eecr = $3->value.number; + free_token($3); + } | + K_SERIAL TKN_EQUAL yesno { if ($3->primary == K_YES) diff --git a/jtagmkII.c b/jtagmkII.c index d3f8d357..79386234 100644 --- a/jtagmkII.c +++ b/jtagmkII.c @@ -71,20 +71,17 @@ static int prog_enabled; /* Cached value of PROGRAMMING status. */ static unsigned char serno[6]; /* JTAG ICE serial number. */ /* * The OCDEN fuse is bit 7 of the high fuse (hfuse). In order to - * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, we need to - * enable on-chip debugging, as these memory types are apparently - * emulated by running MCU instructions on the target MCU. We cache - * the original value here, so it can be restored before exiting. - * User-requested hfuse updates will always mask out the OCDEN fuse - * then, only updating the cached copy. + * 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) -static unsigned char hfuse_backup; -static int internal_hfuse_handling; + +/* The length of the device descriptor is firmware-dependent. */ +static size_t device_descriptor_length; static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned long addr, unsigned char * value); @@ -537,6 +534,7 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) { #define MAXTRIES 33 unsigned char buf[3], *resp, c = 0xff; int status; + unsigned int fwver; if (verbose >= 3) fprintf(stderr, "%s: jtagmkII_getsync()\n", progname); @@ -563,6 +561,8 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) { if (status > 0) { if ((c = resp[0]) == RSP_SIGN_ON) { + fwver = ((unsigned)resp[8] << 8) | (unsigned)resp[7]; + memcpy(serno, resp + 10, 6); if (verbose >= 1 && status > 17) { fprintf(stderr, "JTAG ICE mkII sign-on message:\n"); fprintf(stderr, "Communications protocol version: %u\n", @@ -581,7 +581,6 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) { (unsigned)resp[8], (unsigned)resp[7]); fprintf(stderr, " hardware version: %u\n", (unsigned)resp[9]); - memcpy(serno, resp + 10, 6); fprintf(stderr, "Serial number: " "%02x:%02x:%02x:%02x:%02x:%02x\n", serno[0], serno[1], serno[2], serno[3], serno[4], serno[5]); @@ -608,6 +607,28 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) { return -1; } + device_descriptor_length = sizeof(struct device_descriptor); + /* + * There's no official documentation from Atmel about what firmware + * revision matches what device descriptor length. The algorithm + * below has been found empirically. + */ +#define FWVER(maj, min) ((maj << 8) | (min)) + if (fwver < FWVER(3, 16)) { + device_descriptor_length -= 2; + fprintf(stderr, + "%s: jtagmkII_getsync(): " + "S_MCU firmware version might be too old to work correctly\n", + progname); + } else if (fwver < FWVER(4, 0)) { + device_descriptor_length -= 2; + } +#undef FWVER + if (verbose >= 2) + fprintf(stderr, + "%s: jtagmkII_getsync(): Using a %u-byte device descriptor\n", + progname, device_descriptor_length); + /* Turn the ICE into JTAG mode */ buf[0] = EMULATOR_MODE_JTAG; if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0) @@ -718,6 +739,7 @@ static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p) sendbuf.dd.ucSPMCRAddress = p->spmcr; sendbuf.dd.ucRAMPZAddress = p->rampz; sendbuf.dd.ucIDRAddress = p->idr; + u16_to_b2(sendbuf.dd.EECRAddress, p->eecr); sendbuf.dd.ucAllowFullPageBitstream = (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0; sendbuf.dd.EnablePageProgramming = @@ -738,7 +760,8 @@ static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p) fprintf(stderr, "%s: jtagmkII_set_devdescr(): " "Sending set device descriptor command: ", progname); - jtagmkII_send(pgm, (unsigned char *)&sendbuf, sizeof sendbuf); + jtagmkII_send(pgm, (unsigned char *)&sendbuf, + device_descriptor_length + sizeof(unsigned char)); status = jtagmkII_recv(pgm, &resp); if (status <= 0) { @@ -986,19 +1009,14 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p) if (jtagmkII_reset(pgm) < 0) return -1; - internal_hfuse_handling = 1; strcpy(hfuse.desc, "hfuse"); - if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &hfuse_backup) < 0) { - internal_hfuse_handling = 0; + if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &b) < 0) return -1; - } - b = hfuse_backup; - b &= ~OCDEN; - if (jtagmkII_write_byte(pgm, p, &hfuse, 1, b) < 0) { - internal_hfuse_handling = 0; - return -1; - } - internal_hfuse_handling = 0; + if ((b & OCDEN) != 0) + fprintf(stderr, + "%s: jtagmkII_initialize(): warning: OCDEN fuse not programmed, " + "single-byte EEPROM updates not possible\n", + progname); return 0; } @@ -1050,46 +1068,10 @@ static void jtagmkII_close(PROGRAMMER * pgm) { int status; unsigned char buf[1], *resp, c; - AVRMEM hfuse; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_close()\n", progname); - internal_hfuse_handling = 1; - strcpy(hfuse.desc, "hfuse"); - (void)jtagmkII_write_byte(pgm, NULL, &hfuse, 1, hfuse_backup); - internal_hfuse_handling = 0; - - buf[0] = CMND_RESET; - if (verbose >= 2) - fprintf(stderr, "%s: jtagmkII_close(): Sending restore target command: ", - progname); - jtagmkII_send(pgm, buf, 1); - - status = jtagmkII_recv(pgm, &resp); - if (status <= 0) { - if (verbose >= 2) - putc('\n', stderr); - fprintf(stderr, - "%s: jtagmkII_close(): " - "timeout/error communicating with programmer (status %d)\n", - progname, status); - } else { - if (verbose >= 3) { - putc('\n', stderr); - jtagmkII_prmsg(pgm, resp, status); - } else if (verbose == 2) - fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); - c = resp[0]; - free(resp); - if (c != RSP_OK) { - fprintf(stderr, - "%s: jtagmkII_close(): " - "bad response to restore target command: 0x%02x\n", - progname, c); - } - } - buf[0] = CMND_GO; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_close(): Sending GO command: ", @@ -1397,10 +1379,6 @@ static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 1; - if (!internal_hfuse_handling) { - *value = hfuse_backup; - return 0; - } } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 2; @@ -1497,7 +1475,7 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, { unsigned char cmd[11]; unsigned char *resp = NULL, writedata; - int status, tries, need_progmode = 1, is_hfuse = 0; + int status, tries, need_progmode = 1; if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_write_byte(.., %s, 0x%lx, ...)\n", @@ -1519,10 +1497,6 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, } else if (strcmp(mem->desc, "hfuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 1; - if (!internal_hfuse_handling) { - is_hfuse = 1; - writedata &= ~OCDEN; - } } else if (strcmp(mem->desc, "efuse") == 0) { cmd[1] = MTYPE_FUSE_BITS; addr = 2; @@ -1583,8 +1557,6 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, goto fail; } - if (is_hfuse && !internal_hfuse_handling) - hfuse_backup = data; free(resp); return 0; diff --git a/jtagmkII_private.h b/jtagmkII_private.h index 6558a824..03f80ff9 100644 --- a/jtagmkII_private.h +++ b/jtagmkII_private.h @@ -285,12 +285,6 @@ struct device_descriptor unsigned char ucPCMaskExtended; /* For parts with extended PC */ unsigned char ucPCMaskHigh; /* PC high mask */ unsigned char ucEindAddress; /* Selects reset type. [EIND address...] */ - /* Does not work yet, M_MCU f/w rev 3.11, S_MCU f/w rev 3.16 */ - /* unsigned char EECRAddress[2]; */ /* EECR IO address */ + /* new as of early 2005, firmware 4.x */ + unsigned char EECRAddress[2]; /* EECR memory-mapped IO address */ }; - -#define fill_b4(u) \ -{ ((u) & 0xffUL), (((u) & 0xff00UL) >> 8), \ - (((u) & 0xff0000UL) >> 16), (((u) & 0xff000000UL) >> 24) } -#define fill_b2(u) \ -{ ((u) & 0xff), (((u) & 0xff00) >> 8) } diff --git a/lexer.l b/lexer.l index f240a9bd..a8386fc1 100644 --- a/lexer.l +++ b/lexer.l @@ -130,6 +130,7 @@ default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; } default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; } default_serial { yylval=NULL; return K_DEFAULT_SERIAL; } devicecode { yylval=NULL; return K_DEVICECODE; } +eecr { yylval=NULL; return K_EECR; } eeprom { yylval=NULL; return K_EEPROM; } enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; } errled { yylval=NULL; return K_ERRLED; }