Hello, I have added a new Device for flashing it, please see the following lines ... I have tested it on WindowsXP it runs well so far ;-), with MINGW openocd will NOT build silently ( missing symbols at the final link), after running make You have to do additionally:
cd src gcc -std=gnu99 -g -O2 -D__USE_MINGW_ANSI_STDIO -Wall -Wstrict-prototypes -Wformat-security -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -o openocd.exe main.o ./flash/nor/.libs/libocdflashnor.a ./.libs/libopenocd.a -lws2_32 -lftd2xx ./flash/nor/.libs/libocdflashnor.a ./helper/.libs/libhelper.a cd .. make install Best regards, Enrico >From e3d55eaffb2c56677072fb8c8f880397181fd641 Mon Sep 17 00:00:00 2001 From: Enrico <[email protected]> Date: Mon, 1 Mar 2010 09:00:14 +0100 Subject: [PATCH] Device ADUC706x added with this patch You may Flash the ADUC706x- Devices too ... --- src/flash/nor/Makefile.am | 1 + src/flash/nor/aduc706x.c | 452 +++++++++++++++++++++++++++++++++++++++++++++ src/flash/nor/drivers.c | 6 +- tcl/target/aduc706x.cfg | 47 +++++ 4 files changed, 504 insertions(+), 2 deletions(-) create mode 100644 src/flash/nor/aduc706x.c create mode 100644 tcl/target/aduc706x.cfg diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 5d0a4df..f11d466 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -11,6 +11,7 @@ libocdflashnor_la_SOURCES = \ NOR_DRIVERS = \ aduc702x.c \ + aduc706x.c \ at91sam3.c \ at91sam7.c \ avrf.c \ diff --git a/src/flash/nor/aduc706x.c b/src/flash/nor/aduc706x.c new file mode 100644 index 0000000..4d7c683 --- /dev/null +++ b/src/flash/nor/aduc706x.c @@ -0,0 +1,452 @@ +/*************************************************************************** + * Copyright (C) 2008 by Kevin McGuire * + * Copyright (C) 2008 by Marcel Wijlaars * + * Copyright (C) 2009 by Michael Ashton * + * Copyright (C) 2009 by Enrico Guenther, OKM GmbH, * + * ( Taken from aduc702x.c, changed some MMR's, FlashAlgo ) * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <helper/time_support.h> +#include <target/algorithm.h> +#include <target/arm.h> + + +static int aduc706x_build_sector_list(struct flash_bank *bank); +static int aduc706x_check_flash_completion(struct target* target, unsigned int timeout_ms); +static int aduc706x_set_write_enable(struct target *target, int enable); + +#define ADUC706x_FLASH 0xFFFF0E00 +#define ADUC706x_FLASH_FEESTA (0*4) +#define ADUC706x_FLASH_FEEMOD (1*4) +#define ADUC706x_FLASH_FEECON (2*4) +#define ADUC706x_FLASH_FEEDAT (3*4) +#define ADUC706x_FLASH_FEEADR (4*4) +#define ADUC706x_FLASH_UNUSED (5*4) +#define ADUC706x_FLASH_FEESIGN (6*4) +#define ADUC706x_FLASH_FEEPRO (7*4) +#define ADUC706x_FLASH_FEEHIDE (8*4) + +typedef struct { + uint32_t feesta; + uint32_t feemod; + uint32_t feecon; + uint32_t feedat; + uint32_t feeadr; + uint32_t feesign; + uint32_t feepro; + uint32_t feehide; +} ADUC706x_FLASH_MMIO; + + + +struct aduc706x_flash_bank { + struct working_area *write_algorithm; +}; + +/* flash bank aduc706x 0 0 0 0 <target#>*/ +FLASH_BANK_COMMAND_HANDLER(aduc706x_flash_bank_command) +{ + struct aduc706x_flash_bank *nbank; + + nbank = malloc(sizeof(struct aduc706x_flash_bank)); + + bank->base = 0x80000; + bank->size = 0x7800; // 30k, 2k on top not accessible + bank->driver_priv = nbank; + + aduc706x_build_sector_list(bank); + + return ERROR_OK; +} + +static int aduc706x_build_sector_list(struct flash_bank *bank) +{ + //aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv; + + int i = 0; + uint32_t offset = 0; + + // sector size is 512 + bank->num_sectors = bank->size / 512; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + for (i = 0; i < bank->num_sectors; ++i) + { + bank->sectors[i].offset = offset; + bank->sectors[i].size = 512; + offset += bank->sectors[i].size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + return ERROR_OK; +} + +static int aduc706x_protect_check(struct flash_bank *bank) +{ + printf("aduc706x_protect_check not implemented yet.\n"); + return ERROR_OK; +} + +static int aduc706x_erase(struct flash_bank *bank, int first, int last) +{ + //int res; + int x; + int count; + //uint32_t v; + struct target *target = bank->target; + + aduc706x_set_write_enable(target, 1); + + /* mass erase */ + if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) { + LOG_DEBUG("performing mass erase.\n"); + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEDAT, 0x3cff); + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEADR, 0x77c3); + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEMOD, 0x8); /* enable erase/write commands */ + target_write_u8(target, ADUC706x_FLASH + ADUC706x_FLASH_FEECON, 0x06); + + if (aduc706x_check_flash_completion(target, 3500) != ERROR_OK) + { + LOG_ERROR("ADUC706x: mass erase failed\n"); + aduc706x_set_write_enable(target, 0); + return ERROR_FLASH_OPERATION_FAILED; + } + + LOG_DEBUG("mass erase successful.\n"); + return ERROR_OK; + } else { + unsigned long adr; + + count = last - first + 1; + for (x = 0; x < count; ++x) + { + adr = bank->base + ((first + x) * 512); + + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEADR, adr); + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEMOD, 0x8); /* enable erase/write commands */ + target_write_u8(target, ADUC706x_FLASH + ADUC706x_FLASH_FEECON, 0x05); + + if (aduc706x_check_flash_completion(target, 50) != ERROR_OK) + { + LOG_ERROR("ADUC706x: failed to erase sector at address 0x%08lX\n", adr); + aduc706x_set_write_enable(target, 0); + return ERROR_FLASH_SECTOR_NOT_ERASED; + } + + LOG_DEBUG("erased sector at address 0x%08lX\n", adr); + } + } + + aduc706x_set_write_enable(target, 0); + + return ERROR_OK; +} + +static int aduc706x_protect(struct flash_bank *bank, int set, int first, int last) +{ + printf("aduc706x_protect not implemented yet.\n"); + return ERROR_FLASH_OPERATION_FAILED; +} + +/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall + * back to another mechanism that does not require onboard RAM + * + * Caller should not check for other return values specifically + */ +static int aduc706x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct aduc706x_flash_bank *aduc706x_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t buffer_size = 2048; + struct working_area *source; + uint32_t address = bank->base + offset; + struct reg_param reg_params[6]; + struct arm_algorithm armv4_5_info; + int retval = ERROR_OK; + + if (((count%2)!=0)||((offset%2)!=0)) + { + LOG_ERROR("ADUC706x: write block must be multiple of two bytes in offset & length"); + return ERROR_FAIL; + } + + /* parameters: + + r0 - address of source data (absolute) + r1 - number of halfwords to be copied + r2 - start address in flash (offset from beginning of flash memory) + r3 - exit code + r4 - base address of flash controller (0x0xFFFF0E00) + + registers: + + r5 - scratch + r6 - set to 2, used to write flash command + + */ + uint32_t aduc706x_flash_write_code[] = { + //start: + 0xE3A05008,// mov r5, #8 + 0xE5845004,// str r5, [r4, #4] + 0xE3A06002,// mov r6, #2 + //next: + 0xE1C421B0,// strh r2, [r4, #16] + 0xE0D050B2,// ldrh r5, [r0], #2 + 0xE1C450BC,// strh r5, [r4, #12] + 0xE5C46008,// strb r6, [r4, #8] + //wait_complete: + 0xE1D430B0,// ldrh r3, [r4] + 0xE3130004,// tst r3, #4 + 0x1AFFFFFC,// bne wait_complete + 0xE3130003,// tst r3,#3 ; I've observed, that sometimes both bits are 0, this should not be the case + // ; but if, I wait until at least one bit is set + 0x1A000002,// bne ok + //loop: + 0xE1D430B0,// ldrh r3, [r4] + 0xE3130003,// tst r3,#3 + 0x0AFFFFFC,// beq loop + //ok: + 0xE2822002,// add r2, r2, #2 + 0xE2511001,// subs r1, r1, #1 + 0x0A000001,// beq done + 0xE3130001,// tst r3, #1 + 0x1AFFFFEE,// bne next + //done: + 0xEAFFFFFE // b done + }; + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(aduc706x_flash_write_code), + &aduc706x_info->write_algorithm) != ERROR_OK) + { + LOG_WARNING("ADUC706x: no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + retval=target_write_buffer(target, aduc706x_info->write_algorithm->address, + sizeof(aduc706x_flash_write_code), (uint8_t*)aduc706x_flash_write_code); + if (retval!=ERROR_OK) + { + return retval; + } + + /* memory buffer */ + while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) + { + buffer_size /= 2; + if (buffer_size <= 256) + { + /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */ + if (aduc706x_info->write_algorithm) + target_free_working_area(target, aduc706x_info->write_algorithm); + + LOG_WARNING("ADUC706x: no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + armv4_5_info.common_magic = ARM_COMMON_MAGIC; + armv4_5_info.core_mode = ARM_MODE_SVC; + armv4_5_info.core_state = ARM_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_IN); + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); + + while (count > 0) + { + uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; + + retval=target_write_buffer(target, source->address, thisrun_count, buffer); + if (retval!=ERROR_OK) + { + break; + } + + buf_set_u32(reg_params[0].value, 0, 32, source->address); + buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2); + buf_set_u32(reg_params[2].value, 0, 32, address); + buf_set_u32(reg_params[4].value, 0, 32, 0xFFFF0E00); + + if ((retval = target_run_algorithm(target, 0, NULL, 5, + reg_params, aduc706x_info->write_algorithm->address, + aduc706x_info->write_algorithm->address + sizeof(aduc706x_flash_write_code) - 4, + 10000, &armv4_5_info)) != ERROR_OK) + { + LOG_ERROR("ADUC706x: error executing flash write algorithm"); + break; + } + { + unsigned long x; + + if (((x=buf_get_u32(reg_params[3].value, 0, 32)) & 1) != 1) + { + LOG_ERROR("ADUC706x: detected error writing flash, FlashAlgo exit code is 0x%lX",x); + retval = ERROR_FAIL; + break; + } + } + buffer += thisrun_count; + address += thisrun_count; + count -= thisrun_count; + } + + target_free_working_area(target, source); + target_free_working_area(target, aduc706x_info->write_algorithm); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + + return retval; +} + +/* All-JTAG, single-access method. Very slow. Used only if there is no + * working area available. */ +static int aduc706x_write_single(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) +{ + uint32_t x; + uint8_t b; + struct target *target = bank->target; + + aduc706x_set_write_enable(target, 1); + + for (x = 0; x < count; x += 2) { + // FEEADR = address + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEADR, offset + x); + + // set up data + if ((x + 1) == count) + { + // last byte + target_read_u8(target, offset + x + 1, &b); + } + else + b = buffer[x + 1]; + + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEDAT, buffer[x] | (b << 8)); + + // do single-write command + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEMOD, 0x8); /* enable erase/write commands */ + target_write_u8(target, ADUC706x_FLASH + ADUC706x_FLASH_FEECON, 0x02); + + if (aduc706x_check_flash_completion(target, 1) != ERROR_OK) + { + LOG_ERROR("ADUC706x: single write failed for address 0x%08lX\n", (unsigned long)(offset + x)); + aduc706x_set_write_enable(target, 0); + return ERROR_FLASH_OPERATION_FAILED; + } + + } + LOG_DEBUG("wrote %d bytes at address 0x%08lX\n", (int)count, (unsigned long)(offset + x)); + + aduc706x_set_write_enable(target, 0); + + return ERROR_OK; +} + +int aduc706x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) +{ + int retval; + + /* try using a block write */ + if ((retval = aduc706x_write_block(bank, buffer, offset, count)) != ERROR_OK) + { + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + /* if block write failed (no sufficient working area), + * use normal (slow) JTAG method */ + LOG_WARNING("ADUC706x: couldn't use block writes, falling back to single memory accesses"); + + if ((retval = aduc706x_write_single(bank, buffer, offset, count)) != ERROR_OK) + { + LOG_ERROR("ADUC706x: slow write failed"); + return ERROR_FLASH_OPERATION_FAILED; + } + } + } + + return retval; +} + +static int aduc706x_probe(struct flash_bank *bank) +{ + return ERROR_OK; +} + +static int aduc706x_info(struct flash_bank *bank, char *buf, int buf_size) +{ + snprintf(buf, buf_size, "aduc706x flash driver info"); + return ERROR_OK; +} + +/* sets FEEMOD bit 3 + * enable = 1 enables writes & erases, 0 disables them */ +static int aduc706x_set_write_enable(struct target *target, int enable) +{ + // don't bother to preserve int enable bit here + target_write_u16(target, ADUC706x_FLASH + ADUC706x_FLASH_FEEMOD, enable ? 8 : 0); + + return ERROR_OK; +} + +/* wait up to timeout_ms for controller to not be busy, + * then check whether the command passed or failed. + * + * this function sleeps 1ms between checks (after the first one), + * so in some cases may slow things down without a usleep after the first read */ +static int aduc706x_check_flash_completion(struct target* target, unsigned int timeout_ms) +{ + uint8_t v = 4; + + long long endtime = timeval_ms() + timeout_ms; + while (1) { + target_read_u8(target, ADUC706x_FLASH + ADUC706x_FLASH_FEESTA, &v); + if ((v & 4) == 0) break; + alive_sleep(1); + if (timeval_ms() >= endtime) break; + } + + if (v & 2) return ERROR_FAIL; + // if a command is ignored, both the success and fail bits may be 0 + else if ((v & 3) == 0) return ERROR_FAIL; + else return ERROR_OK; +} + +struct flash_driver aduc706x_flash = { + .name = "aduc706x", + .flash_bank_command = aduc706x_flash_bank_command, + .erase = aduc706x_erase, + .protect = aduc706x_protect, + .write = aduc706x_write, + .probe = aduc706x_probe, + .auto_probe = aduc706x_probe, + .erase_check = default_flash_blank_check, + .protect_check = aduc706x_protect_check, + .info = aduc706x_info +}; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 7f71d83..ab795d6 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -29,7 +29,8 @@ extern struct flash_driver at91sam3_flash; extern struct flash_driver at91sam7_flash; extern struct flash_driver str7x_flash; extern struct flash_driver str9x_flash; -extern struct flash_driver aduc702x_flash; +extern struct flash_driver aduc702x_flash; +extern struct flash_driver aduc706x_flash; extern struct flash_driver stellaris_flash; extern struct flash_driver str9xpec_flash; extern struct flash_driver stm32x_flash; @@ -53,7 +54,8 @@ struct flash_driver *flash_drivers[] = { &at91sam3_flash, &str7x_flash, &str9x_flash, - &aduc702x_flash, + &aduc702x_flash, + &aduc706x_flash, &stellaris_flash, &str9xpec_flash, &stm32x_flash, diff --git a/tcl/target/aduc706x.cfg b/tcl/target/aduc706x.cfg new file mode 100644 index 0000000..b9aa784 --- /dev/null +++ b/tcl/target/aduc706x.cfg @@ -0,0 +1,47 @@ +## -*- tcl -*- +## + + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME aduc706x +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + # This config file was defaulting to big endian.. + set _ENDIAN little +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x3f0f0f0f +} + + +jtag_nsrst_delay 200 +jtag_ntrst_delay 200 + +# This is for the case that TRST/SRST is not wired on your JTAG adaptor. +# Don't really need them anyways. +reset_config none + +## JTAG scan chain +#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +## +## Target configuration +## +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME + +# allocate some SRAM as working area +$_TARGETNAME configure -work-area-phys 0x40000 -work-area-size 0x800 + +## flash configuration +# only target number is needed +flash bank ADUC7061 aduc706x 0 0 0 0 ADUC7061.cpu -- 1.6.5.1.1367.gcd48 _______________________________________________ Openocd-development mailing list [email protected] https://lists.berlios.de/mailman/listinfo/openocd-development
