From b62408923b576d0b1eeedb706b16a6bea567d94d Mon Sep 17 00:00:00 2001 From: joerg_wunsch Date: Fri, 13 Apr 2012 15:25:41 +0000 Subject: [PATCH] bug #28744: Can't load bootloader to xmega128a1 (part 2, fix for firmware >= V7.x) * jtagmkII.c: Add firmware-version dependent handling of Xmega parameters. V7.x firmware expects the NVM offsets being specified through the Xmega parameters command, but left out as part of the memory address itself. * jtagmkII_private.h: Add CMND_SET_XMEGA_PARAMS, and struct xmega_device_desc. * config_gram.y: Add mcu_base keyword. * avrpart.h: (Dito.) * lexer.l: (Dito.) * avrdude.conf.in (.xmega): add mcu_base, and data memory segment. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1078 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 13 +++++ NEWS | 1 + avrdude.conf.in | 6 +++ avrpart.h | 1 + config_gram.y | 7 +++ jtagmkII.c | 129 ++++++++++++++++++++++++++++++++++++++++++--- jtagmkII_private.h | 22 ++++++++ lexer.l | 1 + 8 files changed, 174 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 685fbe0e..37fac2da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2012-04-13 Joerg Wunsch + + bug #28744: Can't load bootloader to xmega128a1 (part 2, fix for + firmware >= V7.x) + * jtagmkII.c: Add firmware-version dependent handling of Xmega parameters. + V7.x firmware expects the NVM offsets being specified through the Xmega + parameters command, but left out as part of the memory address itself. + * jtagmkII_private.h: Add CMND_SET_XMEGA_PARAMS, and struct xmega_device_desc. + * config_gram.y: Add mcu_base keyword. + * avrpart.h: (Dito.) + * lexer.l: (Dito.) + * avrdude.conf.in (.xmega): add mcu_base, and data memory segment. + 2012-03-30 Joerg Wunsch bug #28744: Can't load bootloader to xmega128a1 (part 1, fix for diff --git a/NEWS b/NEWS index 053c094b..818a3664 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,7 @@ Current: - bug #34027: avrdude AT90S1200 Problem - bug #30451: Accessing some Xmega memory sections gives not supported error + - bug #28744: Can't load bootloader to xmega128a1 * Keep track of input file contents diff --git a/avrdude.conf.in b/avrdude.conf.in index e43d007b..7a6c99de 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -12286,6 +12286,7 @@ part has_jtag = yes; has_pdi = yes; nvm_base = 0x01c0; + mcu_base = 0x0090; memory "prodsig" size = 0x200; @@ -12335,6 +12336,11 @@ part size = 1; offset = 0x8f0027; ; + + memory "data" + # SRAM, only used to supply the offset + offset = 0x1000000; + ; ; diff --git a/avrpart.h b/avrpart.h index 90a6f267..d097aac2 100644 --- a/avrpart.h +++ b/avrpart.h @@ -156,6 +156,7 @@ typedef struct avrpart { 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 */ + unsigned int mcu_base; /* Base address of MCU control block in ATxmega devices */ unsigned int nvm_base; /* Base address of NVM controller in ATxmega devices */ OPCODE * op[AVR_OP_MAX]; /* opcodes */ diff --git a/config_gram.y b/config_gram.y index 1c1c79bb..d4fa3511 100644 --- a/config_gram.y +++ b/config_gram.y @@ -93,6 +93,7 @@ static int pin_name; %token K_IO %token K_LOADPAGE %token K_MAX_WRITE_DELAY +%token K_MCU_BASE %token K_MIN_WRITE_DELAY %token K_MISO %token K_MOSI @@ -1079,6 +1080,12 @@ part_parm : free_token($3); } | + K_MCU_BASE TKN_EQUAL TKN_NUMBER + { + current_part->mcu_base = $3->value.number; + free_token($3); + } | + K_NVM_BASE TKN_EQUAL TKN_NUMBER { current_part->nvm_base = $3->value.number; diff --git a/jtagmkII.c b/jtagmkII.c index 66ff1ca9..b3ee7cd2 100644 --- a/jtagmkII.c +++ b/jtagmkII.c @@ -82,6 +82,9 @@ struct pdata /* Start address of Xmega boot area */ unsigned long boot_start; + + /* Major firmware version (needed for Xmega programming) */ + unsigned int fwver; }; #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) @@ -143,6 +146,7 @@ static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int page_size, unsigned int addr, unsigned int n_bytes); static unsigned char jtagmkII_memtype(PROGRAMMER * pgm, AVRPART * p, unsigned long addr); +static unsigned int jtagmkII_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr); // AVR32 #define ERROR_SAB 0xFFFFFFFF @@ -724,6 +728,7 @@ int jtagmkII_getsync(PROGRAMMER * pgm, int mode) { if (status > 0) { if ((c = resp[0]) == RSP_SIGN_ON) { fwver = ((unsigned)resp[8] << 8) | (unsigned)resp[7]; + PDATA(pgm)->fwver = fwver; hwver = (unsigned)resp[9]; memcpy(PDATA(pgm)->serno, resp + 10, 6); if (verbose >= 1 && status > 17) { @@ -1035,6 +1040,83 @@ static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p) } } +static void jtagmkII_set_xmega_params(PROGRAMMER * pgm, AVRPART * p) +{ + int status; + unsigned char *resp, c; + LNODEID ln; + AVRMEM * m; + struct { + unsigned char cmd; + struct xmega_device_desc dd; + } sendbuf; + + memset(&sendbuf, 0, sizeof sendbuf); + sendbuf.cmd = CMND_SET_XMEGA_PARAMS; + u16_to_b2(sendbuf.dd.whatever, 0x0002); + sendbuf.dd.datalen = 47; + u16_to_b2(sendbuf.dd.nvm_base_addr, p->nvm_base); + u16_to_b2(sendbuf.dd.mcu_base_addr, p->mcu_base); + + 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.flash_page_size, m->page_size * 2); + } else if (strcmp(m->desc, "eeprom") == 0) { + sendbuf.dd.eeprom_page_size = m->page_size; + u16_to_b2(sendbuf.dd.eeprom_size, m->size); + u32_to_b4(sendbuf.dd.nvm_eeprom_offset, m->offset); + } else if (strcmp(m->desc, "application") == 0) { + u32_to_b4(sendbuf.dd.app_size, m->size); + u32_to_b4(sendbuf.dd.nvm_app_offset, m->offset); + } else if (strcmp(m->desc, "boot") == 0) { + u16_to_b2(sendbuf.dd.boot_size, m->size); + u32_to_b4(sendbuf.dd.nvm_boot_offset, m->offset); + } else if (strcmp(m->desc, "fuse0") == 0) { + u32_to_b4(sendbuf.dd.nvm_fuse_offset, m->offset); + } else if (strcmp(m->desc, "lock") == 0) { + u32_to_b4(sendbuf.dd.nvm_lock_offset, m->offset); + } else if (strcmp(m->desc, "usersig") == 0) { + u32_to_b4(sendbuf.dd.nvm_user_sig_offset, m->offset); + } else if (strcmp(m->desc, "prodsig") == 0) { + u32_to_b4(sendbuf.dd.nvm_prod_sig_offset, m->offset); + } else if (strcmp(m->desc, "data") == 0) { + u32_to_b4(sendbuf.dd.nvm_data_offset, m->offset); + } + } + + if (verbose >= 2) + fprintf(stderr, "%s: jtagmkII_set_xmega_params(): " + "Sending set Xmega params command: ", + progname); + jtagmkII_send(pgm, (unsigned char *)&sendbuf, sizeof sendbuf); + + status = jtagmkII_recv(pgm, &resp); + if (status <= 0) { + if (verbose >= 2) + putc('\n', stderr); + fprintf(stderr, + "%s: jtagmkII_set_xmega_params(): " + "timeout/error communicating with programmer (status %d)\n", + progname, status); + return; + } + if (verbose >= 3) { + putc('\n', stderr); + jtagmkII_prmsg(pgm, resp, status); + } else if (verbose == 2) + fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status); + c = resp[0]; + free(resp); + if (c != RSP_OK) { + fprintf(stderr, + "%s: jtagmkII_set_xmega_params(): " + "bad response to set device descriptor command: %s\n", + progname, jtagmkII_get_rc(c)); + } +} + /* * Reset the target. */ @@ -1287,7 +1369,10 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p) /* * Must set the device descriptor before entering programming mode. */ - jtagmkII_set_devdescr(pgm, p); + if (PDATA(pgm)->fwver >= 0x700 && (p->flags & AVRPART_HAS_PDI) != 0) + jtagmkII_set_xmega_params(pgm, p); + else + jtagmkII_set_devdescr(pgm, p); PDATA(pgm)->boot_start = ULONG_MAX; /* @@ -1850,7 +1935,7 @@ static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, cmd[1] = jtagmkII_memtype(pgm, p, addr); u32_to_b4(cmd + 2, page_size); - u32_to_b4(cmd + 6, addr+m->offset ); + u32_to_b4(cmd + 6, jtagmkII_memaddr(pgm, p, m, addr)); /* * The JTAG ICE will refuse to write anything but a full page, at @@ -1924,7 +2009,7 @@ static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int maxaddr = addr + n_bytes; unsigned char cmd[10]; unsigned char *resp; - int status, tries; + int status, tries, dynamic_memtype = 0; long otimeout = serial_recv_timeout; if (verbose >= 2) @@ -1937,8 +2022,12 @@ static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, page_size = m->readsize; cmd[0] = CMND_READ_MEMORY; - cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE; - if (strcmp(m->desc, "eeprom") == 0) { + cmd[1] = jtagmkII_memtype(pgm, p, addr); + if (strcmp(m->desc, "flash") == 0) { + if (p->flags & AVRPART_HAS_PDI) + /* dynamically decide between flash/boot memtype */ + dynamic_memtype = 1; + } else if (strcmp(m->desc, "eeprom") == 0) { cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE; if (pgm->flag & PGM_FL_IS_DW) return -1; @@ -1958,8 +2047,11 @@ static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, "block_size at addr %d is %d\n", progname, addr, block_size); + if (dynamic_memtype) + cmd[1] = jtagmkII_memtype(pgm, p, addr); + u32_to_b4(cmd + 2, block_size); - u32_to_b4(cmd + 6, addr+m->offset ); + u32_to_b4(cmd + 6, jtagmkII_memaddr(pgm, p, m, addr)); tries = 0; @@ -2544,6 +2636,31 @@ static unsigned char jtagmkII_memtype(PROGRAMMER * pgm, AVRPART * p, unsigned lo } } +static unsigned int jtagmkII_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr) +{ + /* + * 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. + */ + return addr + m->offset; +} + #ifdef __OBJC__ #pragma mark - diff --git a/jtagmkII_private.h b/jtagmkII_private.h index cb442c91..4e3272d6 100644 --- a/jtagmkII_private.h +++ b/jtagmkII_private.h @@ -111,6 +111,7 @@ #define CMND_WRITE_MEMORY32 0x2D #define CMND_ISP_PACKET 0x2F #define CMND_XMEGA_ERASE 0x34 +#define CMND_SET_XMEGA_PARAMS 0x36 // undocumented in AVR067 /* ICE responses */ @@ -355,6 +356,27 @@ struct device_descriptor /* new as of early 2005, firmware 4.x */ unsigned char EECRAddress[2]; /* EECR memory-mapped IO address */ }; + +/* New Xmega device descriptor, for firmware version 7 and above */ +struct xmega_device_desc { + unsigned char whatever[2]; // cannot guess; must be 0x0002 + unsigned char datalen; // length of the following data, = 47 + 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 /* JTAGMKII_PRIVATE_EXPORTED */ /* return code from jtagmkII_getsync() to indicate a "graceful" diff --git a/lexer.l b/lexer.l index 7e55026f..255ae941 100644 --- a/lexer.l +++ b/lexer.l @@ -167,6 +167,7 @@ load_ext_addr { yylval=new_token(K_LOAD_EXT_ADDR); return K_LOAD_EXT_ADDR; } loadpage_hi { yylval=new_token(K_LOADPAGE_HI); return K_LOADPAGE_HI; } loadpage_lo { yylval=new_token(K_LOADPAGE_LO); return K_LOADPAGE_LO; } max_write_delay { yylval=NULL; return K_MAX_WRITE_DELAY; } +mcu_base { yylval=NULL; return K_MCU_BASE; } memory { yylval=NULL; return K_MEMORY; } min_write_delay { yylval=NULL; return K_MIN_WRITE_DELAY; } miso { yylval=NULL; return K_MISO; }