]> git.sur5r.net Git - openocd/commitdiff
move nor drivers to src/flash/nor
authorZachary T Welch <zw@superlucidity.net>
Wed, 2 Dec 2009 23:54:15 +0000 (15:54 -0800)
committerZachary T Welch <zw@superlucidity.net>
Thu, 3 Dec 2009 07:27:09 +0000 (23:27 -0800)
Moves NOR flash drivers to 'src/flash/nor/'.
Adds 'src/flash/nor/Makefile.am'.
Builds 'libocdflashnor.la'.

71 files changed:
configure.in
src/flash/Makefile.am
src/flash/aduc702x.c [deleted file]
src/flash/at91sam3.c [deleted file]
src/flash/at91sam3.h [deleted file]
src/flash/at91sam7.c [deleted file]
src/flash/at91sam7.h [deleted file]
src/flash/avrf.c [deleted file]
src/flash/avrf.h [deleted file]
src/flash/cfi.c [deleted file]
src/flash/cfi.h [deleted file]
src/flash/ecos.c [deleted file]
src/flash/faux.c [deleted file]
src/flash/lpc2000.c [deleted file]
src/flash/lpc2000.h [deleted file]
src/flash/lpc288x.c [deleted file]
src/flash/lpc288x.h [deleted file]
src/flash/lpc2900.c [deleted file]
src/flash/non_cfi.c [deleted file]
src/flash/non_cfi.h [deleted file]
src/flash/nor/Makefile.am [new file with mode: 0644]
src/flash/nor/aduc702x.c [new file with mode: 0644]
src/flash/nor/at91sam3.c [new file with mode: 0644]
src/flash/nor/at91sam3.h [new file with mode: 0644]
src/flash/nor/at91sam7.c [new file with mode: 0644]
src/flash/nor/at91sam7.h [new file with mode: 0644]
src/flash/nor/avrf.c [new file with mode: 0644]
src/flash/nor/avrf.h [new file with mode: 0644]
src/flash/nor/cfi.c [new file with mode: 0644]
src/flash/nor/cfi.h [new file with mode: 0644]
src/flash/nor/ecos.c [new file with mode: 0644]
src/flash/nor/faux.c [new file with mode: 0644]
src/flash/nor/lpc2000.c [new file with mode: 0644]
src/flash/nor/lpc2000.h [new file with mode: 0644]
src/flash/nor/lpc288x.c [new file with mode: 0644]
src/flash/nor/lpc288x.h [new file with mode: 0644]
src/flash/nor/lpc2900.c [new file with mode: 0644]
src/flash/nor/non_cfi.c [new file with mode: 0644]
src/flash/nor/non_cfi.h [new file with mode: 0644]
src/flash/nor/ocl.c [new file with mode: 0644]
src/flash/nor/ocl.h [new file with mode: 0644]
src/flash/nor/pic32mx.c [new file with mode: 0644]
src/flash/nor/pic32mx.h [new file with mode: 0644]
src/flash/nor/stellaris.c [new file with mode: 0644]
src/flash/nor/stellaris.h [new file with mode: 0644]
src/flash/nor/stm32x.c [new file with mode: 0644]
src/flash/nor/stm32x.h [new file with mode: 0644]
src/flash/nor/str7x.c [new file with mode: 0644]
src/flash/nor/str7x.h [new file with mode: 0644]
src/flash/nor/str9x.c [new file with mode: 0644]
src/flash/nor/str9x.h [new file with mode: 0644]
src/flash/nor/str9xpec.c [new file with mode: 0644]
src/flash/nor/str9xpec.h [new file with mode: 0644]
src/flash/nor/tms470.c [new file with mode: 0644]
src/flash/nor/tms470.h [new file with mode: 0644]
src/flash/ocl.c [deleted file]
src/flash/ocl.h [deleted file]
src/flash/pic32mx.c [deleted file]
src/flash/pic32mx.h [deleted file]
src/flash/stellaris.c [deleted file]
src/flash/stellaris.h [deleted file]
src/flash/stm32x.c [deleted file]
src/flash/stm32x.h [deleted file]
src/flash/str7x.c [deleted file]
src/flash/str7x.h [deleted file]
src/flash/str9x.c [deleted file]
src/flash/str9x.h [deleted file]
src/flash/str9xpec.c [deleted file]
src/flash/str9xpec.h [deleted file]
src/flash/tms470.c [deleted file]
src/flash/tms470.h [deleted file]

index 3680cac52e4daf173e7d1a0211d0deb8c44c6627..7b2b4af3da099b09bf6735a420014bde3f9991bd 100644 (file)
@@ -1122,6 +1122,7 @@ AC_OUTPUT(dnl
     src/target/Makefile dnl
     src/server/Makefile dnl
     src/flash/Makefile dnl
+    src/flash/nor/Makefile dnl
     src/flash/nand/Makefile dnl
     src/pld/Makefile dnl
     doc/Makefile dnl
index 353fcf1650a0eb88efddad55e39db5fc9161ae8c..54a5116ee8f8991b6a4a4fef6d096a58b8d2a200 100644 (file)
@@ -1,4 +1,5 @@
 SUBDIRS = \
+       nor \
        nand
 
 AM_CPPFLAGS = \
@@ -9,66 +10,24 @@ AM_CPPFLAGS = \
 METASOURCES = AUTO
 noinst_LTLIBRARIES = libflash.la
 libflash_la_SOURCES = \
-       $(FLASH_SRCS) \
-       $(NAND_SRCS) \
-       mflash.c
-
-libflash_la_LIBADD = \
-       $(top_builddir)/src/flash/nand/libocdflashnand.la
-
-FLASH_SRCS = \
        common.c \
-       cfi.c \
-       non_cfi.c \
-       faux.c \
-       $(FLASH_DEVICES_SRCS) \
-       flash.c
-
-FLASH_DEVICES_SRCS = \
-       aduc702x.c \
-       at91sam3.c \
-       at91sam7.c \
-       avrf.c \
-       ecos.c \
-       lpc2000.c \
-       lpc288x.c \
-       lpc2900.c \
-       ocl.c \
-       pic32mx.c \
-       stellaris.c \
-       stm32x.c \
-       str7x.c \
-       str9x.c \
-       str9xpec.c \
-       tms470.c
-
-NAND_SRCS = \
+       flash.c \
        arm_nandio.c \
        nand_ecc.c \
        nand_ecc_kw.c \
-       nand.c
+       nand.c \
+       mflash.c
+
+libflash_la_LIBADD = \
+       $(top_builddir)/src/flash/nor/libocdflashnor.la \
+       $(top_builddir)/src/flash/nand/libocdflashnand.la
 
 noinst_HEADERS = \
        arm_nandio.h \
-       at91sam7.h \
-       at91sam3.h \
-       avrf.h \
-       cfi.h \
        common.h \
        flash.h \
-       lpc2000.h \
-       lpc288x.h \
        mflash.h \
-       non_cfi.h \
-       nand.h \
-       ocl.h \
-       pic32mx.h \
-       stellaris.h \
-       stm32x.h \
-       str7x.h \
-       str9x.h \
-       str9xpec.h \
-       tms470.h
+       nand.h
 
 EXTRA_DIST = startup.tcl
 
diff --git a/src/flash/aduc702x.c b/src/flash/aduc702x.c
deleted file mode 100644 (file)
index 643705c..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2008 by Kevin McGuire                                   *
- *   Copyright (C) 2008 by Marcel Wijlaars                                 *
- *   Copyright (C) 2009 by Michael Ashton                                  *
- *                                                                         *
- *   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 "flash.h"
-#include "armv4_5.h"
-#include "binarybuffer.h"
-#include "time_support.h"
-#include "algorithm.h"
-
-
-static int aduc702x_build_sector_list(struct flash_bank *bank);
-static int aduc702x_check_flash_completion(struct target* target, unsigned int timeout_ms);
-static int aduc702x_set_write_enable(struct target *target, int enable);
-
-#define ADUC702x_FLASH                         0xfffff800
-#define ADUC702x_FLASH_FEESTA          (0*4)
-#define ADUC702x_FLASH_FEEMOD          (1*4)
-#define ADUC702x_FLASH_FEECON          (2*4)
-#define ADUC702x_FLASH_FEEDAT          (3*4)
-#define ADUC702x_FLASH_FEEADR          (4*4)
-#define ADUC702x_FLASH_FEESIGN         (5*4)
-#define ADUC702x_FLASH_FEEPRO          (6*4)
-#define ADUC702x_FLASH_FEEHIDE         (7*4)
-
-struct aduc702x_flash_bank {
-       struct working_area *write_algorithm;
-};
-
-/* flash bank aduc702x 0 0 0 0 <target#>
- * The ADC7019-28 devices all have the same flash layout */
-FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
-{
-       struct aduc702x_flash_bank *nbank;
-
-       nbank = malloc(sizeof(struct aduc702x_flash_bank));
-
-        bank->base = 0x80000;
-        bank->size = 0xF800; // top 4k not accessible
-       bank->driver_priv = nbank;
-
-        aduc702x_build_sector_list(bank);
-
-        return ERROR_OK;
-}
-
-static int aduc702x_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 aduc702x_protect_check(struct flash_bank *bank)
-{
-       printf("aduc702x_protect_check not implemented yet.\n");
-       return ERROR_OK;
-}
-
-static int aduc702x_erase(struct flash_bank *bank, int first, int last)
-{
-        //int res;
-       int x;
-       int count;
-       //uint32_t v;
-       struct target *target = bank->target;
-
-        aduc702x_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, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff);
-               target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
-               target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
-
-                if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK)
-               {
-                       LOG_ERROR("mass erase failed\n");
-                        aduc702x_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, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
-                        target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
-
-                        if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
-                        {
-                                LOG_ERROR("failed to erase sector at address 0x%08lX\n", adr);
-                                aduc702x_set_write_enable(target, 0);
-                                return ERROR_FLASH_SECTOR_NOT_ERASED;
-                        }
-
-                        LOG_DEBUG("erased sector at address 0x%08lX\n", adr);
-                }
-        }
-
-        aduc702x_set_write_enable(target, 0);
-
-       return ERROR_OK;
-}
-
-static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       printf("aduc702x_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 aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t buffer_size = 7000;
-       struct working_area *source;
-       uint32_t address = bank->base + offset;
-       struct reg_param reg_params[6];
-       struct armv4_5_algorithm armv4_5_info;
-       int retval = ERROR_OK;
-
-       if (((count%2)!=0)||((offset%2)!=0))
-       {
-               LOG_ERROR("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 (0xFFFFF800)
-
-        registers:
-
-        r5 - scratch
-        r6 - set to 2, used to write flash command
-
-        */
-        uint32_t aduc702x_flash_write_code[] = {
-        //<_start>:
-                0xe3a05008,    // mov  r5, #8  ; 0x8
-                0xe5845004,    // str  r5, [r4, #4]
-                0xe3a06002,    // mov  r6, #2  ; 0x2
-        //<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  ; 0x4
-                0x1afffffc,    // bne  1001c <wait_complete>
-                0xe2822002,    // add  r2, r2, #2      ; 0x2
-                0xe2511001,    // subs r1, r1, #1      ; 0x1
-                0x0a000001,    // beq  1003c <done>
-                0xe3130001,    // tst  r3, #1  ; 0x1
-                0x1afffff3,    // bne  1000c <next>
-        //<done>:
-                0xeafffffe     // b    1003c <done>
-       };
-
-       /* flash write code */
-       if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code),
-                &aduc702x_info->write_algorithm) != ERROR_OK)
-       {
-               LOG_WARNING("no working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
-
-       retval=target_write_buffer(target, aduc702x_info->write_algorithm->address,
-                sizeof(aduc702x_flash_write_code), (uint8_t*)aduc702x_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 (aduc702x_info->write_algorithm)
-                               target_free_working_area(target, aduc702x_info->write_algorithm);
-
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-       }
-
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
-       init_reg_param(&reg_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, 0xFFFFF800);
-
-               if ((retval = target_run_algorithm(target, 0, NULL, 5,
-                        reg_params, aduc702x_info->write_algorithm->address,
-                        aduc702x_info->write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4,
-                        10000, &armv4_5_info)) != ERROR_OK)
-               {
-                       LOG_ERROR("error executing aduc702x flash write algorithm");
-                       break;
-               }
-
-               if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1)
-               {
-                       /* FIX!!!! what does this mean??? replace w/sensible error message */
-                       LOG_ERROR("aduc702x detected error writing flash");
-                       retval = ERROR_FAIL;
-                       break;
-               }
-
-               buffer += thisrun_count;
-               address += thisrun_count;
-               count -= thisrun_count;
-       }
-
-       target_free_working_area(target, source);
-       target_free_working_area(target, aduc702x_info->write_algorithm);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-       destroy_reg_param(&reg_params[4]);
-
-       return retval;
-}
-
-/* All-JTAG, single-access method.  Very slow.  Used only if there is no
- * working area available. */
-static int aduc702x_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;
-
-        aduc702x_set_write_enable(target, 1);
-
-       for (x = 0; x < count; x += 2) {
-                // FEEADR = address
-               target_write_u16(target, ADUC702x_FLASH + ADUC702x_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, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8));
-
-                // do single-write command
-               target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02);
-
-                if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
-                {
-                       LOG_ERROR("single write failed for address 0x%08lX\n", (unsigned long)(offset + x));
-                        aduc702x_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));
-
-        aduc702x_set_write_enable(target, 0);
-
-       return ERROR_OK;
-}
-
-int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       int retval;
-
-        /* try using a block write */
-        if ((retval = aduc702x_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("couldn't use block writes, falling back to single memory accesses");
-
-                        if ((retval = aduc702x_write_single(bank, buffer, offset, count)) != ERROR_OK)
-                        {
-                                LOG_ERROR("slow write failed");
-                                return ERROR_FLASH_OPERATION_FAILED;
-                        }
-                }
-        }
-
-        return retval;
-}
-
-static int aduc702x_probe(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "aduc702x flash driver info");
-       return ERROR_OK;
-}
-
-/* sets FEEMOD bit 3
- * enable = 1 enables writes & erases, 0 disables them */
-static int aduc702x_set_write_enable(struct target *target, int enable)
-{
-        // don't bother to preserve int enable bit here
-        target_write_u16(target, ADUC702x_FLASH + ADUC702x_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 aduc702x_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, ADUC702x_FLASH + ADUC702x_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 aduc702x_flash = {
-               .name = "aduc702x",
-               .flash_bank_command = &aduc702x_flash_bank_command,
-               .erase = &aduc702x_erase,
-               .protect = &aduc702x_protect,
-               .write = &aduc702x_write,
-               .probe = &aduc702x_probe,
-               .auto_probe = &aduc702x_probe,
-               .erase_check = &default_flash_blank_check,
-               .protect_check = &aduc702x_protect_check,
-               .info = &aduc702x_info
-       };
diff --git a/src/flash/at91sam3.c b/src/flash/at91sam3.c
deleted file mode 100644 (file)
index be17a5f..0000000
+++ /dev/null
@@ -1,2516 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2009 by Duane Ellis                                     *
- *   openocd@duaneellis.com                                                *
- *                                                                         *
- *   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.             *
-****************************************************************************/
-
-/* Some of the the lower level code was based on code supplied by
- * ATMEL under this copyright. */
-
-/* BEGIN ATMEL COPYRIGHT */
-/* ----------------------------------------------------------------------------
- *         ATMEL Microcontroller Software Support
- * ----------------------------------------------------------------------------
- * Copyright (c) 2009, Atmel Corporation
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the disclaimer below.
- *
- * Atmel's name may not be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
- * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * ----------------------------------------------------------------------------
- */
-/* END ATMEL COPYRIGHT */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include "types.h"
-#include "flash.h"
-#include "membuf.h"
-#include "at91sam3.h"
-#include "time_support.h"
-
-#define REG_NAME_WIDTH  (12)
-
-
-#define FLASH_BANK0_BASE   0x00080000
-#define FLASH_BANK1_BASE   0x00100000
-
-#define        AT91C_EFC_FCMD_GETD                 (0x0) // (EFC) Get Flash Descriptor
-#define        AT91C_EFC_FCMD_WP                   (0x1) // (EFC) Write Page
-#define        AT91C_EFC_FCMD_WPL                  (0x2) // (EFC) Write Page and Lock
-#define        AT91C_EFC_FCMD_EWP                  (0x3) // (EFC) Erase Page and Write Page
-#define        AT91C_EFC_FCMD_EWPL                 (0x4) // (EFC) Erase Page and Write Page then Lock
-#define        AT91C_EFC_FCMD_EA                   (0x5) // (EFC) Erase All
-// cmd6 is not present int he at91sam3u4/2/1 data sheet table 17-2
-// #define     AT91C_EFC_FCMD_EPL                  (0x6) // (EFC) Erase plane?
-// cmd7 is not present int he at91sam3u4/2/1 data sheet table 17-2
-// #define     AT91C_EFC_FCMD_EPA                  (0x7) // (EFC) Erase pages?
-#define        AT91C_EFC_FCMD_SLB                  (0x8) // (EFC) Set Lock Bit
-#define        AT91C_EFC_FCMD_CLB                  (0x9) // (EFC) Clear Lock Bit
-#define        AT91C_EFC_FCMD_GLB                  (0xA) // (EFC) Get Lock Bit
-#define        AT91C_EFC_FCMD_SFB                  (0xB) // (EFC) Set Fuse Bit
-#define        AT91C_EFC_FCMD_CFB                  (0xC) // (EFC) Clear Fuse Bit
-#define        AT91C_EFC_FCMD_GFB                  (0xD) // (EFC) Get Fuse Bit
-#define        AT91C_EFC_FCMD_STUI                 (0xE) // (EFC) Start Read Unique ID
-#define        AT91C_EFC_FCMD_SPUI                 (0xF) // (EFC) Stop Read Unique ID
-
-#define  offset_EFC_FMR   0
-#define  offset_EFC_FCR   4
-#define  offset_EFC_FSR   8
-#define  offset_EFC_FRR   12
-
-
-static float
-_tomhz(uint32_t freq_hz)
-{
-       float f;
-
-       f = ((float)(freq_hz)) / 1000000.0;
-       return f;
-}
-
-// How the chip is configured.
-struct sam3_cfg {
-       uint32_t unique_id[4];
-
-       uint32_t slow_freq;
-       uint32_t rc_freq;
-       uint32_t mainosc_freq;
-       uint32_t plla_freq;
-       uint32_t mclk_freq;
-       uint32_t cpu_freq;
-       uint32_t fclk_freq;
-       uint32_t pclk0_freq;
-       uint32_t pclk1_freq;
-       uint32_t pclk2_freq;
-
-
-#define SAM3_CHIPID_CIDR          (0x400E0740)
-       uint32_t CHIPID_CIDR;
-#define SAM3_CHIPID_EXID          (0x400E0744)
-       uint32_t CHIPID_EXID;
-
-#define SAM3_SUPC_CR              (0x400E1210)
-       uint32_t SUPC_CR;
-
-#define SAM3_PMC_BASE             (0x400E0400)
-#define SAM3_PMC_SCSR             (SAM3_PMC_BASE + 0x0008)
-       uint32_t PMC_SCSR;
-#define SAM3_PMC_PCSR             (SAM3_PMC_BASE + 0x0018)
-       uint32_t PMC_PCSR;
-#define SAM3_CKGR_UCKR            (SAM3_PMC_BASE + 0x001c)
-       uint32_t CKGR_UCKR;
-#define SAM3_CKGR_MOR             (SAM3_PMC_BASE + 0x0020)
-       uint32_t CKGR_MOR;
-#define SAM3_CKGR_MCFR            (SAM3_PMC_BASE + 0x0024)
-       uint32_t CKGR_MCFR;
-#define SAM3_CKGR_PLLAR           (SAM3_PMC_BASE + 0x0028)
-       uint32_t CKGR_PLLAR;
-#define SAM3_PMC_MCKR             (SAM3_PMC_BASE + 0x0030)
-       uint32_t PMC_MCKR;
-#define SAM3_PMC_PCK0             (SAM3_PMC_BASE + 0x0040)
-       uint32_t PMC_PCK0;
-#define SAM3_PMC_PCK1             (SAM3_PMC_BASE + 0x0044)
-       uint32_t PMC_PCK1;
-#define SAM3_PMC_PCK2             (SAM3_PMC_BASE + 0x0048)
-       uint32_t PMC_PCK2;
-#define SAM3_PMC_SR               (SAM3_PMC_BASE + 0x0068)
-       uint32_t PMC_SR;
-#define SAM3_PMC_IMR              (SAM3_PMC_BASE + 0x006c)
-       uint32_t PMC_IMR;
-#define SAM3_PMC_FSMR             (SAM3_PMC_BASE + 0x0070)
-       uint32_t PMC_FSMR;
-#define SAM3_PMC_FSPR             (SAM3_PMC_BASE + 0x0074)
-       uint32_t PMC_FSPR;
-};
-
-
-struct sam3_bank_private {
-       int probed;
-       // DANGER: THERE ARE DRAGONS HERE..
-       // NOTE: If you add more 'ghost' pointers
-       // be aware that you must *manually* update
-       // these pointers in the function sam3_GetDetails()
-       // See the comment "Here there be dragons"
-
-       // so we can find the chip we belong to
-       struct sam3_chip *pChip;
-       // so we can find the orginal bank pointer
-       struct flash_bank *pBank;
-       unsigned bank_number;
-       uint32_t controller_address;
-       uint32_t base_address;
-       bool present;
-       unsigned size_bytes;
-       unsigned nsectors;
-       unsigned sector_size;
-       unsigned page_size;
-};
-
-struct sam3_chip_details {
-       // THERE ARE DRAGONS HERE..
-       // note: If you add pointers here
-       // becareful about them as they
-       // may need to be updated inside
-       // the function: "sam3_GetDetails()
-       // which copy/overwrites the
-       // 'runtime' copy of this structure
-       uint32_t chipid_cidr;
-       const char *name;
-
-       unsigned n_gpnvms;
-#define SAM3_N_NVM_BITS 3
-       unsigned  gpnvm[SAM3_N_NVM_BITS];
-       unsigned  total_flash_size;
-       unsigned  total_sram_size;
-       unsigned  n_banks;
-#define SAM3_MAX_FLASH_BANKS 2
-       // these are "initialized" from the global const data
-       struct sam3_bank_private bank[SAM3_MAX_FLASH_BANKS];
-};
-
-
-struct sam3_chip {
-       struct sam3_chip *next;
-       int    probed;
-
-       // this is "initialized" from the global const structure
-       struct sam3_chip_details details;
-       struct target *target;
-       struct sam3_cfg cfg;
-
-       struct membuf *mbuf;
-};
-
-
-struct sam3_reg_list {
-       uint32_t address;  size_t struct_offset; const char *name;
-       void (*explain_func)(struct sam3_chip *pInfo);
-};
-
-
-static struct sam3_chip *all_sam3_chips;
-
-static struct sam3_chip *
-get_current_sam3(struct command_context *cmd_ctx)
-{
-       struct target *t;
-       static struct sam3_chip *p;
-
-       t = get_current_target(cmd_ctx);
-       if (!t) {
-               command_print(cmd_ctx, "No current target?");
-               return NULL;
-       }
-
-       p = all_sam3_chips;
-       if (!p) {
-               // this should not happen
-               // the command is not registered until the chip is created?
-               command_print(cmd_ctx, "No SAM3 chips exist?");
-               return NULL;
-       }
-
-       while (p) {
-               if (p->target == t) {
-                       return p;
-               }
-               p = p->next;
-       }
-       command_print(cmd_ctx, "Cannot find SAM3 chip?");
-       return NULL;
-}
-
-
-// these are used to *initialize* the "pChip->details" structure.
-static const struct sam3_chip_details all_sam3_details[] = {
-       {
-               .chipid_cidr    = 0x28100960,
-               .name           = "at91sam3u4e",
-               .total_flash_size     = 256 * 1024,
-               .total_sram_size      = 52 * 1024,
-               .n_gpnvms       = 3,
-               .n_banks        = 2,
-
-               // System boots at address 0x0
-               // gpnvm[1] = selects boot code
-               //     if gpnvm[1] == 0
-               //         boot is via "SAMBA" (rom)
-               //     else
-               //         boot is via FLASH
-               //         Selection is via gpnvm[2]
-               //     endif
-               //
-               // NOTE: banks 0 & 1 switch places
-               //     if gpnvm[2] == 0
-               //         Bank0 is the boot rom
-               //      else
-               //         Bank1 is the boot rom
-               //      endif
-//             .bank[0] = {
-               {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 0,
-                       .base_address = FLASH_BANK0_BASE,
-                       .controller_address = 0x400e0800,
-                       .present = 1,
-                       .size_bytes = 128 * 1024,
-                       .nsectors   = 16,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-
-//             .bank[1] = {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 1,
-                       .base_address = FLASH_BANK1_BASE,
-                       .controller_address = 0x400e0a00,
-                       .present = 1,
-                       .size_bytes = 128 * 1024,
-                       .nsectors   = 16,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-               },
-       },
-
-       {
-               .chipid_cidr    = 0x281a0760,
-               .name           = "at91sam3u2e",
-               .total_flash_size     = 128 * 1024,
-               .total_sram_size      =  36 * 1024,
-               .n_gpnvms       = 2,
-               .n_banks        = 1,
-
-               // System boots at address 0x0
-               // gpnvm[1] = selects boot code
-               //     if gpnvm[1] == 0
-               //         boot is via "SAMBA" (rom)
-               //     else
-               //         boot is via FLASH
-               //         Selection is via gpnvm[2]
-               //     endif
-//             .bank[0] = {
-               {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 0,
-                       .base_address = FLASH_BANK0_BASE,
-                       .controller_address = 0x400e0800,
-                       .present = 1,
-                       .size_bytes = 128 * 1024,
-                       .nsectors   = 16,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-//               .bank[1] = {
-                 {
-                       .present = 0,
-                       .probed = 0,
-                       .bank_number = 1,
-                 },
-               },
-       },
-       {
-               .chipid_cidr    = 0x28190560,
-               .name           = "at91sam3u1e",
-               .total_flash_size     = 64 * 1024,
-               .total_sram_size      = 20 * 1024,
-               .n_gpnvms       = 2,
-               .n_banks        = 1,
-
-               // System boots at address 0x0
-               // gpnvm[1] = selects boot code
-               //     if gpnvm[1] == 0
-               //         boot is via "SAMBA" (rom)
-               //     else
-               //         boot is via FLASH
-               //         Selection is via gpnvm[2]
-               //     endif
-               //
-
-//             .bank[0] = {
-               {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 0,
-                       .base_address = FLASH_BANK0_BASE,
-                       .controller_address = 0x400e0800,
-                       .present = 1,
-                       .size_bytes =  64 * 1024,
-                       .nsectors   =  8,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-
-//             .bank[1] = {
-                 {
-                       .present = 0,
-                       .probed = 0,
-                       .bank_number = 1,
-                 },
-               },
-       },
-
-       {
-               .chipid_cidr    = 0x28000960,
-               .name           = "at91sam3u4c",
-               .total_flash_size     = 256 * 1024,
-               .total_sram_size      = 52 * 1024,
-               .n_gpnvms       = 3,
-               .n_banks        = 2,
-
-               // System boots at address 0x0
-               // gpnvm[1] = selects boot code
-               //     if gpnvm[1] == 0
-               //         boot is via "SAMBA" (rom)
-               //     else
-               //         boot is via FLASH
-               //         Selection is via gpnvm[2]
-               //     endif
-               //
-               // NOTE: banks 0 & 1 switch places
-               //     if gpnvm[2] == 0
-               //         Bank0 is the boot rom
-               //      else
-               //         Bank1 is the boot rom
-               //      endif
-               {
-                 {
-//             .bank[0] = {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 0,
-                       .base_address = FLASH_BANK0_BASE,
-                       .controller_address = 0x400e0800,
-                       .present = 1,
-                       .size_bytes = 128 * 1024,
-                       .nsectors   = 16,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-//             .bank[1] = {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 1,
-                       .base_address = FLASH_BANK1_BASE,
-                       .controller_address = 0x400e0a00,
-                       .present = 1,
-                       .size_bytes = 128 * 1024,
-                       .nsectors   = 16,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-               },
-       },
-
-       {
-               .chipid_cidr    = 0x280a0760,
-               .name           = "at91sam3u2c",
-               .total_flash_size     = 128 * 1024,
-               .total_sram_size      = 36 * 1024,
-               .n_gpnvms       = 2,
-               .n_banks        = 1,
-
-               // System boots at address 0x0
-               // gpnvm[1] = selects boot code
-               //     if gpnvm[1] == 0
-               //         boot is via "SAMBA" (rom)
-               //     else
-               //         boot is via FLASH
-               //         Selection is via gpnvm[2]
-               //     endif
-               {
-//             .bank[0] = {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 0,
-                       .base_address = FLASH_BANK0_BASE,
-                       .controller_address = 0x400e0800,
-                       .present = 1,
-                       .size_bytes = 128 * 1024,
-                       .nsectors   = 16,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-//             .bank[1] = {
-                 {
-                       .present = 0,
-                       .probed = 0,
-                       .bank_number = 1,
-                 },
-               },
-       },
-       {
-               .chipid_cidr    = 0x28090560,
-               .name           = "at91sam3u1c",
-               .total_flash_size     = 64 * 1024,
-               .total_sram_size      = 20 * 1024,
-               .n_gpnvms       = 2,
-               .n_banks        = 1,
-
-               // System boots at address 0x0
-               // gpnvm[1] = selects boot code
-               //     if gpnvm[1] == 0
-               //         boot is via "SAMBA" (rom)
-               //     else
-               //         boot is via FLASH
-               //         Selection is via gpnvm[2]
-               //     endif
-               //
-
-               {
-//             .bank[0] = {
-                 {
-                       .probed = 0,
-                       .pChip  = NULL,
-                       .pBank  = NULL,
-                       .bank_number = 0,
-                       .base_address = FLASH_BANK0_BASE,
-                       .controller_address = 0x400e0800,
-                       .present = 1,
-                       .size_bytes =  64 * 1024,
-                       .nsectors   =  8,
-                       .sector_size = 8192,
-                       .page_size   = 256,
-                 },
-//             .bank[1] = {
-                 {
-                       .present = 0,
-                       .probed = 0,
-                       .bank_number = 1,
-
-                 },
-               },
-       },
-
-       // terminate
-       {
-               .chipid_cidr    = 0,
-               .name                   = NULL,
-       }
-};
-
-/* Globals above */
-/***********************************************************************
- **********************************************************************
- **********************************************************************
- **********************************************************************
- **********************************************************************
- **********************************************************************/
-/* *ATMEL* style code - from the SAM3 driver code */
-
-/**
- * Get the current status of the EEFC and
- * the value of some status bits (LOCKE, PROGE).
- * @param pPrivate - info about the bank
- * @param v        - result goes here
- */
-static int
-EFC_GetStatus(struct sam3_bank_private *pPrivate, uint32_t *v)
-{
-       int r;
-       r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FSR, v);
-       LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)",
-                         (unsigned int)(*v),
-                         ((unsigned int)((*v >> 2) & 1)),
-                         ((unsigned int)((*v >> 1) & 1)),
-                         ((unsigned int)((*v >> 0) & 1)));
-
-       return r;
-}
-
-/**
- * Get the result of the last executed command.
- * @param pPrivate - info about the bank
- * @param v        - result goes here
- */
-static int
-EFC_GetResult(struct sam3_bank_private *pPrivate, uint32_t *v)
-{
-       int r;
-       uint32_t rv;
-       r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FRR, &rv);
-       if (v) {
-               *v = rv;
-       }
-       LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv)));
-       return r;
-}
-
-static int
-EFC_StartCommand(struct sam3_bank_private *pPrivate,
-                                unsigned command, unsigned argument)
-{
-       uint32_t n,v;
-       int r;
-       int retry;
-
-       retry = 0;
- do_retry:
-
-    // Check command & argument
-    switch (command) {
-
-       case AT91C_EFC_FCMD_WP:
-       case AT91C_EFC_FCMD_WPL:
-       case AT91C_EFC_FCMD_EWP:
-       case AT91C_EFC_FCMD_EWPL:
-               // case AT91C_EFC_FCMD_EPL:
-               // case AT91C_EFC_FCMD_EPA:
-       case AT91C_EFC_FCMD_SLB:
-       case AT91C_EFC_FCMD_CLB:
-               n = (pPrivate->size_bytes / pPrivate->page_size);
-               if (argument >= n) {
-                       LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n));
-               }
-               break;
-
-       case AT91C_EFC_FCMD_SFB:
-       case AT91C_EFC_FCMD_CFB:
-               if (argument >= pPrivate->pChip->details.n_gpnvms) {
-                       LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs",
-                                         pPrivate->pChip->details.n_gpnvms);
-               }
-               break;
-
-       case AT91C_EFC_FCMD_GETD:
-       case AT91C_EFC_FCMD_EA:
-       case AT91C_EFC_FCMD_GLB:
-       case AT91C_EFC_FCMD_GFB:
-       case AT91C_EFC_FCMD_STUI:
-       case AT91C_EFC_FCMD_SPUI:
-               if (argument != 0) {
-                       LOG_ERROR("Argument is meaningless for cmd: %d", command);
-               }
-               break;
-       default:
-               LOG_ERROR("Unknown command %d", command);
-               break;
-    }
-
-       if (command == AT91C_EFC_FCMD_SPUI) {
-               // this is a very special situation.
-               // Situation (1) - error/retry - see below
-               //      And we are being called recursively
-               // Situation (2) - normal, finished reading unique id
-       } else {
-               // it should be "ready"
-               EFC_GetStatus(pPrivate, &v);
-               if (v & 1) {
-                       // then it is ready
-                       // we go on
-               } else {
-                       if (retry) {
-                               // we have done this before
-                               // the controller is not responding.
-                               LOG_ERROR("flash controller(%d) is not ready! Error", pPrivate->bank_number);
-                               return ERROR_FAIL;
-                       } else {
-                               retry++;
-                               LOG_ERROR("Flash controller(%d) is not ready, attempting reset",
-                                                 pPrivate->bank_number);
-                               // we do that by issuing the *STOP* command
-                               EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0);
-                               // above is recursive, and further recursion is blocked by
-                               // if (command == AT91C_EFC_FCMD_SPUI) above
-                               goto do_retry;
-                       }
-               }
-       }
-
-       v = (0x5A << 24) | (argument << 8) | command;
-       LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v)));
-       r = target_write_u32(pPrivate->pBank->target,
-                                                 pPrivate->controller_address + offset_EFC_FCR,
-                                                 v);
-       if (r != ERROR_OK) {
-               LOG_DEBUG("Error Write failed");
-       }
-       return r;
-}
-
-/**
- * Performs the given command and wait until its completion (or an error).
- * @param pPrivate - info about the bank
- * @param command  - Command to perform.
- * @param argument - Optional command argument.
- * @param status   - put command status bits here
- */
-static int
-EFC_PerformCommand(struct sam3_bank_private *pPrivate,
-                                       unsigned command,
-                                       unsigned argument,
-                                       uint32_t *status)
-{
-
-       int r;
-       uint32_t v;
-       long long ms_now, ms_end;
-
-       // default
-       if (status) {
-               *status = 0;
-       }
-
-       r = EFC_StartCommand(pPrivate, command, argument);
-       if (r != ERROR_OK) {
-               return r;
-       }
-
-       ms_end = 500 + timeval_ms();
-
-
-    do {
-               r = EFC_GetStatus(pPrivate, &v);
-               if (r != ERROR_OK) {
-                       return r;
-               }
-               ms_now = timeval_ms();
-               if (ms_now > ms_end) {
-                       // error
-                       LOG_ERROR("Command timeout");
-                       return ERROR_FAIL;
-               }
-    }
-    while ((v & 1) == 0)
-               ;
-
-       // error bits..
-       if (status) {
-               *status = (v & 0x6);
-       }
-       return ERROR_OK;
-
-}
-
-
-
-
-
-/**
- * Read the unique ID.
- * @param pPrivate - info about the bank
- * The unique ID is stored in the 'pPrivate' structure.
- */
-static int
-FLASHD_ReadUniqueID (struct sam3_bank_private *pPrivate)
-{
-       int r;
-       uint32_t v;
-       int x;
-       // assume 0
-    pPrivate->pChip->cfg.unique_id[0] = 0;
-    pPrivate->pChip->cfg.unique_id[1] = 0;
-    pPrivate->pChip->cfg.unique_id[2] = 0;
-    pPrivate->pChip->cfg.unique_id[3] = 0;
-
-       LOG_DEBUG("Begin");
-       r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0);
-       if (r < 0) {
-               return r;
-       }
-
-       for (x = 0 ; x < 4 ; x++) {
-               r = target_read_u32(pPrivate->pChip->target,
-                                                        pPrivate->pBank->base + (x * 4),
-                                                        &v);
-               if (r < 0) {
-                       return r;
-               }
-               pPrivate->pChip->cfg.unique_id[x] = v;
-       }
-
-    r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL);
-       LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x",
-                         r,
-                         (unsigned int)(pPrivate->pChip->cfg.unique_id[0]),
-                         (unsigned int)(pPrivate->pChip->cfg.unique_id[1]),
-                         (unsigned int)(pPrivate->pChip->cfg.unique_id[2]),
-                         (unsigned int)(pPrivate->pChip->cfg.unique_id[3]));
-       return r;
-
-}
-
-/**
- * Erases the entire flash.
- * @param pPrivate - the info about the bank.
- */
-static int
-FLASHD_EraseEntireBank(struct sam3_bank_private *pPrivate)
-{
-       LOG_DEBUG("Here");
-       return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL);
-}
-
-
-
-/**
- * Gets current GPNVM state.
- * @param pPrivate - info about the bank.
- * @param gpnvm    -  GPNVM bit index.
- * @param puthere  - result stored here.
- */
-//------------------------------------------------------------------------------
-static int
-FLASHD_GetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere)
-{
-       uint32_t v;
-       int r;
-
-       LOG_DEBUG("Here");
-       if (pPrivate->bank_number != 0) {
-               LOG_ERROR("GPNVM only works with Bank0");
-               return ERROR_FAIL;
-       }
-
-       if (gpnvm >= pPrivate->pChip->details.n_gpnvms) {
-               LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
-                                 gpnvm,pPrivate->pChip->details.n_gpnvms);
-               return ERROR_FAIL;
-       }
-
-    // Get GPNVMs status
-       r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL);
-       if (r != ERROR_OK) {
-               LOG_ERROR("Failed");
-               return r;
-       }
-
-    r = EFC_GetResult(pPrivate, &v);
-
-       if (puthere) {
-               // Check if GPNVM is set
-               // get the bit and make it a 0/1
-               *puthere = (v >> gpnvm) & 1;
-       }
-
-       return r;
-}
-
-
-
-
-/**
- * Clears the selected GPNVM bit.
- * @param pPrivate info about the bank
- * @param gpnvm GPNVM index.
- * @returns 0 if successful; otherwise returns an error code.
- */
-static int
-FLASHD_ClrGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm)
-{
-       int r;
-       unsigned v;
-
-       LOG_DEBUG("Here");
-       if (pPrivate->bank_number != 0) {
-               LOG_ERROR("GPNVM only works with Bank0");
-               return ERROR_FAIL;
-       }
-
-       if (gpnvm >= pPrivate->pChip->details.n_gpnvms) {
-               LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
-                                 gpnvm,pPrivate->pChip->details.n_gpnvms);
-               return ERROR_FAIL;
-       }
-
-       r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v);
-       if (r != ERROR_OK) {
-               LOG_DEBUG("Failed: %d",r);
-               return r;
-       }
-       r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL);
-       LOG_DEBUG("End: %d",r);
-       return r;
-}
-
-
-
-/**
- * Sets the selected GPNVM bit.
- * @param pPrivate info about the bank
- * @param gpnvm GPNVM index.
- */
-static int
-FLASHD_SetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm)
-{
-       int r;
-       unsigned v;
-
-       if (pPrivate->bank_number != 0) {
-               LOG_ERROR("GPNVM only works with Bank0");
-               return ERROR_FAIL;
-       }
-
-       if (gpnvm >= pPrivate->pChip->details.n_gpnvms) {
-               LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
-                                 gpnvm,pPrivate->pChip->details.n_gpnvms);
-               return ERROR_FAIL;
-       }
-
-       r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v);
-       if (r != ERROR_OK) {
-               return r;
-       }
-       if (v) {
-               // already set
-               r = ERROR_OK;
-       } else {
-               // set it
-               r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL);
-       }
-       return r;
-}
-
-
-/**
- * Returns a bit field (at most 64) of locked regions within a page.
- * @param pPrivate info about the bank
- * @param v where to store locked bits
- */
-static int
-FLASHD_GetLockBits(struct sam3_bank_private *pPrivate, uint32_t *v)
-{
-       int r;
-       LOG_DEBUG("Here");
-    r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL);
-       if (r == ERROR_OK) {
-               r = EFC_GetResult(pPrivate, v);
-       }
-       LOG_DEBUG("End: %d",r);
-       return r;
-}
-
-
-/**
- * Unlocks all the regions in the given address range.
- * @param pPrivate info about the bank
- * @param start_sector first sector to unlock
- * @param end_sector last (inclusive) to unlock
- */
-
-static int
-FLASHD_Unlock(struct sam3_bank_private *pPrivate,
-                          unsigned start_sector,
-                          unsigned end_sector)
-{
-       int r;
-       uint32_t status;
-       uint32_t pg;
-       uint32_t pages_per_sector;
-
-       pages_per_sector = pPrivate->sector_size / pPrivate->page_size;
-
-    /* Unlock all pages */
-    while (start_sector <= end_sector) {
-               pg = start_sector * pages_per_sector;
-
-        r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status);
-        if (r != ERROR_OK) {
-            return r;
-        }
-        start_sector++;
-    }
-
-    return ERROR_OK;
-}
-
-
-/**
- * Locks regions
- * @param pPrivate - info about the bank
- * @param start_sector - first sector to lock
- * @param end_sector   - last sector (inclusive) to lock
- */
-static int
-FLASHD_Lock(struct sam3_bank_private *pPrivate,
-                        unsigned start_sector,
-                        unsigned end_sector)
-{
-       uint32_t status;
-       uint32_t pg;
-       uint32_t pages_per_sector;
-       int r;
-
-       pages_per_sector = pPrivate->sector_size / pPrivate->page_size;
-
-    /* Lock all pages */
-    while (start_sector <= end_sector) {
-               pg = start_sector * pages_per_sector;
-
-        r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status);
-        if (r != ERROR_OK) {
-            return r;
-        }
-        start_sector++;
-    }
-    return ERROR_OK;
-}
-
-
-/****** END SAM3 CODE ********/
-
-/* begin helpful debug code */
-
-static void
-sam3_sprintf(struct sam3_chip *pChip , const char *fmt, ...)
-{
-       va_list ap;
-       va_start(ap,fmt);
-       if (pChip->mbuf == NULL) {
-               return;
-       }
-
-       membuf_vsprintf(pChip->mbuf, fmt, ap);
-       va_end(ap);
-}
-
-// print the fieldname, the field value, in dec & hex, and return field value
-static uint32_t
-sam3_reg_fieldname(struct sam3_chip *pChip,
-                                       const char *regname,
-                                       uint32_t value,
-                                       unsigned shift,
-                                       unsigned width)
-{
-       uint32_t v;
-       int hwidth, dwidth;
-
-
-       // extract the field
-       v = value >> shift;
-       v = v & ((1 << width)-1);
-       if (width <= 16) {
-               hwidth = 4;
-               dwidth = 5;
-       } else {
-               hwidth = 8;
-               dwidth = 12;
-       }
-
-       // show the basics
-       sam3_sprintf(pChip, "\t%*s: %*d [0x%0*x] ",
-                                 REG_NAME_WIDTH, regname,
-                                 dwidth, v,
-                                 hwidth, v);
-       return v;
-}
-
-
-static const char _unknown[] = "unknown";
-static const char * const eproc_names[] = {
-       _unknown,                                       // 0
-       "arm946es",                                     // 1
-       "arm7tdmi",                                     // 2
-       "cortex-m3",                            // 3
-       "arm920t",                                      // 4
-       "arm926ejs",                            // 5
-       _unknown,                                       // 6
-       _unknown,                                       // 7
-       _unknown,                                       // 8
-       _unknown,                                       // 9
-       _unknown,                                       // 10
-       _unknown,                                       // 11
-       _unknown,                                       // 12
-       _unknown,                                       // 13
-       _unknown,                                       // 14
-       _unknown,                                       // 15
-};
-
-#define nvpsize2 nvpsize               // these two tables are identical
-static const char * const nvpsize[] = {
-       "none",                                         //  0
-       "8K bytes",                                     //  1
-       "16K bytes",                            //  2
-       "32K bytes",                            //  3
-       _unknown,                                       //  4
-       "64K bytes",                            //  5
-       _unknown,                                       //  6
-       "128K bytes",                           //  7
-       _unknown,                                       //  8
-       "256K bytes",                           //  9
-       "512K bytes",                           // 10
-       _unknown,                                       // 11
-       "1024K bytes",                          // 12
-       _unknown,                                       // 13
-       "2048K bytes",                          // 14
-       _unknown,                                       // 15
-};
-
-
-static const char * const sramsize[] = {
-       "48K Bytes",                            //  0
-       "1K Bytes",                                     //  1
-       "2K Bytes",                                     //  2
-       "6K Bytes",                                     //  3
-       "112K Bytes",                           //  4
-       "4K Bytes",                                     //  5
-       "80K Bytes",                            //  6
-       "160K Bytes",                           //  7
-       "8K Bytes",                                     //  8
-       "16K Bytes",                            //  9
-       "32K Bytes",                            // 10
-       "64K Bytes",                            // 11
-       "128K Bytes",                           // 12
-       "256K Bytes",                           // 13
-       "96K Bytes",                            // 14
-       "512K Bytes",                           // 15
-
-};
-
-static const struct archnames { unsigned value; const char *name; } archnames[] = {
-       { 0x19,  "AT91SAM9xx Series"                                            },
-       { 0x29,  "AT91SAM9XExx Series"                                          },
-       { 0x34,  "AT91x34 Series"                                                       },
-       { 0x37,  "CAP7 Series"                                                          },
-       { 0x39,  "CAP9 Series"                                                          },
-       { 0x3B,  "CAP11 Series"                                                         },
-       { 0x40,  "AT91x40 Series"                                                       },
-       { 0x42,  "AT91x42 Series"                                                       },
-       { 0x55,  "AT91x55 Series"                                                       },
-       { 0x60,  "AT91SAM7Axx Series"                                           },
-       { 0x61,  "AT91SAM7AQxx Series"                                          },
-       { 0x63,  "AT91x63 Series"                                                       },
-       { 0x70,  "AT91SAM7Sxx Series"                                           },
-       { 0x71,  "AT91SAM7XCxx Series"                                          },
-       { 0x72,  "AT91SAM7SExx Series"                                          },
-       { 0x73,  "AT91SAM7Lxx Series"                                           },
-       { 0x75,  "AT91SAM7Xxx Series"                                           },
-       { 0x76,  "AT91SAM7SLxx Series"                                          },
-       { 0x80,  "ATSAM3UxC Series (100-pin version)"           },
-       { 0x81,  "ATSAM3UxE Series (144-pin version)"           },
-       { 0x83,  "ATSAM3AxC Series (100-pin version)"           },
-       { 0x84,  "ATSAM3XxC Series (100-pin version)"           },
-       { 0x85,  "ATSAM3XxE Series (144-pin version)"           },
-       { 0x86,  "ATSAM3XxG Series (208/217-pin version)"       },
-       { 0x88,  "ATSAM3SxA Series (48-pin version)"            },
-       { 0x89,  "ATSAM3SxB Series (64-pin version)"            },
-       { 0x8A,  "ATSAM3SxC Series (100-pin version)"           },
-       { 0x92,  "AT91x92 Series"                                                       },
-       { 0xF0,  "AT75Cxx Series"                                                       },
-       { -1, NULL },
-
-};
-
-static const char * const nvptype[] = {
-       "rom", // 0
-       "romless or onchip flash", // 1
-       "embedded flash memory", // 2
-       "rom(nvpsiz) + embedded flash (nvpsiz2)", //3
-       "sram emulating flash", // 4
-       _unknown, // 5
-       _unknown, // 6
-       _unknown, // 7
-
-};
-
-static const char *_yes_or_no(uint32_t v)
-{
-       if (v) {
-               return "YES";
-       } else {
-               return "NO";
-       }
-}
-
-static const char * const _rc_freq[] = {
-       "4 MHz", "8 MHz", "12 MHz", "reserved"
-};
-
-static void
-sam3_explain_ckgr_mor(struct sam3_chip *pChip)
-{
-       uint32_t v;
-       uint32_t rcen;
-
-       v = sam3_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1);
-       sam3_sprintf(pChip, "(main xtal enabled: %s)\n",
-                                 _yes_or_no(v));
-       v = sam3_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1);
-       sam3_sprintf(pChip, "(main osc bypass: %s)\n",
-                                 _yes_or_no(v));
-       rcen = sam3_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 2, 1);
-       sam3_sprintf(pChip, "(onchip RC-OSC enabled: %s)\n",
-                                 _yes_or_no(rcen));
-       v = sam3_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3);
-       sam3_sprintf(pChip, "(onchip RC-OSC freq: %s)\n",
-                                 _rc_freq[v]);
-
-       pChip->cfg.rc_freq = 0;
-       if (rcen) {
-               switch (v) {
-               default:
-                       pChip->cfg.rc_freq = 0;
-               case 0:
-                       pChip->cfg.rc_freq = 4 * 1000 * 1000;
-                       break;
-               case 1:
-                       pChip->cfg.rc_freq = 8 * 1000 * 1000;
-                       break;
-               case 2:
-                       pChip->cfg.rc_freq = 12* 1000 * 1000;
-                       break;
-               }
-       }
-
-       v = sam3_reg_fieldname(pChip,"MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8);
-       sam3_sprintf(pChip, "(startup clks, time= %f uSecs)\n",
-                                 ((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq)));
-       v = sam3_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1);
-       sam3_sprintf(pChip, "(mainosc source: %s)\n",
-                                 v ? "external xtal" : "internal RC");
-
-       v = sam3_reg_fieldname(pChip,"CFDEN", pChip->cfg.CKGR_MOR, 25, 1);
-       sam3_sprintf(pChip, "(clock failure enabled: %s)\n",
-                                _yes_or_no(v));
-}
-
-
-
-static void
-sam3_explain_chipid_cidr(struct sam3_chip *pChip)
-{
-       int x;
-       uint32_t v;
-       const char *cp;
-
-       sam3_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5);
-       sam3_sprintf(pChip,"\n");
-
-       v = sam3_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3);
-       sam3_sprintf(pChip, "%s\n", eproc_names[v]);
-
-       v = sam3_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4);
-       sam3_sprintf(pChip, "%s\n", nvpsize[v]);
-
-       v = sam3_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4);
-       sam3_sprintf(pChip, "%s\n", nvpsize2[v]);
-
-       v = sam3_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16,4);
-       sam3_sprintf(pChip, "%s\n", sramsize[ v ]);
-
-       v = sam3_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8);
-       cp = _unknown;
-       for (x = 0 ; archnames[x].name ; x++) {
-               if (v == archnames[x].value) {
-                       cp = archnames[x].name;
-                       break;
-               }
-       }
-
-       sam3_sprintf(pChip, "%s\n", cp);
-
-       v = sam3_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3);
-       sam3_sprintf(pChip, "%s\n", nvptype[ v ]);
-
-       v = sam3_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1);
-       sam3_sprintf(pChip, "(exists: %s)\n", _yes_or_no(v));
-}
-
-static void
-sam3_explain_ckgr_mcfr(struct sam3_chip *pChip)
-{
-       uint32_t v;
-
-
-       v = sam3_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1);
-       sam3_sprintf(pChip, "(main ready: %s)\n", _yes_or_no(v));
-
-       v = sam3_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16);
-
-       v = (v * pChip->cfg.slow_freq) / 16;
-       pChip->cfg.mainosc_freq = v;
-
-       sam3_sprintf(pChip, "(%3.03f Mhz (%d.%03dkhz slowclk)\n",
-                                _tomhz(v),
-                                pChip->cfg.slow_freq / 1000,
-                                pChip->cfg.slow_freq % 1000);
-
-}
-
-static void
-sam3_explain_ckgr_plla(struct sam3_chip *pChip)
-{
-       uint32_t mula,diva;
-
-       diva = sam3_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8);
-       sam3_sprintf(pChip,"\n");
-       mula = sam3_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11);
-       sam3_sprintf(pChip,"\n");
-       pChip->cfg.plla_freq = 0;
-       if (mula == 0) {
-               sam3_sprintf(pChip,"\tPLLA Freq: (Disabled,mula = 0)\n");
-       } else if (diva == 0) {
-               sam3_sprintf(pChip,"\tPLLA Freq: (Disabled,diva = 0)\n");
-       } else if (diva == 1) {
-               pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1));
-               sam3_sprintf(pChip,"\tPLLA Freq: %3.03f MHz\n",
-                                        _tomhz(pChip->cfg.plla_freq));
-       }
-}
-
-
-static void
-sam3_explain_mckr(struct sam3_chip *pChip)
-{
-       uint32_t css, pres, fin = 0;
-       int pdiv = 0;
-       const char *cp = NULL;
-
-       css = sam3_reg_fieldname(pChip, "CSS", pChip->cfg.PMC_MCKR, 0, 2);
-       switch (css & 3) {
-       case 0:
-               fin = pChip->cfg.slow_freq;
-               cp = "slowclk";
-               break;
-       case 1:
-               fin = pChip->cfg.mainosc_freq;
-               cp  = "mainosc";
-               break;
-       case 2:
-               fin = pChip->cfg.plla_freq;
-               cp  = "plla";
-               break;
-       case 3:
-               if (pChip->cfg.CKGR_UCKR & (1 << 16)) {
-                       fin = 480 * 1000 * 1000;
-                       cp = "upll";
-               } else {
-                       fin = 0;
-                       cp  = "upll (*ERROR* UPLL is disabled)";
-               }
-               break;
-       default:
-               assert(0);
-               break;
-       }
-
-       sam3_sprintf(pChip, "%s (%3.03f Mhz)\n",
-                                 cp,
-                                 _tomhz(fin));
-       pres = sam3_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3);
-       switch (pres & 0x07) {
-       case 0:
-               pdiv = 1;
-               cp = "selected clock";
-       case 1:
-               pdiv = 2;
-               cp = "clock/2";
-               break;
-       case 2:
-               pdiv = 4;
-               cp = "clock/4";
-               break;
-       case 3:
-               pdiv = 8;
-               cp = "clock/8";
-               break;
-       case 4:
-               pdiv = 16;
-               cp = "clock/16";
-               break;
-       case 5:
-               pdiv = 32;
-               cp = "clock/32";
-               break;
-       case 6:
-               pdiv = 64;
-               cp = "clock/64";
-               break;
-       case 7:
-               pdiv = 6;
-               cp = "clock/6";
-               break;
-       default:
-               assert(0);
-               break;
-       }
-       sam3_sprintf(pChip, "(%s)\n", cp);
-       fin = fin / pdiv;
-       // sam3 has a *SINGLE* clock -
-       // other at91 series parts have divisors for these.
-       pChip->cfg.cpu_freq = fin;
-       pChip->cfg.mclk_freq = fin;
-       pChip->cfg.fclk_freq = fin;
-       sam3_sprintf(pChip, "\t\tResult CPU Freq: %3.03f\n",
-                                 _tomhz(fin));
-}
-
-#if 0
-static struct sam3_chip *
-target2sam3(struct target *pTarget)
-{
-       struct sam3_chip *pChip;
-
-       if (pTarget == NULL) {
-               return NULL;
-       }
-
-       pChip = all_sam3_chips;
-       while (pChip) {
-               if (pChip->target == pTarget) {
-                       break; // return below
-               } else {
-                       pChip = pChip->next;
-               }
-       }
-       return pChip;
-}
-#endif
-
-static uint32_t *
-sam3_get_reg_ptr(struct sam3_cfg *pCfg, const struct sam3_reg_list *pList)
-{
-       // this function exists to help
-       // keep funky offsetof() errors
-       // and casting from causing bugs
-
-       // By using prototypes - we can detect what would
-       // be casting errors.
-
-       return ((uint32_t *)(((char *)(pCfg)) + pList->struct_offset));
-}
-
-
-#define SAM3_ENTRY(NAME, FUNC)  { .address = SAM3_ ## NAME, .struct_offset = offsetof(struct sam3_cfg, NAME), #NAME, FUNC }
-static const struct sam3_reg_list sam3_all_regs[] = {
-       SAM3_ENTRY(CKGR_MOR , sam3_explain_ckgr_mor),
-       SAM3_ENTRY(CKGR_MCFR , sam3_explain_ckgr_mcfr),
-       SAM3_ENTRY(CKGR_PLLAR , sam3_explain_ckgr_plla),
-       SAM3_ENTRY(CKGR_UCKR , NULL),
-       SAM3_ENTRY(PMC_FSMR , NULL),
-       SAM3_ENTRY(PMC_FSPR , NULL),
-       SAM3_ENTRY(PMC_IMR , NULL),
-       SAM3_ENTRY(PMC_MCKR , sam3_explain_mckr),
-       SAM3_ENTRY(PMC_PCK0 , NULL),
-       SAM3_ENTRY(PMC_PCK1 , NULL),
-       SAM3_ENTRY(PMC_PCK2 , NULL),
-       SAM3_ENTRY(PMC_PCSR , NULL),
-       SAM3_ENTRY(PMC_SCSR , NULL),
-       SAM3_ENTRY(PMC_SR , NULL),
-       SAM3_ENTRY(CHIPID_CIDR , sam3_explain_chipid_cidr),
-       SAM3_ENTRY(CHIPID_EXID , NULL),
-       SAM3_ENTRY(SUPC_CR, NULL),
-
-       // TERMINATE THE LIST
-       { .name = NULL }
-};
-#undef SAM3_ENTRY
-
-
-
-
-static struct sam3_bank_private *
-get_sam3_bank_private(struct flash_bank *bank)
-{
-       return (struct sam3_bank_private *)(bank->driver_priv);
-}
-
-/**
- * Given a pointer to where it goes in the structure,
- * determine the register name, address from the all registers table.
- */
-static const struct sam3_reg_list *
-sam3_GetReg(struct sam3_chip *pChip, uint32_t *goes_here)
-{
-       const struct sam3_reg_list *pReg;
-
-       pReg = &(sam3_all_regs[0]);
-       while (pReg->name) {
-               uint32_t *pPossible;
-
-               // calculate where this one go..
-               // it is "possibly" this register.
-
-               pPossible = ((uint32_t *)(((char *)(&(pChip->cfg))) + pReg->struct_offset));
-
-               // well? Is it this register
-               if (pPossible == goes_here) {
-                       // Jump for joy!
-                       return pReg;
-               }
-
-               // next...
-               pReg++;
-       }
-       // This is *TOTAL*PANIC* - we are totally screwed.
-       LOG_ERROR("INVALID SAM3 REGISTER");
-       return NULL;
-}
-
-
-static int
-sam3_ReadThisReg(struct sam3_chip *pChip, uint32_t *goes_here)
-{
-       const struct sam3_reg_list *pReg;
-       int r;
-
-       pReg = sam3_GetReg(pChip, goes_here);
-       if (!pReg) {
-               return ERROR_FAIL;
-       }
-
-       r = target_read_u32(pChip->target, pReg->address, goes_here);
-       if (r != ERROR_OK) {
-               LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d\n",
-                                 pReg->name, (unsigned)(pReg->address), r);
-       }
-       return r;
-}
-
-
-
-static int
-sam3_ReadAllRegs(struct sam3_chip *pChip)
-{
-       int r;
-       const struct sam3_reg_list *pReg;
-
-       pReg = &(sam3_all_regs[0]);
-       while (pReg->name) {
-               r = sam3_ReadThisReg(pChip,
-                                                                 sam3_get_reg_ptr(&(pChip->cfg), pReg));
-               if (r != ERROR_OK) {
-                       LOG_ERROR("Cannot read SAM3 registere: %s @ 0x%08x, Error: %d\n",
-                                         pReg->name, ((unsigned)(pReg->address)), r);
-                       return r;
-               }
-
-               pReg++;
-       }
-
-       return ERROR_OK;
-}
-
-
-static int
-sam3_GetInfo(struct sam3_chip *pChip)
-{
-       const struct sam3_reg_list *pReg;
-       uint32_t regval;
-
-       membuf_reset(pChip->mbuf);
-
-
-       pReg = &(sam3_all_regs[0]);
-       while (pReg->name) {
-               // display all regs
-               LOG_DEBUG("Start: %s", pReg->name);
-               regval = *sam3_get_reg_ptr(&(pChip->cfg), pReg);
-               sam3_sprintf(pChip, "%*s: [0x%08x] -> 0x%08x\n",
-                                        REG_NAME_WIDTH,
-                                        pReg->name,
-                                        pReg->address,
-                                        regval);
-               if (pReg->explain_func) {
-                       (*(pReg->explain_func))(pChip);
-               }
-               LOG_DEBUG("End: %s", pReg->name);
-               pReg++;
-       }
-       sam3_sprintf(pChip,"   rc-osc: %3.03f MHz\n", _tomhz(pChip->cfg.rc_freq));
-       sam3_sprintf(pChip,"  mainosc: %3.03f MHz\n", _tomhz(pChip->cfg.mainosc_freq));
-       sam3_sprintf(pChip,"     plla: %3.03f MHz\n", _tomhz(pChip->cfg.plla_freq));
-       sam3_sprintf(pChip," cpu-freq: %3.03f MHz\n", _tomhz(pChip->cfg.cpu_freq));
-       sam3_sprintf(pChip,"mclk-freq: %3.03f MHz\n", _tomhz(pChip->cfg.mclk_freq));
-
-
-       sam3_sprintf(pChip, " UniqueId: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 pChip->cfg.unique_id[0],
-                                 pChip->cfg.unique_id[1],
-                                 pChip->cfg.unique_id[2],
-                                 pChip->cfg.unique_id[3]);
-
-
-       return ERROR_OK;
-}
-
-
-static int
-sam3_erase_check(struct flash_bank *bank)
-{
-       int x;
-
-       LOG_DEBUG("Here");
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-       if (0 == bank->num_sectors) {
-               LOG_ERROR("Target: not supported/not probed\n");
-               return ERROR_FAIL;
-       }
-
-       LOG_INFO("sam3 - supports auto-erase, erase_check ignored");
-       for (x = 0 ; x < bank->num_sectors ; x++) {
-               bank->sectors[x].is_erased = 1;
-       }
-
-       LOG_DEBUG("Done");
-       return ERROR_OK;
-}
-
-static int
-sam3_protect_check(struct flash_bank *bank)
-{
-       int r;
-       uint32_t v=0;
-       unsigned x;
-       struct sam3_bank_private *pPrivate;
-
-       LOG_DEBUG("Begin");
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       pPrivate = get_sam3_bank_private(bank);
-       if (!pPrivate) {
-               LOG_ERROR("no private for this bank?");
-               return ERROR_FAIL;
-       }
-       if (!(pPrivate->probed)) {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       r = FLASHD_GetLockBits(pPrivate , &v);
-       if (r != ERROR_OK) {
-               LOG_DEBUG("Failed: %d",r);
-               return r;
-       }
-
-       for (x = 0 ; x < pPrivate->nsectors ; x++) {
-               bank->sectors[x].is_protected = (!!(v & (1 << x)));
-       }
-       LOG_DEBUG("Done");
-       return ERROR_OK;
-}
-
-FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
-{
-       struct sam3_chip *pChip;
-
-       pChip = all_sam3_chips;
-
-       // is this an existing chip?
-       while (pChip) {
-               if (pChip->target == bank->target) {
-                       break;
-               }
-               pChip = pChip->next;
-       }
-
-       if (!pChip) {
-               // this is a *NEW* chip
-               pChip = calloc(1, sizeof(struct sam3_chip));
-               if (!pChip) {
-                       LOG_ERROR("NO RAM!");
-                       return ERROR_FAIL;
-               }
-               pChip->target = bank->target;
-               // insert at head
-               pChip->next = all_sam3_chips;
-               all_sam3_chips = pChip;
-               pChip->target = bank->target;
-               // assumption is this runs at 32khz
-               pChip->cfg.slow_freq = 32768;
-               pChip->probed = 0;
-               pChip->mbuf = membuf_new();
-               if (!(pChip->mbuf)) {
-                       LOG_ERROR("no memory");
-                       return ERROR_FAIL;
-               }
-       }
-
-       switch (bank->base) {
-       default:
-               LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x)",
-                                 ((unsigned int)(bank->base)),
-                                 ((unsigned int)(FLASH_BANK0_BASE)),
-                                 ((unsigned int)(FLASH_BANK1_BASE)));
-               return ERROR_FAIL;
-               break;
-       case FLASH_BANK0_BASE:
-               bank->driver_priv = &(pChip->details.bank[0]);
-               bank->bank_number = 0;
-               pChip->details.bank[0].pChip = pChip;
-               pChip->details.bank[0].pBank = bank;
-               break;
-       case FLASH_BANK1_BASE:
-               bank->driver_priv = &(pChip->details.bank[1]);
-               bank->bank_number = 1;
-               pChip->details.bank[1].pChip = pChip;
-               pChip->details.bank[1].pBank = bank;
-               break;
-       }
-
-       // we initialize after probing.
-       return ERROR_OK;
-}
-
-static int
-sam3_GetDetails(struct sam3_bank_private *pPrivate)
-{
-       const struct sam3_chip_details *pDetails;
-       struct sam3_chip *pChip;
-       void *vp;
-       struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS];
-
-       unsigned x;
-       const char *cp;
-
-       LOG_DEBUG("Begin");
-       pDetails = all_sam3_details;
-       while (pDetails->name) {
-               if (pDetails->chipid_cidr == pPrivate->pChip->cfg.CHIPID_CIDR) {
-                       break;
-               } else {
-                       pDetails++;
-               }
-       }
-       if (pDetails->name == NULL) {
-               LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can this chip?)",
-                                 (unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR));
-               // Help the victim, print details about the chip
-               membuf_reset(pPrivate->pChip->mbuf);
-               membuf_sprintf(pPrivate->pChip->mbuf,
-                                               "SAM3 CHIPID_CIDR: 0x%08x decodes as follows\n",
-                                               pPrivate->pChip->cfg.CHIPID_CIDR);
-               sam3_explain_chipid_cidr(pPrivate->pChip);
-               cp = membuf_strtok(pPrivate->pChip->mbuf, "\n", &vp);
-               while (cp) {
-                       LOG_INFO("%s", cp);
-                       cp = membuf_strtok(NULL, "\n", &vp);
-               }
-               return ERROR_FAIL;
-       }
-
-       // DANGER: THERE ARE DRAGONS HERE
-
-       // get our pChip - it is going
-       // to be over-written shortly
-       pChip = pPrivate->pChip;
-
-       // Note that, in reality:
-       //
-       //     pPrivate = &(pChip->details.bank[0])
-       // or  pPrivate = &(pChip->details.bank[1])
-       //
-
-       // save the "bank" pointers
-       for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
-               saved_banks[ x ] = pChip->details.bank[x].pBank;
-       }
-
-       // Overwrite the "details" structure.
-       memcpy(&(pPrivate->pChip->details),
-                       pDetails,
-                       sizeof(pPrivate->pChip->details));
-
-       // now fix the ghosted pointers
-       for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
-               pChip->details.bank[x].pChip = pChip;
-               pChip->details.bank[x].pBank = saved_banks[x];
-       }
-
-       // update the *BANK*SIZE*
-
-       LOG_DEBUG("End");
-       return ERROR_OK;
-}
-
-
-
-static int
-_sam3_probe(struct flash_bank *bank, int noise)
-{
-       unsigned x;
-       int r;
-       struct sam3_bank_private *pPrivate;
-
-
-       LOG_DEBUG("Begin: Bank: %d, Noise: %d", bank->bank_number, noise);
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       pPrivate = get_sam3_bank_private(bank);
-       if (!pPrivate) {
-               LOG_ERROR("Invalid/unknown bank number\n");
-               return ERROR_FAIL;
-       }
-
-       r = sam3_ReadAllRegs(pPrivate->pChip);
-       if (r != ERROR_OK) {
-               return r;
-       }
-
-
-       LOG_DEBUG("Here");
-       r = sam3_GetInfo(pPrivate->pChip);
-       if (r != ERROR_OK) {
-               return r;
-       }
-       if (!(pPrivate->pChip->probed)) {
-               pPrivate->pChip->probed = 1;
-               LOG_DEBUG("Here");
-               r = sam3_GetDetails(pPrivate);
-               if (r != ERROR_OK) {
-                       return r;
-               }
-       }
-
-       // update the flash bank size
-       for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
-               if (bank->base == pPrivate->pChip->details.bank[0].base_address) {
-                       bank->size =  pPrivate->pChip->details.bank[0].size_bytes;
-                       break;
-               }
-       }
-
-       if (bank->sectors == NULL) {
-               bank->sectors     = calloc(pPrivate->nsectors, (sizeof((bank->sectors)[0])));
-               if (bank->sectors == NULL) {
-                       LOG_ERROR("No memory!");
-                       return ERROR_FAIL;
-               }
-               bank->num_sectors = pPrivate->nsectors;
-
-               for (x = 0 ; ((int)(x)) < bank->num_sectors ; x++) {
-                       bank->sectors[x].size         = pPrivate->sector_size;
-                       bank->sectors[x].offset       = x * (pPrivate->sector_size);
-                       // mark as unknown
-                       bank->sectors[x].is_erased    = -1;
-                       bank->sectors[x].is_protected = -1;
-               }
-       }
-
-       pPrivate->probed = 1;
-
-       r = sam3_protect_check(bank);
-       if (r != ERROR_OK) {
-               return r;
-       }
-
-       LOG_DEBUG("Bank = %d, nbanks = %d",
-                         pPrivate->bank_number , pPrivate->pChip->details.n_banks);
-       if ((pPrivate->bank_number + 1) == pPrivate->pChip->details.n_banks) {
-               // read unique id,
-               // it appears to be associated with the *last* flash bank.
-               FLASHD_ReadUniqueID(pPrivate);
-       }
-
-       return r;
-}
-
-static int
-sam3_probe(struct flash_bank *bank)
-{
-       return _sam3_probe(bank, 1);
-}
-
-static int
-sam3_auto_probe(struct flash_bank *bank)
-{
-       return _sam3_probe(bank, 0);
-}
-
-
-
-static int
-sam3_erase(struct flash_bank *bank, int first, int last)
-{
-       struct sam3_bank_private *pPrivate;
-       int r;
-
-       LOG_DEBUG("Here");
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       r = sam3_auto_probe(bank);
-       if (r != ERROR_OK) {
-               LOG_DEBUG("Here,r=%d",r);
-               return r;
-       }
-
-       pPrivate = get_sam3_bank_private(bank);
-       if (!(pPrivate->probed)) {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if ((first == 0) && ((last + 1)== ((int)(pPrivate->nsectors)))) {
-               // whole chip
-               LOG_DEBUG("Here");
-               return FLASHD_EraseEntireBank(pPrivate);
-       }
-       LOG_INFO("sam3 auto-erases while programing (request ignored)");
-       return ERROR_OK;
-}
-
-static int
-sam3_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       struct sam3_bank_private *pPrivate;
-       int r;
-
-       LOG_DEBUG("Here");
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       pPrivate = get_sam3_bank_private(bank);
-       if (!(pPrivate->probed)) {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if (set) {
-               r = FLASHD_Lock(pPrivate, (unsigned)(first), (unsigned)(last));
-       } else {
-               r = FLASHD_Unlock(pPrivate, (unsigned)(first), (unsigned)(last));
-       }
-       LOG_DEBUG("End: r=%d",r);
-
-       return r;
-
-}
-
-
-static int
-sam3_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-       buf[ 0 ] = 0;
-       return ERROR_OK;
-}
-
-static int
-sam3_page_read(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf)
-{
-       uint32_t adr;
-       int r;
-
-       adr = pagenum * pPrivate->page_size;
-       adr += adr + pPrivate->base_address;
-
-       r = target_read_memory(pPrivate->pChip->target,
-                                                       adr,
-                                                       4, /* THIS*MUST*BE* in 32bit values */
-                                                       pPrivate->page_size / 4,
-                                                       buf);
-       if (r != ERROR_OK) {
-               LOG_ERROR("SAM3: Flash program failed to read page phys address: 0x%08x", (unsigned int)(adr));
-       }
-       return r;
-}
-
-// The code below is basically this:
-// compiled with
-// arm-none-eabi-gcc -mthumb -mcpu = cortex-m3 -O9 -S ./foobar.c -o foobar.s
-//
-// Only the *CPU* can write to the flash buffer.
-// the DAP cannot... so - we download this 28byte thing
-// Run the algorithm - (below)
-// to program the device
-//
-// ========================================
-// #include <stdint.h>
-//
-// struct foo {
-//   uint32_t *dst;
-//   const uint32_t *src;
-//   int   n;
-//   volatile uint32_t *base;
-//   uint32_t   cmd;
-// };
-//
-//
-// uint32_t sam3_function(struct foo *p)
-// {
-//   volatile uint32_t *v;
-//   uint32_t *d;
-//   const uint32_t *s;
-//   int   n;
-//   uint32_t r;
-//
-//   d = p->dst;
-//   s = p->src;
-//   n = p->n;
-//
-//   do {
-//     *d++ = *s++;
-//   } while (--n)
-//     ;
-//
-//   v = p->base;
-//
-//   v[ 1 ] = p->cmd;
-//   do {
-//     r = v[8/4];
-//   } while (!(r&1))
-//     ;
-//   return r;
-// }
-// ========================================
-
-
-
-static const uint8_t
-sam3_page_write_opcodes[] = {
-       //  24 0000 0446                mov     r4, r0
-       0x04,0x46,
-       //  25 0002 6168                ldr     r1, [r4, #4]
-       0x61,0x68,
-       //  26 0004 0068                ldr     r0, [r0, #0]
-       0x00,0x68,
-       //  27 0006 A268                ldr     r2, [r4, #8]
-       0xa2,0x68,
-       //  28                          @ lr needed for prologue
-       //  29                  .L2:
-       //  30 0008 51F8043B            ldr     r3, [r1], #4
-       0x51,0xf8,0x04,0x3b,
-       //  31 000c 12F1FF32            adds    r2, r2, #-1
-       0x12,0xf1,0xff,0x32,
-       //  32 0010 40F8043B            str     r3, [r0], #4
-       0x40,0xf8,0x04,0x3b,
-       //  33 0014 F8D1                bne     .L2
-       0xf8,0xd1,
-       //  34 0016 E268                ldr     r2, [r4, #12]
-       0xe2,0x68,
-       //  35 0018 2369                ldr     r3, [r4, #16]
-       0x23,0x69,
-       //  36 001a 5360                str     r3, [r2, #4]
-       0x53,0x60,
-       //  37 001c 0832                adds    r2, r2, #8
-       0x08,0x32,
-       //  38                  .L4:
-       //  39 001e 1068                ldr     r0, [r2, #0]
-       0x10,0x68,
-       //  40 0020 10F0010F            tst     r0, #1
-       0x10,0xf0,0x01,0x0f,
-       //  41 0024 FBD0                beq     .L4
-       0xfb,0xd0,
-       //  42                  .done:
-       //  43 0026 FEE7                b       .done
-       0xfe,0xe7
-};
-
-
-static int
-sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf)
-{
-       uint32_t adr;
-       uint32_t status;
-       int r;
-
-       adr = pagenum * pPrivate->page_size;
-       adr += (adr + pPrivate->base_address);
-
-       LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr));
-       r = target_write_memory(pPrivate->pChip->target,
-                                                        adr,
-                                                        4, /* THIS*MUST*BE* in 32bit values */
-                                                        pPrivate->page_size / 4,
-                                                        buf);
-       if (r != ERROR_OK) {
-               LOG_ERROR("SAM3: Failed to write (buffer) page at phys address 0x%08x", (unsigned int)(adr));
-               return r;
-       }
-
-       r = EFC_PerformCommand(pPrivate,
-                                                       // send Erase & Write Page
-                                                       AT91C_EFC_FCMD_EWP,
-                                                       pagenum,
-                                                       &status);
-
-       if (r != ERROR_OK) {
-               LOG_ERROR("SAM3: Error performing Erase & Write page @ phys address 0x%08x", (unsigned int)(adr));
-       }
-       if (status & (1 << 2)) {
-               LOG_ERROR("SAM3: Page @ Phys address 0x%08x is locked", (unsigned int)(adr));
-               return ERROR_FAIL;
-       }
-       if (status & (1 << 1)) {
-               LOG_ERROR("SAM3: Flash Command error @phys address 0x%08x", (unsigned int)(adr));
-               return ERROR_FAIL;
-       }
-       return ERROR_OK;
-}
-
-
-
-
-
-static int
-sam3_write(struct flash_bank *bank,
-                  uint8_t *buffer,
-                  uint32_t offset,
-                  uint32_t count)
-{
-       int n;
-       unsigned page_cur;
-       unsigned page_end;
-       int r;
-       unsigned page_offset;
-       struct sam3_bank_private *pPrivate;
-       uint8_t *pagebuffer;
-
-       // incase we bail further below, set this to null
-       pagebuffer = NULL;
-
-       // ignore dumb requests
-       if (count == 0) {
-               r = ERROR_OK;
-               goto done;
-       }
-
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               r = ERROR_TARGET_NOT_HALTED;
-               goto done;
-       }
-
-       pPrivate = get_sam3_bank_private(bank);
-       if (!(pPrivate->probed)) {
-               r = ERROR_FLASH_BANK_NOT_PROBED;
-               goto done;
-       }
-
-
-       if ((offset + count) > pPrivate->size_bytes) {
-               LOG_ERROR("Flash write error - past end of bank");
-               LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x",
-                                 (unsigned int)(offset),
-                                 (unsigned int)(count),
-                                 (unsigned int)(pPrivate->size_bytes));
-               r = ERROR_FAIL;
-               goto done;
-       }
-
-       pagebuffer = malloc(pPrivate->page_size);
-       if( !pagebuffer ){
-               LOG_ERROR("No memory for %d Byte page buffer", (int)(pPrivate->page_size));
-               r = ERROR_FAIL;
-               goto done;
-       }
-
-       // what page do we start & end in?
-       page_cur = offset / pPrivate->page_size;
-       page_end = (offset + count - 1) / pPrivate->page_size;
-
-       LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count));
-       LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end));
-
-       // Special case: all one page
-       //
-       // Otherwise:
-       //    (1) non-aligned start
-       //    (2) body pages
-       //    (3) non-aligned end.
-
-       // Handle special case - all one page.
-       if (page_cur == page_end) {
-               LOG_DEBUG("Special case, all in one page");
-               r = sam3_page_read(pPrivate, page_cur, pagebuffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-
-               page_offset = (offset & (pPrivate->page_size-1));
-               memcpy(pagebuffer + page_offset,
-                               buffer,
-                               count);
-
-               r = sam3_page_write(pPrivate, page_cur, pagebuffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-               r = ERROR_OK;
-               goto done;
-       }
-
-       // non-aligned start
-       page_offset = offset & (pPrivate->page_size - 1);
-       if (page_offset) {
-               LOG_DEBUG("Not-Aligned start");
-               // read the partial
-               r = sam3_page_read(pPrivate, page_cur, pagebuffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-
-               // over-write with new data
-               n = (pPrivate->page_size - page_offset);
-               memcpy(pagebuffer + page_offset,
-                               buffer,
-                               n);
-
-               r = sam3_page_write(pPrivate, page_cur, pagebuffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-
-               count  -= n;
-               offset += n;
-               buffer += n;
-               page_cur++;
-       }
-
-       // intermediate large pages
-       // also - the final *terminal*
-       // if that terminal page is a full page
-       LOG_DEBUG("Full Page Loop: cur=%d, end=%d, count = 0x%08x",
-                         (int)page_cur, (int)page_end, (unsigned int)(count));
-
-       while ((page_cur < page_end) &&
-                  (count >= pPrivate->page_size)) {
-               r = sam3_page_write(pPrivate, page_cur, buffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-               count    -= pPrivate->page_size;
-               buffer   += pPrivate->page_size;
-               page_cur += 1;
-       }
-
-       // terminal partial page?
-       if (count) {
-               LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count));
-               // we have a partial page
-               r = sam3_page_read(pPrivate, page_cur, pagebuffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-               // data goes at start
-               memcpy(pagebuffer, buffer, count);
-               r = sam3_page_write(pPrivate, page_cur, pagebuffer);
-               if (r != ERROR_OK) {
-                       goto done;
-               }
-               buffer += count;
-               count  -= count;
-       }
-       LOG_DEBUG("Done!");
-       r = ERROR_OK;
- done:
-       if( pagebuffer ){
-               free(pagebuffer);
-       }
-       return r;
-}
-
-COMMAND_HANDLER(sam3_handle_info_command)
-{
-       struct sam3_chip *pChip;
-       void *vp;
-       const char *cp;
-       unsigned x;
-       int r;
-
-       pChip = get_current_sam3(CMD_CTX);
-       if (!pChip) {
-               return ERROR_OK;
-       }
-
-       r = 0;
-
-       // bank0 must exist before we can do anything
-       if (pChip->details.bank[0].pBank == NULL) {
-               x = 0;
-       need_define:
-               command_print(CMD_CTX,
-                                          "Please define bank %d via command: flash bank %s ... ",
-                                          x,
-                                          at91sam3_flash.name);
-               return ERROR_FAIL;
-       }
-
-       // if bank 0 is not probed, then probe it
-       if (!(pChip->details.bank[0].probed)) {
-               r = sam3_auto_probe(pChip->details.bank[0].pBank);
-               if (r != ERROR_OK) {
-                       return ERROR_FAIL;
-               }
-       }
-       // above garentees the "chip details" structure is valid
-       // and thus, bank private areas are valid
-       // and we have a SAM3 chip, what a concept!
-
-
-       // auto-probe other banks, 0 done above
-    for (x = 1 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
-               // skip banks not present
-               if (!(pChip->details.bank[x].present)) {
-                       continue;
-               }
-
-               if (pChip->details.bank[x].pBank == NULL) {
-                       goto need_define;
-               }
-
-               if (pChip->details.bank[x].probed) {
-                       continue;
-               }
-
-               r = sam3_auto_probe(pChip->details.bank[x].pBank);
-               if (r != ERROR_OK) {
-                       return r;
-               }
-       }
-
-
-       r = sam3_GetInfo(pChip);
-       if (r != ERROR_OK) {
-               LOG_DEBUG("Sam3Info, Failed %d\n",r);
-               return r;
-       }
-
-
-       // print results
-       cp = membuf_strtok(pChip->mbuf, "\n", &vp);
-       while (cp) {
-               command_print(CMD_CTX,"%s", cp);
-               cp = membuf_strtok(NULL, "\n", &vp);
-       }
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(sam3_handle_gpnvm_command)
-{
-       unsigned x,v;
-       int r,who;
-       struct sam3_chip *pChip;
-
-       pChip = get_current_sam3(CMD_CTX);
-       if (!pChip) {
-               return ERROR_OK;
-       }
-
-       if (pChip->target->state != TARGET_HALTED) {
-               LOG_ERROR("sam3 - target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-
-       if (pChip->details.bank[0].pBank == NULL) {
-               command_print(CMD_CTX, "Bank0 must be defined first via: flash bank %s ...",
-                                          at91sam3_flash.name);
-               return ERROR_FAIL;
-       }
-       if (!pChip->details.bank[0].probed) {
-               r = sam3_auto_probe(pChip->details.bank[0].pBank);
-               if (r != ERROR_OK) {
-                       return r;
-               }
-       }
-
-
-       switch (CMD_ARGC) {
-       default:
-               command_print(CMD_CTX,"Too many parameters\n");
-               return ERROR_COMMAND_SYNTAX_ERROR;
-               break;
-       case 0:
-               who = -1;
-               goto showall;
-               break;
-       case 1:
-               who = -1;
-               break;
-       case 2:
-               if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) {
-                       who = -1;
-               } else {
-                       uint32_t v32;
-                       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32);
-                       who = v32;
-               }
-               break;
-       }
-
-       if (0 == strcmp("show", CMD_ARGV[0])) {
-               if (who == -1) {
-               showall:
-                       r = ERROR_OK;
-                       for (x = 0 ; x < pChip->details.n_gpnvms ; x++) {
-                               r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v);
-                               if (r != ERROR_OK) {
-                                       break;
-                               }
-                               command_print(CMD_CTX, "sam3-gpnvm%u: %u", x, v);
-                       }
-                       return r;
-               }
-               if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
-                       r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
-                       command_print(CMD_CTX, "sam3-gpnvm%u: %u", who, v);
-                       return r;
-               } else {
-                       command_print(CMD_CTX, "sam3-gpnvm invalid GPNVM: %u", who);
-                       return ERROR_COMMAND_SYNTAX_ERROR;
-               }
-       }
-
-       if (who == -1) {
-               command_print(CMD_CTX, "Missing GPNVM number");
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       if (0 == strcmp("set", CMD_ARGV[0])) {
-               r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who);
-       } else if ((0 == strcmp("clr", CMD_ARGV[0])) ||
-                          (0 == strcmp("clear", CMD_ARGV[0]))) { // quietly accept both
-               r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who);
-       } else {
-               command_print(CMD_CTX, "Unkown command: %s", CMD_ARGV[0]);
-               r = ERROR_COMMAND_SYNTAX_ERROR;
-       }
-       return r;
-}
-
-COMMAND_HANDLER(sam3_handle_slowclk_command)
-{
-       struct sam3_chip *pChip;
-
-       pChip = get_current_sam3(CMD_CTX);
-       if (!pChip) {
-               return ERROR_OK;
-       }
-
-
-       switch (CMD_ARGC) {
-       case 0:
-               // show
-               break;
-       case 1:
-       {
-               // set
-               uint32_t v;
-               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v);
-               if (v > 200000) {
-                       // absurd slow clock of 200Khz?
-                       command_print(CMD_CTX,"Absurd/illegal slow clock freq: %d\n", (int)(v));
-                       return ERROR_COMMAND_SYNTAX_ERROR;
-               }
-               pChip->cfg.slow_freq = v;
-               break;
-       }
-       default:
-               // error
-               command_print(CMD_CTX,"Too many parameters");
-               return ERROR_COMMAND_SYNTAX_ERROR;
-               break;
-       }
-       command_print(CMD_CTX, "Slowclk freq: %d.%03dkhz",
-                                  (int)(pChip->cfg.slow_freq/ 1000),
-                                  (int)(pChip->cfg.slow_freq% 1000));
-       return ERROR_OK;
-}
-
-static const struct command_registration at91sam3_exec_command_handlers[] = {
-       {
-               .name = "gpnvm",
-               .handler = &sam3_handle_gpnvm_command,
-               .mode = COMMAND_EXEC,
-               .usage = "[(set|clear) [<bit_id>]]",
-               .help = "Without arguments, shows the gpnvm register; "
-                       "otherwise, sets or clear the specified bit.",
-       },
-       {
-               .name = "info",
-               .handler = &sam3_handle_info_command,
-               .mode = COMMAND_EXEC,
-               .help = "print information about the current sam3 chip",
-       },
-       {
-               .name = "slowclk",
-               .handler = &sam3_handle_slowclk_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<value>",
-               .help = "set the slowclock frequency (default 32768hz)",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration at91sam3_command_handlers[] = {
-       {
-               .name = "at91sam3",
-               .mode = COMMAND_ANY,
-               .help = "at91sam3 flash command group",
-               .chain = at91sam3_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver at91sam3_flash = {
-               .name = "at91sam3",
-               .commands = at91sam3_command_handlers,
-               .flash_bank_command = &sam3_flash_bank_command,
-               .erase = &sam3_erase,
-               .protect = &sam3_protect,
-               .write = &sam3_write,
-               .probe = &sam3_probe,
-               .auto_probe = &sam3_auto_probe,
-               .erase_check = &sam3_erase_check,
-               .protect_check = &sam3_protect_check,
-               .info = &sam3_info,
-       };
diff --git a/src/flash/at91sam3.h b/src/flash/at91sam3.h
deleted file mode 100644 (file)
index 4fa7f46..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2009 by Duane Ellis                                     *
- *   openocd@duaneellis.com                                                *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-
-
-// nothing to do here other then export this.
-extern struct flash_driver at91sam3_flash;
diff --git a/src/flash/at91sam7.c b/src/flash/at91sam7.c
deleted file mode 100644 (file)
index f9b87ba..0000000
+++ /dev/null
@@ -1,1213 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2006 by Magnus Lundin                                   *
- *   lundin@mlu.mine.nu                                                    *
- *                                                                         *
- *   Copyright (C) 2008 by Gheorghe Guran (atlas)                          *
- *                                                                         *
- *   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.             *
-****************************************************************************/
-
-/***************************************************************************
-*
-* New flash setup command:
-*
-* flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_id>
-*      [<chip_type> <banks>
-*       <sectors_per_bank> <pages_per_sector>
-*       <page_size> <num_nvmbits>
-*       <ext_freq_khz>]
-*
-*   <ext_freq_khz> - MUST be used if clock is from external source,
-*                    CAN be used if main oscillator frequency is known (recommended)
-* Examples:
-* ==== RECOMMENDED (covers clock speed) ============
-*  flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 25000
-*                      (if auto-detect fails; provides clock spec)
-*  flash bank at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 25000
-*                      (auto-detect everything except the clock)
-* ==== NOT RECOMMENDED !!! (clock speed is not configured) ====
-*  flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 0
-*                      (if auto-detect fails)
-*  flash bank at91sam7 0 0 0 0 $_TARGETNAME
-*                      (old style, auto-detect everything)
-****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "at91sam7.h"
-#include "binarybuffer.h"
-
-static int at91sam7_protect_check(struct flash_bank *bank);
-static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
-
-static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
-static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
-static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
-static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen);
-
-static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
-static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
-static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
-
-static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
-
-#if 0
-static long SRAMSIZ[16] = {
-       -1,
-       0x0400,         /*  1K */
-       0x0800,         /*  2K */
-       -1,
-       0x1c000,        /* 112K */
-       0x1000,         /*   4K */
-       0x14000,        /*  80K */
-       0x28000,        /* 160K */
-       0x2000,         /*   8K */
-       0x4000,         /*  16K */
-       0x8000,         /*  32K */
-       0x10000,        /*  64K */
-       0x20000,        /* 128K */
-       0x40000,        /* 256K */
-       0x18000,        /*  96K */
-       0x80000,        /* 512K */
-};
-#endif
-
-
-static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
-{
-       uint32_t fsr;
-       target_read_u32(target, MC_FSR[bank_number], &fsr);
-
-       return fsr;
-}
-
-/* Read clock configuration and set at91sam7_info->mck_freq */
-static void at91sam7_read_clock_info(struct flash_bank *bank)
-{
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t mckr, mcfr, pllr, mor;
-       unsigned long tmp = 0, mainfreq;
-
-       /* Read Clock Generator Main Oscillator Register */
-       target_read_u32(target, CKGR_MOR, &mor);
-       /* Read Clock Generator Main Clock Frequency Register */
-       target_read_u32(target, CKGR_MCFR, &mcfr);
-       /* Read Master Clock Register*/
-       target_read_u32(target, PMC_MCKR, &mckr);
-       /* Read Clock Generator PLL Register  */
-       target_read_u32(target, CKGR_PLLR, &pllr);
-
-       at91sam7_info->mck_valid = 0;
-       at91sam7_info->mck_freq = 0;
-       switch (mckr & PMC_MCKR_CSS)
-       {
-               case 0:                 /* Slow Clock */
-                       at91sam7_info->mck_valid = 1;
-                       tmp = RC_FREQ;
-                       break;
-
-               case 1:                 /* Main Clock */
-                       if ((mcfr & CKGR_MCFR_MAINRDY) &&
-                               (at91sam7_info->ext_freq == 0))
-                       {
-                               at91sam7_info->mck_valid = 1;
-                               tmp = RC_FREQ / 16ul * (mcfr & 0xffff);
-                       }
-                       else if (at91sam7_info->ext_freq != 0)
-                       {
-                               at91sam7_info->mck_valid = 1;
-                               tmp = at91sam7_info->ext_freq;
-                       }
-                       break;
-
-               case 2:                 /* Reserved */
-                       break;
-
-               case 3:                 /* PLL Clock */
-                       if ((mcfr & CKGR_MCFR_MAINRDY) &&
-                               (at91sam7_info->ext_freq == 0))
-                       {
-                               target_read_u32(target, CKGR_PLLR, &pllr);
-                               if (!(pllr & CKGR_PLLR_DIV))
-                                       break; /* 0 Hz */
-                               at91sam7_info->mck_valid = 1;
-                               mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
-                               /* Integer arithmetic should have sufficient precision
-                                * as long as PLL is properly configured. */
-                               tmp = mainfreq / (pllr & CKGR_PLLR_DIV)*
-                                       (((pllr & CKGR_PLLR_MUL) >> 16) + 1);
-                       }
-                       else if ((at91sam7_info->ext_freq != 0) &&
-                               ((pllr&CKGR_PLLR_DIV) != 0))
-                       {
-                               at91sam7_info->mck_valid = 1;
-                               tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)*
-                                       (((pllr & CKGR_PLLR_MUL) >> 16) + 1);
-                       }
-                       break;
-       }
-
-       /* Prescaler adjust */
-       if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0))
-       {
-               at91sam7_info->mck_valid = 0;
-               at91sam7_info->mck_freq = 0;
-       }
-       else if (((mckr & PMC_MCKR_PRES) >> 2) != 0)
-               at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
-       else
-               at91sam7_info->mck_freq = tmp;
-}
-
-/* Setup the timimg registers for nvbits or normal flash */
-static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
-{
-       uint32_t fmr, fmcn = 0, fws = 0;
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       if (mode && (mode != at91sam7_info->flashmode))
-       {
-               /* Always round up (ceil) */
-               if (mode == FMR_TIMING_NVBITS)
-               {
-                       if (at91sam7_info->cidr_arch == 0x60)
-                       {
-                               /* AT91SAM7A3 uses master clocks in 100 ns */
-                               fmcn = (at91sam7_info->mck_freq/10000000ul) + 1;
-                       }
-                       else
-                       {
-                               /* master clocks in 1uS for ARCH 0x7 types */
-                               fmcn = (at91sam7_info->mck_freq/1000000ul) + 1;
-                       }
-               }
-               else if (mode == FMR_TIMING_FLASH)
-               {
-                       /* main clocks in 1.5uS */
-                       fmcn = (at91sam7_info->mck_freq/1000000ul)+
-                               (at91sam7_info->mck_freq/2000000ul) + 1;
-               }
-
-               /* hard overclocking */
-               if (fmcn > 0xFF)
-                       fmcn = 0xFF;
-
-               /* Only allow fmcn = 0 if clock period is > 30 us = 33kHz. */
-               if (at91sam7_info->mck_freq <= 33333ul)
-                       fmcn = 0;
-               /* Only allow fws = 0 if clock frequency is < 30 MHz. */
-               if (at91sam7_info->mck_freq > 30000000ul)
-                       fws = 1;
-
-               LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn));
-               fmr = fmcn << 16 | fws << 8;
-               target_write_u32(target, MC_FMR[bank->bank_number], fmr);
-       }
-
-       at91sam7_info->flashmode = mode;
-}
-
-static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
-{
-       uint32_t status;
-
-       while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0))
-       {
-               LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status);
-               alive_sleep(1);
-       }
-
-       LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status);
-
-       if (status & 0x0C)
-       {
-               LOG_ERROR("status register: 0x%" PRIx32 "", status);
-               if (status & 0x4)
-                       LOG_ERROR("Lock Error Bit Detected, Operation Abort");
-               if (status & 0x8)
-                       LOG_ERROR("Invalid command and/or bad keyword, Operation Abort");
-               if (status & 0x10)
-                       LOG_ERROR("Security Bit Set, Operation Abort");
-       }
-
-       return status;
-}
-
-/* Send one command to the AT91SAM flash controller */
-static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen)
-{
-       uint32_t fcr;
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
-       target_write_u32(target, MC_FCR[bank->bank_number], fcr);
-       LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen);
-
-       if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB)))
-       {
-               /* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
-               if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               return ERROR_OK;
-       }
-
-       if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C)
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-/* Read device id register, main clock frequency register and fill in driver info structure */
-static int at91sam7_read_part_info(struct flash_bank *bank)
-{
-       struct flash_bank *t_bank = bank;
-       struct at91sam7_flash_bank *at91sam7_info;
-       struct target *target = t_bank->target;
-
-       uint16_t bnk, sec;
-       uint16_t arch;
-       uint32_t cidr;
-       uint8_t banks_num = 0;
-       uint16_t num_nvmbits = 0;
-       uint16_t sectors_num = 0;
-       uint16_t pages_per_sector = 0;
-       uint16_t page_size = 0;
-       uint32_t ext_freq;
-       uint32_t bank_size;
-       uint32_t base_address = 0;
-       char *target_name = "Unknown";
-
-       at91sam7_info = t_bank->driver_priv;
-
-       if (at91sam7_info->cidr != 0)
-       {
-               /* flash already configured, update clock and check for protected sectors */
-               struct flash_bank *fb = bank;
-               t_bank = fb;
-
-               while (t_bank)
-               {
-                       /* re-calculate master clock frequency */
-                       at91sam7_read_clock_info(t_bank);
-
-                       /* no timming */
-                       at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);
-
-                       /* check protect state */
-                       at91sam7_protect_check(t_bank);
-
-                       t_bank = fb->next;
-                       fb = t_bank;
-               }
-
-               return ERROR_OK;
-       }
-
-       /* Read and parse chip identification register */
-       target_read_u32(target, DBGU_CIDR, &cidr);
-       if (cidr == 0)
-       {
-               LOG_WARNING("Cannot identify target as an AT91SAM");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (at91sam7_info->flash_autodetection == 0)
-       {
-               /* banks and sectors are already created, based on data from input file */
-               struct flash_bank *fb = bank;
-               t_bank = fb;
-               while (t_bank)
-               {
-                       at91sam7_info = t_bank->driver_priv;
-
-                       at91sam7_info->cidr = cidr;
-                       at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
-                       at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
-                       at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
-                       at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
-                       at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
-                       at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
-                       at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
-                       at91sam7_info->cidr_version = cidr&0x001F;
-
-                       /* calculate master clock frequency */
-                       at91sam7_read_clock_info(t_bank);
-
-                       /* no timming */
-                       at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);
-
-                       /* check protect state */
-                       at91sam7_protect_check(t_bank);
-
-                       t_bank = fb->next;
-                       fb = t_bank;
-               }
-
-               return ERROR_OK;
-       }
-
-       arch = (cidr >> 20)&0x00FF;
-
-       /* check flash size */
-       switch ((cidr >> 8)&0x000F)
-       {
-               case FLASH_SIZE_8KB:
-                       break;
-
-               case FLASH_SIZE_16KB:
-                       banks_num = 1;
-                       sectors_num = 8;
-                       pages_per_sector = 32;
-                       page_size  = 64;
-                       base_address = 0x00100000;
-                       if (arch == 0x70)
-                       {
-                               num_nvmbits = 2;
-                               target_name = "AT91SAM7S161/16";
-                       }
-                       break;
-
-               case FLASH_SIZE_32KB:
-                       banks_num = 1;
-                       sectors_num = 8;
-                       pages_per_sector = 32;
-                       page_size  = 128;
-                       base_address = 0x00100000;
-                       if (arch == 0x70)
-                       {
-                               num_nvmbits = 2;
-                               target_name = "AT91SAM7S321/32";
-                       }
-                       if (arch == 0x72)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7SE32";
-                       }
-                       break;
-
-               case FLASH_SIZE_64KB:
-                       banks_num = 1;
-                       sectors_num = 16;
-                       pages_per_sector = 32;
-                       page_size  = 128;
-                       base_address = 0x00100000;
-                       if (arch == 0x70)
-                       {
-                               num_nvmbits = 2;
-                               target_name = "AT91SAM7S64";
-                       }
-                       break;
-
-               case FLASH_SIZE_128KB:
-                       banks_num = 1;
-                       sectors_num = 8;
-                       pages_per_sector = 64;
-                       page_size  = 256;
-                       base_address = 0x00100000;
-                       if (arch == 0x70)
-                       {
-                               num_nvmbits = 2;
-                               target_name = "AT91SAM7S128";
-                       }
-                       if (arch == 0x71)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7XC128";
-                       }
-                       if (arch == 0x72)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7SE128";
-                       }
-                       if (arch == 0x75)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7X128";
-                       }
-                       break;
-
-               case FLASH_SIZE_256KB:
-                       banks_num = 1;
-                       sectors_num = 16;
-                       pages_per_sector = 64;
-                       page_size  = 256;
-                       base_address = 0x00100000;
-                       if (arch == 0x60)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7A3";
-                       }
-                       if (arch == 0x70)
-                       {
-                               num_nvmbits = 2;
-                               target_name = "AT91SAM7S256";
-                       }
-                       if (arch == 0x71)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7XC256";
-                       }
-                       if (arch == 0x72)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7SE256";
-                       }
-                       if (arch == 0x75)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7X256";
-                       }
-                       break;
-
-               case FLASH_SIZE_512KB:
-                       banks_num = 2;
-                       sectors_num = 16;
-                       pages_per_sector = 64;
-                       page_size  = 256;
-                       base_address = 0x00100000;
-                       if (arch == 0x70)
-                       {
-                               num_nvmbits = 2;
-                               target_name = "AT91SAM7S512";
-                       }
-                       if (arch == 0x71)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7XC512";
-                       }
-                       if (arch == 0x72)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7SE512";
-                       }
-                       if (arch == 0x75)
-                       {
-                               num_nvmbits = 3;
-                               target_name = "AT91SAM7X512";
-                       }
-                       break;
-
-               case FLASH_SIZE_1024KB:
-                       break;
-
-               case FLASH_SIZE_2048KB:
-                       break;
-       }
-
-       if (strcmp(target_name, "Unknown") == 0)
-       {
-               LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       ext_freq = at91sam7_info->ext_freq;
-
-       /* calculate bank size  */
-       bank_size = sectors_num * pages_per_sector * page_size;
-
-       for (bnk = 0; bnk < banks_num; bnk++)
-       {
-               if (bnk > 0)
-               {
-                       /* create a new flash bank element */
-                       struct flash_bank *fb = malloc(sizeof(struct flash_bank));
-                       fb->target = target;
-                       fb->driver = bank->driver;
-                       fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
-                       fb->next = NULL;
-
-                       /* link created bank in 'flash_banks' list and redirect t_bank */
-                       t_bank->next = fb;
-                       t_bank = fb;
-               }
-
-               t_bank->bank_number = bnk;
-               t_bank->base = base_address + bnk * bank_size;
-               t_bank->size = bank_size;
-               t_bank->chip_width = 0;
-               t_bank->bus_width = 4;
-               t_bank->num_sectors = sectors_num;
-
-               /* allocate sectors */
-               t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
-               for (sec = 0; sec < sectors_num; sec++)
-               {
-                       t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
-                       t_bank->sectors[sec].size = pages_per_sector * page_size;
-                       t_bank->sectors[sec].is_erased = -1;
-                       t_bank->sectors[sec].is_protected = -1;
-               }
-
-               at91sam7_info = t_bank->driver_priv;
-
-               at91sam7_info->cidr = cidr;
-               at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
-               at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
-               at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
-               at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
-               at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
-               at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
-               at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
-               at91sam7_info->cidr_version = cidr&0x001F;
-
-               at91sam7_info->target_name  = target_name;
-               at91sam7_info->flashmode = 0;
-               at91sam7_info->ext_freq = ext_freq;
-               at91sam7_info->num_nvmbits = num_nvmbits;
-               at91sam7_info->num_nvmbits_on = 0;
-               at91sam7_info->pagesize = page_size;
-               at91sam7_info->pages_per_sector = pages_per_sector;
-
-               /* calculate master clock frequency */
-               at91sam7_read_clock_info(t_bank);
-
-               /* no timming */
-               at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);
-
-               /* check protect state */
-               at91sam7_protect_check(t_bank);
-       }
-
-       LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch);
-
-       return ERROR_OK;
-}
-
-static int at91sam7_erase_check(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint16_t retval;
-       uint32_t blank;
-       uint16_t fast_check;
-       uint8_t *buffer;
-       uint16_t nSector;
-       uint16_t nByte;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* Configure the flash controller timing */
-       at91sam7_read_clock_info(bank);
-       at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
-
-       fast_check = 1;
-       for (nSector = 0; nSector < bank->num_sectors; nSector++)
-       {
-               retval = target_blank_check_memory(target, bank->base + bank->sectors[nSector].offset,
-                       bank->sectors[nSector].size, &blank);
-               if (retval != ERROR_OK)
-               {
-                       fast_check = 0;
-                       break;
-               }
-               if (blank == 0xFF)
-                       bank->sectors[nSector].is_erased = 1;
-               else
-                       bank->sectors[nSector].is_erased = 0;
-       }
-
-       if (fast_check)
-       {
-               return ERROR_OK;
-       }
-
-       LOG_USER("Running slow fallback erase check - add working memory");
-
-       buffer = malloc(bank->sectors[0].size);
-       for (nSector = 0; nSector < bank->num_sectors; nSector++)
-       {
-               bank->sectors[nSector].is_erased = 1;
-               retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
-                       bank->sectors[nSector].size/4, buffer);
-               if (retval != ERROR_OK)
-                       return retval;
-
-               for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++)
-               {
-                       if (buffer[nByte] != 0xFF)
-                       {
-                               bank->sectors[nSector].is_erased = 0;
-                               break;
-                       }
-               }
-       }
-       free(buffer);
-
-       return ERROR_OK;
-}
-
-static int at91sam7_protect_check(struct flash_bank *bank)
-{
-       uint8_t lock_pos, gpnvm_pos;
-       uint32_t status;
-
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-
-       if (at91sam7_info->cidr == 0)
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       status = at91sam7_get_flash_status(bank->target, bank->bank_number);
-       at91sam7_info->lockbits = (status >> 16);
-
-       at91sam7_info->num_lockbits_on = 0;
-       for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++)
-       {
-               if (((status >> (16 + lock_pos))&(0x0001)) == 1)
-               {
-                       at91sam7_info->num_lockbits_on++;
-                       bank->sectors[lock_pos].is_protected = 1;
-               }
-               else
-                       bank->sectors[lock_pos].is_protected = 0;
-       }
-
-       /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
-       status = at91sam7_get_flash_status(bank->target, 0);
-
-       at91sam7_info->securitybit = (status >> 4)&0x01;
-       at91sam7_info->nvmbits = (status >> 8)&0xFF;
-
-       at91sam7_info->num_nvmbits_on = 0;
-       for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++)
-       {
-               if (((status >> (8 + gpnvm_pos))&(0x01)) == 1)
-               {
-                       at91sam7_info->num_nvmbits_on++;
-               }
-       }
-
-       return ERROR_OK;
-}
-
-FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
-{
-       struct flash_bank *t_bank = bank;
-       struct at91sam7_flash_bank *at91sam7_info;
-       struct target *target = t_bank->target;
-
-       uint32_t base_address;
-       uint32_t bank_size;
-       uint32_t ext_freq = 0;
-
-       int chip_width;
-       int bus_width;
-       int banks_num;
-       int num_sectors;
-
-       uint16_t pages_per_sector;
-       uint16_t page_size;
-       uint16_t num_nvmbits;
-
-       char *target_name;
-
-       int bnk, sec;
-
-       at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
-       t_bank->driver_priv = at91sam7_info;
-
-       /* part wasn't probed for info yet */
-       at91sam7_info->cidr = 0;
-       at91sam7_info->flashmode = 0;
-       at91sam7_info->ext_freq = 0;
-       at91sam7_info->flash_autodetection = 0;
-
-       if (CMD_ARGC < 13)
-       {
-               at91sam7_info->flash_autodetection = 1;
-               return ERROR_OK;
-       }
-
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address);
-
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], chip_width);
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], bus_width);
-
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[8], banks_num);
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[9], num_sectors);
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector);
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size);
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits);
-
-       if (CMD_ARGC == 14) {
-               unsigned long freq;
-               COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq);
-               ext_freq = freq * 1000;
-               at91sam7_info->ext_freq = ext_freq;
-       }
-
-       if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
-               (pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0))
-       {
-               at91sam7_info->flash_autodetection = 1;
-               return ERROR_OK;
-       }
-
-       target_name = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
-       strcpy(target_name, CMD_ARGV[7]);
-
-       /* calculate bank size  */
-       bank_size = num_sectors * pages_per_sector * page_size;
-
-       for (bnk = 0; bnk < banks_num; bnk++)
-       {
-               if (bnk > 0)
-               {
-                       /* create a new bank element */
-                       struct flash_bank *fb = malloc(sizeof(struct flash_bank));
-                       fb->target = target;
-                       fb->driver = bank->driver;
-                       fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
-                       fb->next = NULL;
-
-                       /* link created bank in 'flash_banks' list and redirect t_bank */
-                       t_bank->next = fb;
-                       t_bank = fb;
-               }
-
-               t_bank->bank_number = bnk;
-               t_bank->base = base_address + bnk * bank_size;
-               t_bank->size = bank_size;
-               t_bank->chip_width = chip_width;
-               t_bank->bus_width = bus_width;
-               t_bank->num_sectors = num_sectors;
-
-               /* allocate sectors */
-               t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
-               for (sec = 0; sec < num_sectors; sec++)
-               {
-                       t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
-                       t_bank->sectors[sec].size = pages_per_sector * page_size;
-                       t_bank->sectors[sec].is_erased = -1;
-                       t_bank->sectors[sec].is_protected = -1;
-               }
-
-               at91sam7_info = t_bank->driver_priv;
-
-               at91sam7_info->target_name  = target_name;
-               at91sam7_info->flashmode = 0;
-               at91sam7_info->ext_freq  = ext_freq;
-               at91sam7_info->num_nvmbits = num_nvmbits;
-               at91sam7_info->num_nvmbits_on = 0;
-               at91sam7_info->pagesize = page_size;
-               at91sam7_info->pages_per_sector = pages_per_sector;
-       }
-
-       return ERROR_OK;
-}
-
-static int at91sam7_erase(struct flash_bank *bank, int first, int last)
-{
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-       int sec;
-       uint32_t nbytes, pos;
-       uint8_t *buffer;
-       uint8_t erase_all;
-
-       if (at91sam7_info->cidr == 0)
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       erase_all = 0;
-       if ((first == 0) && (last == (bank->num_sectors-1)))
-       {
-               erase_all = 1;
-       }
-
-       /* Configure the flash controller timing */
-       at91sam7_read_clock_info(bank);
-       at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
-
-       if (erase_all)
-       {
-               if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-       }
-       else
-       {
-               /* allocate and clean buffer  */
-               nbytes = (last - first + 1) * bank->sectors[first].size;
-               buffer = malloc(nbytes * sizeof(uint8_t));
-               for (pos = 0; pos < nbytes; pos++)
-               {
-                       buffer[pos] = 0xFF;
-               }
-
-               if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               free(buffer);
-       }
-
-       /* mark erased sectors */
-       for (sec = first; sec <= last; sec++)
-       {
-               bank->sectors[sec].is_erased = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static int at91sam7_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       uint32_t cmd;
-       int sector;
-       uint32_t pagen;
-
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-
-       if (at91sam7_info->cidr == 0)
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* Configure the flash controller timing */
-       at91sam7_read_clock_info(bank);
-       at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
-
-       for (sector = first; sector <= last; sector++)
-       {
-               if (set)
-                       cmd = SLB;
-               else
-                       cmd = CLB;
-
-               /* if we lock a page from one sector then entire sector will be locked, also,
-                * if we unlock a page from a locked sector, entire sector will be unlocked   */
-               pagen = sector * at91sam7_info->pages_per_sector;
-
-               if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-       }
-
-       at91sam7_protect_check(bank);
-
-       return ERROR_OK;
-}
-
-static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       int retval;
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t dst_min_alignment, wcount, bytes_remaining = count;
-       uint32_t first_page, last_page, pagen, buffer_pos;
-
-       if (at91sam7_info->cidr == 0)
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset + count > bank->size)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       dst_min_alignment = at91sam7_info->pagesize;
-
-       if (offset % dst_min_alignment)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, dst_min_alignment);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       if (at91sam7_info->cidr_arch == 0)
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       first_page = offset/dst_min_alignment;
-       last_page = DIV_ROUND_UP(offset + count, dst_min_alignment);
-
-       LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count);
-
-       /* Configure the flash controller timing */
-       at91sam7_read_clock_info(bank);
-       at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
-
-       for (pagen = first_page; pagen < last_page; pagen++)
-       {
-               if (bytes_remaining < dst_min_alignment)
-                       count = bytes_remaining;
-               else
-                       count = dst_min_alignment;
-               bytes_remaining -= count;
-
-               /* Write one block to the PageWriteBuffer */
-               buffer_pos = (pagen-first_page)*dst_min_alignment;
-               wcount = DIV_ROUND_UP(count,4);
-               if ((retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               /* Send Write Page command to Flash Controller */
-               if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               LOG_DEBUG("Write flash bank:%i page number:%" PRIi32 "", bank->bank_number, pagen);
-       }
-
-       return ERROR_OK;
-}
-
-static int at91sam7_probe(struct flash_bank *bank)
-{
-       /* we can't probe on an at91sam7
-        * if this is an at91sam7, it has the configured flash */
-       int retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       retval = at91sam7_read_part_info(bank);
-       if (retval != ERROR_OK)
-               return retval;
-
-       return ERROR_OK;
-}
-
-static int at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       int printed;
-       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
-
-       if (at91sam7_info->cidr == 0)
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       printed = snprintf(buf, buf_size,
-               "\n at91sam7 driver information: Chip is %s\n",
-               at91sam7_info->target_name);
-
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf,
-                          buf_size,
-                          " Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | Flashsize: 0x%8.8" PRIx32 "\n",
-                          at91sam7_info->cidr,
-                          at91sam7_info->cidr_arch,
-                          EPROC[at91sam7_info->cidr_eproc],
-                          at91sam7_info->cidr_version,
-                          bank->size);
-
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size,
-               " Master clock (estimated): %u KHz | External clock: %u KHz\n",
-               (unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000));
-
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size,
-               " Pagesize: %i bytes | Lockbits(%i): %i 0x%4.4x | Pages in lock region: %i \n",
-               at91sam7_info->pagesize, bank->num_sectors, at91sam7_info->num_lockbits_on,
-               at91sam7_info->lockbits, at91sam7_info->pages_per_sector*at91sam7_info->num_lockbits_on);
-
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size,
-               " Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n",
-               at91sam7_info->securitybit, at91sam7_info->num_nvmbits,
-               at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits);
-
-       buf += printed;
-       buf_size -= printed;
-
-       return ERROR_OK;
-}
-
-/*
-* On AT91SAM7S: When the gpnvm bits are set with
-* > at91sam7 gpnvm bitnr set
-* the changes are not visible in the flash controller status register MC_FSR
-* until the processor has been reset.
-* On the Olimex board this requires a power cycle.
-* Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3):
-*   The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes
-*   Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
-*/
-COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
-{
-       struct flash_bank *bank;
-       int bit;
-       uint8_t  flashcmd;
-       uint32_t status;
-       struct at91sam7_flash_bank *at91sam7_info;
-       int retval;
-
-       if (CMD_ARGC != 2)
-       {
-               command_print(CMD_CTX, "at91sam7 gpnvm <bit> <set | clear>");
-               return ERROR_OK;
-       }
-
-       bank = get_flash_bank_by_num_noprobe(0);
-       if (bank ==  NULL)
-       {
-               return ERROR_FLASH_BANK_INVALID;
-       }
-       if (strcmp(bank->driver->name, "at91sam7"))
-       {
-               command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]);
-               return ERROR_FLASH_BANK_INVALID;
-       }
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("target has to be halted to perform flash operation");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (strcmp(CMD_ARGV[1], "set") == 0)
-       {
-               flashcmd = SGPB;
-       }
-       else if (strcmp(CMD_ARGV[1], "clear") == 0)
-       {
-               flashcmd = CGPB;
-       }
-       else
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       at91sam7_info = bank->driver_priv;
-       if (at91sam7_info->cidr == 0)
-       {
-               retval = at91sam7_read_part_info(bank);
-               if (retval != ERROR_OK)
-               {
-                       return retval;
-               }
-       }
-
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit);
-       if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits))
-       {
-               command_print(CMD_CTX, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name);
-               return ERROR_OK;
-       }
-
-       /* Configure the flash controller timing */
-       at91sam7_read_clock_info(bank);
-       at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
-
-       if (at91sam7_flash_command(bank, flashcmd, bit) != ERROR_OK)
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
-       status = at91sam7_get_flash_status(bank->target, 0);
-       LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32 " \n", flashcmd, bit, status);
-
-       /* check protect state */
-       at91sam7_protect_check(bank);
-
-       return ERROR_OK;
-}
-
-static const struct command_registration at91sam7_exec_command_handlers[] = {
-       {
-               .name = "gpnvm",
-               .handler = &at91sam7_handle_gpnvm_command,
-               .mode = COMMAND_EXEC,
-               .usage = "gpnvm <bit> set | clear, "
-                       "set or clear one gpnvm bit",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration at91sam7_command_handlers[] = {
-       {
-               .name = "at91sam7",
-               .mode = COMMAND_ANY,
-               .help = "at91sam7 flash command group",
-               .chain = at91sam7_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver at91sam7_flash = {
-               .name = "at91sam7",
-               .commands = at91sam7_command_handlers,
-               .flash_bank_command = &at91sam7_flash_bank_command,
-               .erase = &at91sam7_erase,
-               .protect = &at91sam7_protect,
-               .write = &at91sam7_write,
-               .probe = &at91sam7_probe,
-               .auto_probe = &at91sam7_probe,
-               .erase_check = &at91sam7_erase_check,
-               .protect_check = &at91sam7_protect_check,
-               .info = &at91sam7_info,
-       };
diff --git a/src/flash/at91sam7.h b/src/flash/at91sam7.h
deleted file mode 100644 (file)
index 4510686..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2006 by Magnus Lundin                                   *
- *   lundin@mlu.mine.nu                                                    *
- *                                                                         *
- *   Copyright (C) 2006 by Gheorghe Guran (atlas)                          *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-
-#ifndef AT91SAM7_H
-#define AT91SAM7_H
-
-#include "flash.h"
-
-struct at91sam7_flash_bank
-{
-       /* chip id register */
-       uint32_t cidr;
-       uint16_t cidr_ext;
-       uint16_t cidr_nvptyp;
-       uint16_t cidr_arch;
-       uint16_t cidr_sramsiz;
-       uint16_t cidr_nvpsiz;
-       uint16_t cidr_nvpsiz2;
-       uint16_t cidr_eproc;
-       uint16_t cidr_version;
-       char *target_name;
-
-       /* flash auto-detection */
-       uint8_t  flash_autodetection;
-
-       /* flash geometry */
-       uint16_t pages_per_sector;
-       uint16_t pagesize;
-       uint16_t pages_in_lockregion;
-
-       /* nv memory bits */
-       uint16_t num_lockbits_on;
-       uint16_t lockbits;
-       uint16_t num_nvmbits;
-       uint16_t num_nvmbits_on;
-       uint16_t nvmbits;
-       uint8_t  securitybit;
-
-       /* 0: not init
-        * 1: fmcn for nvbits (1uS)
-        * 2: fmcn for flash (1.5uS) */
-       uint8_t  flashmode;
-
-       /* main clock status */
-       uint8_t  mck_valid;
-       uint32_t mck_freq;
-
-       /* external clock frequency */
-       uint32_t ext_freq;
-
-};
-
-
-/* AT91SAM7 control registers */
-#define DBGU_CIDR                      0xFFFFF240
-#define CKGR_MCFR                      0xFFFFFC24
-#define CKGR_MOR                       0xFFFFFC20
-#define CKGR_MCFR_MAINRDY      0x10000
-#define CKGR_PLLR                      0xFFFFFC2c
-#define CKGR_PLLR_DIV          0xff
-#define CKGR_PLLR_MUL          0x07ff0000
-#define PMC_MCKR                       0xFFFFFC30
-#define PMC_MCKR_CSS           0x03
-#define PMC_MCKR_PRES          0x1c
-
-/* Flash Controller Commands */
-#define WP             0x01
-#define SLB            0x02
-#define WPL            0x03
-#define CLB            0x04
-#define EA             0x08
-#define SGPB   0x0B
-#define CGPB   0x0D
-#define SSB            0x0F
-
-/* MC_FSR bit definitions */
-#define MC_FSR_FRDY                    1
-#define MC_FSR_EOL                     2
-
-/* AT91SAM7 constants */
-#define RC_FREQ                                32000
-
-/* Flash timing modes */
-#define FMR_TIMING_NONE                0
-#define FMR_TIMING_NVBITS      1
-#define FMR_TIMING_FLASH       2
-
-/* Flash size constants */
-#define FLASH_SIZE_8KB         1
-#define FLASH_SIZE_16KB                2
-#define FLASH_SIZE_32KB                3
-#define FLASH_SIZE_64KB                5
-#define FLASH_SIZE_128KB       7
-#define FLASH_SIZE_256KB       9
-#define FLASH_SIZE_512KB       10
-#define FLASH_SIZE_1024KB      12
-#define FLASH_SIZE_2048KB      14
-
-#endif /* AT91SAM7_H */
diff --git a/src/flash/avrf.c b/src/flash/avrf.c
deleted file mode 100644 (file)
index 687dd4b..0000000
+++ /dev/null
@@ -1,483 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2009 by Simon Qian                                      *
- *   SimonQian@SimonQian.com                                               *
- *                                                                         *
- *   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 "avrf.h"
-#include "avrt.h"
-#include "flash.h"
-
-
-/* AVR_JTAG_Instructions */
-#define AVR_JTAG_INS_LEN                                                       4
-// Public Instructions:
-#define AVR_JTAG_INS_EXTEST                                                    0x00
-#define AVR_JTAG_INS_IDCODE                                                    0x01
-#define AVR_JTAG_INS_SAMPLE_PRELOAD                                    0x02
-#define AVR_JTAG_INS_BYPASS                                                    0x0F
-// AVR Specified Public Instructions:
-#define AVR_JTAG_INS_AVR_RESET                                         0x0C
-#define AVR_JTAG_INS_PROG_ENABLE                                       0x04
-#define AVR_JTAG_INS_PROG_COMMANDS                                     0x05
-#define AVR_JTAG_INS_PROG_PAGELOAD                                     0x06
-#define AVR_JTAG_INS_PROG_PAGEREAD                                     0x07
-
-// Data Registers:
-#define AVR_JTAG_REG_Bypass_Len                                                1
-#define AVR_JTAG_REG_DeviceID_Len                                      32
-
-#define AVR_JTAG_REG_Reset_Len                                         1
-#define AVR_JTAG_REG_JTAGID_Len                                                32
-#define AVR_JTAG_REG_ProgrammingEnable_Len                     16
-#define AVR_JTAG_REG_ProgrammingCommand_Len                    15
-#define AVR_JTAG_REG_FlashDataByte_Len                         16
-
-struct avrf_type avft_chips_info[] =
-{
-//      name,                  chip_id,        flash_page_size,        flash_page_num, eeprom_page_size,       eeprom_page_num
-       {"atmega128",   0x9702,         256,                            512,                    8,                                      512},
-};
-
-int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out);
-int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len);
-
-int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
-int mcu_write_dr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int dr_len, int rti);
-int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
-int mcu_write_dr_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
-int mcu_write_ir_u16(struct jtag_tap *tap, uint16_t *ir_in, uint16_t ir_out, int ir_len, int rti);
-int mcu_write_dr_u16(struct jtag_tap *tap, uint16_t *ir_in, uint16_t ir_out, int dr_len, int rti);
-int mcu_write_ir_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
-int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
-int mcu_execute_queue(void);
-
-/* avr program functions */
-static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
-{
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, reset ,AVR_JTAG_REG_Reset_Len);
-
-       return ERROR_OK;
-}
-
-static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id)
-{
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE);
-       avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len);
-
-       return ERROR_OK;
-}
-
-static int avr_jtagprg_enterprogmode(struct avr_common *avr)
-{
-       avr_jtag_reset(avr, 1);
-
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_ProgrammingEnable_Len);
-
-       return ERROR_OK;
-}
-
-static int avr_jtagprg_leaveprogmode(struct avr_common *avr)
-{
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len);
-
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_ProgrammingEnable_Len);
-
-       avr_jtag_reset(avr, 0);
-
-       return ERROR_OK;
-}
-
-static int avr_jtagprg_chiperase(struct avr_common *avr)
-{
-       uint32_t poll_value;
-
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
-
-       do {
-               poll_value = 0;
-               avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
-               if (ERROR_OK != mcu_execute_queue())
-               {
-                       return ERROR_FAIL;
-               }
-               LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
-       } while (!(poll_value & 0x0200));
-
-       return ERROR_OK;
-}
-
-static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size)
-{
-       uint32_t i, poll_value;
-
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
-
-       // load addr high byte
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
-
-       // load addr low byte
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
-
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
-
-       for (i = 0; i < page_size; i++)
-       {
-               if (i < buf_size)
-               {
-                       avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
-               }
-               else
-               {
-                       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8);
-               }
-       }
-
-       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
-
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
-       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
-
-       do {
-               poll_value = 0;
-               avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
-               if (ERROR_OK != mcu_execute_queue())
-               {
-                       return ERROR_FAIL;
-               }
-               LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
-       } while (!(poll_value & 0x0200));
-
-       return ERROR_OK;
-}
-
-FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
-{
-       struct avrf_flash_bank *avrf_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank avr configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       avrf_info = malloc(sizeof(struct avrf_flash_bank));
-       bank->driver_priv = avrf_info;
-
-       avrf_info->probed = 0;
-
-       return ERROR_OK;
-}
-
-static int avrf_erase(struct flash_bank *bank, int first, int last)
-{
-       LOG_INFO("%s", __FUNCTION__);
-       return ERROR_OK;
-}
-
-static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       LOG_INFO("%s", __FUNCTION__);
-       return ERROR_OK;
-}
-
-static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct target *target = bank->target;
-       struct avr_common *avr = target->arch_info;
-       uint32_t cur_size, cur_buffer_size, page_size;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       page_size = bank->sectors[0].size;
-       if ((offset % page_size) != 0)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       LOG_DEBUG("offset is 0x%08" PRIx32 "", offset);
-       LOG_DEBUG("count is %" PRId32 "", count);
-
-       if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
-       {
-               return ERROR_FAIL;
-       }
-
-       cur_size = 0;
-       while (count > 0)
-       {
-               if (count > page_size)
-               {
-                       cur_buffer_size = page_size;
-               }
-               else
-               {
-                       cur_buffer_size = count;
-               }
-               avr_jtagprg_writeflashpage(avr, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size);
-               count -= cur_buffer_size;
-               cur_size += cur_buffer_size;
-
-               keep_alive();
-       }
-
-       return avr_jtagprg_leaveprogmode(avr);
-}
-
-#define EXTRACT_MFG(X)  (((X) & 0xffe) >> 1)
-#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
-#define EXTRACT_VER(X)  (((X) & 0xf0000000) >> 28)
-static int avrf_probe(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct avrf_flash_bank *avrf_info = bank->driver_priv;
-       struct avr_common *avr = target->arch_info;
-       struct avrf_type *avr_info = NULL;
-       int i;
-       uint32_t device_id;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       avrf_info->probed = 0;
-
-       avr_jtag_read_jtagid(avr, &device_id);
-       if (ERROR_OK != mcu_execute_queue())
-       {
-               return ERROR_FAIL;
-       }
-
-       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
-       if (EXTRACT_MFG(device_id) != 0x1F)
-       {
-               LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
-       }
-
-       for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
-       {
-               if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
-               {
-                       avr_info = &avft_chips_info[i];
-                       LOG_INFO("target device is %s", avr_info->name);
-                       break;
-               }
-       }
-
-       if (avr_info != NULL)
-       {
-               // chip found
-               bank->base = 0x00000000;
-               bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
-               bank->num_sectors = avr_info->flash_page_num;
-               bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
-
-               for (i = 0; i < avr_info->flash_page_num; i++)
-               {
-                       bank->sectors[i].offset = i * avr_info->flash_page_size;
-                       bank->sectors[i].size = avr_info->flash_page_size;
-                       bank->sectors[i].is_erased = -1;
-                       bank->sectors[i].is_protected = 1;
-               }
-
-               avrf_info->probed = 1;
-               return ERROR_OK;
-       }
-       else
-       {
-               // chip not supported
-               LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
-
-               avrf_info->probed = 1;
-               return ERROR_FAIL;
-       }
-}
-
-static int avrf_auto_probe(struct flash_bank *bank)
-{
-       struct avrf_flash_bank *avrf_info = bank->driver_priv;
-       if (avrf_info->probed)
-               return ERROR_OK;
-       return avrf_probe(bank);
-}
-
-static int avrf_protect_check(struct flash_bank *bank)
-{
-       LOG_INFO("%s", __FUNCTION__);
-       return ERROR_OK;
-}
-
-static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       struct target *target = bank->target;
-       struct avr_common *avr = target->arch_info;
-       struct avrf_type *avr_info = NULL;
-       int i;
-       uint32_t device_id;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       avr_jtag_read_jtagid(avr, &device_id);
-       if (ERROR_OK != mcu_execute_queue())
-       {
-               return ERROR_FAIL;
-       }
-
-       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
-       if (EXTRACT_MFG(device_id) != 0x1F)
-       {
-               LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
-       }
-
-       for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
-       {
-               if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
-               {
-                       avr_info = &avft_chips_info[i];
-                       LOG_INFO("target device is %s", avr_info->name);
-
-                       break;
-               }
-       }
-
-       if (avr_info != NULL)
-       {
-               // chip found
-               snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id));
-               return ERROR_OK;
-       }
-       else
-       {
-               // chip not supported
-               snprintf(buf, buf_size, "Cannot identify target as a avr\n");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-}
-
-static int avrf_mass_erase(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct avr_common *avr = target->arch_info;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((ERROR_OK != avr_jtagprg_enterprogmode(avr))
-               || (ERROR_OK != avr_jtagprg_chiperase(avr))
-               || (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
-       {
-               return ERROR_FAIL;
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(avrf_handle_mass_erase_command)
-{
-       int i;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "avr mass_erase <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if (avrf_mass_erase(bank) == ERROR_OK)
-       {
-               /* set all sectors as erased */
-               for (i = 0; i < bank->num_sectors; i++)
-               {
-                       bank->sectors[i].is_erased = 1;
-               }
-
-               command_print(CMD_CTX, "avr mass erase complete");
-       }
-       else
-       {
-               command_print(CMD_CTX, "avr mass erase failed");
-       }
-
-       LOG_DEBUG("%s", __FUNCTION__);
-       return ERROR_OK;
-}
-
-static const struct command_registration avrf_exec_command_handlers[] = {
-       {
-               .name = "mass_erase",
-               .handler = &avrf_handle_mass_erase_command,
-               .mode = COMMAND_EXEC,
-               .help = "erase entire device",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration avrf_command_handlers[] = {
-       {
-               .name = "avrf",
-               .mode = COMMAND_ANY,
-               .help = "AVR flash command group",
-               .chain = avrf_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver avr_flash = {
-               .name = "avr",
-               .commands = avrf_command_handlers,
-               .flash_bank_command = &avrf_flash_bank_command,
-               .erase = &avrf_erase,
-               .protect = &avrf_protect,
-               .write = &avrf_write,
-               .probe = &avrf_probe,
-               .auto_probe = &avrf_auto_probe,
-               .erase_check = &default_flash_mem_blank_check,
-               .protect_check = &avrf_protect_check,
-               .info = &avrf_info,
-       };
diff --git a/src/flash/avrf.h b/src/flash/avrf.h
deleted file mode 100644 (file)
index e75d9d7..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2009 by Simon Qian                                      *
- *   SimonQian@SimonQian.com                                               *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef AVRF_H
-#define AVRF_H
-
-#include "types.h"
-
-struct avrf_type
-{
-       char name[15];
-       uint16_t chip_id;
-       int flash_page_size;
-       int flash_page_num;
-       int eeprom_page_size;
-       int eeprom_page_num;
-};
-
-struct avrf_flash_bank
-{
-       int ppage_size;
-       int probed;
-};
-
-#endif /* AVRF_H */
diff --git a/src/flash/cfi.c b/src/flash/cfi.c
deleted file mode 100644 (file)
index 6dbffb9..0000000
+++ /dev/null
@@ -1,2630 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005, 2007 by Dominic Rath                              *
- *   Dominic.Rath@gmx.de                                                   *
- *   Copyright (C) 2009 Michael Schwingen                                  *
- *   michael@schwingen.org                                                 *
- *                                                                         *
- *   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 "cfi.h"
-#include "non_cfi.h"
-#include "armv4_5.h"
-#include "binarybuffer.h"
-#include "algorithm.h"
-
-
-#define CFI_MAX_BUS_WIDTH      4
-#define CFI_MAX_CHIP_WIDTH     4
-
-/* defines internal maximum size for code fragment in cfi_intel_write_block() */
-#define CFI_MAX_INTEL_CODESIZE 256
-
-static struct cfi_unlock_addresses cfi_unlock_addresses[] =
-{
-       [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
-       [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa },
-};
-
-/* CFI fixups foward declarations */
-static void cfi_fixup_0002_erase_regions(struct flash_bank *flash, void *param);
-static void cfi_fixup_0002_unlock_addresses(struct flash_bank *flash, void *param);
-static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *flash, void *param);
-
-/* fixup after reading cmdset 0002 primary query table */
-static const struct cfi_fixup cfi_0002_fixups[] = {
-       {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
-       {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
-       {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
-       {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
-       {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
-       {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
-       {CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
-       {CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
-       {CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
-       {CFI_MFR_AMD, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
-       {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
-       {0, 0, NULL, NULL}
-};
-
-/* fixup after reading cmdset 0001 primary query table */
-static const struct cfi_fixup cfi_0001_fixups[] = {
-       {0, 0, NULL, NULL}
-};
-
-static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       const struct cfi_fixup *f;
-
-       for (f = fixups; f->fixup; f++)
-       {
-               if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) &&
-                       ((f->id  == CFI_ID_ANY)  || (f->id  == cfi_info->device_id)))
-               {
-                       f->fixup(bank, f->param);
-               }
-       }
-}
-
-/* inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset) */
-static __inline__ uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       if (cfi_info->x16_as_x8) offset *= 2;
-
-       /* while the sector list isn't built, only accesses to sector 0 work */
-       if (sector == 0)
-               return bank->base + offset * bank->bus_width;
-       else
-       {
-               if (!bank->sectors)
-               {
-                       LOG_ERROR("BUG: sector list not yet built");
-                       exit(-1);
-               }
-               return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
-       }
-
-}
-
-static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
-{
-       int i;
-
-       /* clear whole buffer, to ensure bits that exceed the bus_width
-        * are set to zero
-        */
-       for (i = 0; i < CFI_MAX_BUS_WIDTH; i++)
-               cmd_buf[i] = 0;
-
-       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
-       {
-               for (i = bank->bus_width; i > 0; i--)
-               {
-                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
-               }
-       }
-       else
-       {
-               for (i = 1; i <= bank->bus_width; i++)
-               {
-                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
-               }
-       }
-}
-
-/* read unsigned 8-bit value from the bank
- * flash banks are expected to be made of similar chips
- * the query result should be the same for all
- */
-static uint8_t cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset)
-{
-       struct target *target = bank->target;
-       uint8_t data[CFI_MAX_BUS_WIDTH];
-
-       target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
-
-       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
-               return data[0];
-       else
-               return data[bank->bus_width - 1];
-}
-
-/* read unsigned 8-bit value from the bank
- * in case of a bank made of multiple chips,
- * the individual values are ORed
- */
-static uint8_t cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset)
-{
-       struct target *target = bank->target;
-       uint8_t data[CFI_MAX_BUS_WIDTH];
-       int i;
-
-       target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
-
-       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
-       {
-               for (i = 0; i < bank->bus_width / bank->chip_width; i++)
-                       data[0] |= data[i];
-
-               return data[0];
-       }
-       else
-       {
-               uint8_t value = 0;
-               for (i = 0; i < bank->bus_width / bank->chip_width; i++)
-                       value |= data[bank->bus_width - 1 - i];
-
-               return value;
-       }
-}
-
-static uint16_t cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset)
-{
-       struct target *target = bank->target;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       uint8_t data[CFI_MAX_BUS_WIDTH * 2];
-
-       if (cfi_info->x16_as_x8)
-       {
-               uint8_t i;
-               for (i = 0;i < 2;i++)
-                       target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1,
-                               &data[i*bank->bus_width]);
-       }
-       else
-               target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
-
-       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
-               return data[0] | data[bank->bus_width] << 8;
-       else
-               return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
-}
-
-static uint32_t cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset)
-{
-       struct target *target = bank->target;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       uint8_t data[CFI_MAX_BUS_WIDTH * 4];
-
-       if (cfi_info->x16_as_x8)
-       {
-               uint8_t i;
-               for (i = 0;i < 4;i++)
-                       target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1,
-                               &data[i*bank->bus_width]);
-       }
-       else
-               target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
-
-       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
-               return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24;
-       else
-               return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 |
-                               data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
-}
-
-static void cfi_intel_clear_status_register(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("BUG: attempted to clear status register while target wasn't halted");
-               exit(-1);
-       }
-
-       cfi_command(bank, 0x50, command);
-       target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-}
-
-uint8_t cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout)
-{
-       uint8_t status;
-
-       while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0))
-       {
-               LOG_DEBUG("status: 0x%x", status);
-               alive_sleep(1);
-       }
-
-       /* mask out bit 0 (reserved) */
-       status = status & 0xfe;
-
-       LOG_DEBUG("status: 0x%x", status);
-
-       if ((status & 0x80) != 0x80)
-       {
-               LOG_ERROR("timeout while waiting for WSM to become ready");
-       }
-       else if (status != 0x80)
-       {
-               LOG_ERROR("status register: 0x%x", status);
-               if (status & 0x2)
-                       LOG_ERROR("Block Lock-Bit Detected, Operation Abort");
-               if (status & 0x4)
-                       LOG_ERROR("Program suspended");
-               if (status & 0x8)
-                       LOG_ERROR("Low Programming Voltage Detected, Operation Aborted");
-               if (status & 0x10)
-                       LOG_ERROR("Program Error / Error in Setting Lock-Bit");
-               if (status & 0x20)
-                       LOG_ERROR("Error in Block Erasure or Clear Lock-Bits");
-               if (status & 0x40)
-                       LOG_ERROR("Block Erase Suspended");
-
-               cfi_intel_clear_status_register(bank);
-       }
-
-       return status;
-}
-
-int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
-{
-       uint8_t status, oldstatus;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       oldstatus = cfi_get_u8(bank, 0, 0x0);
-
-       do {
-               status = cfi_get_u8(bank, 0, 0x0);
-               if ((status ^ oldstatus) & 0x40) {
-                       if (status & cfi_info->status_poll_mask & 0x20) {
-                               oldstatus = cfi_get_u8(bank, 0, 0x0);
-                               status = cfi_get_u8(bank, 0, 0x0);
-                               if ((status ^ oldstatus) & 0x40) {
-                                       LOG_ERROR("dq5 timeout, status: 0x%x", status);
-                                       return(ERROR_FLASH_OPERATION_FAILED);
-                               } else {
-                                       LOG_DEBUG("status: 0x%x", status);
-                                       return(ERROR_OK);
-                               }
-                       }
-               } else { /* no toggle: finished, OK */
-                       LOG_DEBUG("status: 0x%x", status);
-                       return(ERROR_OK);
-               }
-
-               oldstatus = status;
-               alive_sleep(1);
-       } while (timeout-- > 0);
-
-       LOG_ERROR("timeout, status: 0x%x", status);
-
-       return(ERROR_FLASH_BUSY);
-}
-
-static int cfi_read_intel_pri_ext(struct flash_bank *bank)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_intel_pri_ext *pri_ext = malloc(sizeof(struct cfi_intel_pri_ext));
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       cfi_info->pri_ext = pri_ext;
-
-       pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
-       pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
-       pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
-
-       if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
-       {
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               cfi_command(bank, 0xff, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               LOG_ERROR("Could not read bank flash bank information");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
-       pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
-
-       LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
-
-       pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5);
-       pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
-       pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa);
-
-       LOG_DEBUG("feature_support: 0x%" PRIx32 ", suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x",
-                 pri_ext->feature_support,
-                 pri_ext->suspend_cmd_support,
-                 pri_ext->blk_status_reg_mask);
-
-       pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc);
-       pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd);
-
-       LOG_DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
-                 (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
-                 (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
-
-       pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe);
-       if (pri_ext->num_protection_fields != 1)
-       {
-               LOG_WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields);
-       }
-
-       pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf);
-       pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11);
-       pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12);
-
-       LOG_DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
-
-       return ERROR_OK;
-}
-
-static int cfi_read_spansion_pri_ext(struct flash_bank *bank)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       cfi_info->pri_ext = pri_ext;
-
-       pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
-       pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
-       pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
-
-       if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
-       {
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               LOG_ERROR("Could not read spansion bank information");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
-       pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
-
-       LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
-
-       pri_ext->SiliconRevision = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5);
-       pri_ext->EraseSuspend    = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6);
-       pri_ext->BlkProt         = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7);
-       pri_ext->TmpBlkUnprotect = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8);
-       pri_ext->BlkProtUnprot   = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
-       pri_ext->SimultaneousOps = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10);
-       pri_ext->BurstMode       = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11);
-       pri_ext->PageMode        = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12);
-       pri_ext->VppMin          = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13);
-       pri_ext->VppMax          = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14);
-       pri_ext->TopBottom       = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15);
-
-       LOG_DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", pri_ext->SiliconRevision,
-             pri_ext->EraseSuspend, pri_ext->BlkProt);
-
-       LOG_DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, Simultaneous Ops: 0x%x", pri_ext->TmpBlkUnprotect,
-             pri_ext->BlkProtUnprot, pri_ext->SimultaneousOps);
-
-       LOG_DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode);
-
-
-       LOG_DEBUG("Vpp min: %2.2d.%1.1d, Vpp max: %2.2d.%1.1x",
-                 (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f,
-                 (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f);
-
-       LOG_DEBUG("WP# protection 0x%x", pri_ext->TopBottom);
-
-       /* default values for implementation specific workarounds */
-       pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
-       pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
-       pri_ext->_reversed_geometry = 0;
-
-       return ERROR_OK;
-}
-
-static int cfi_read_atmel_pri_ext(struct flash_bank *bank)
-{
-       int retval;
-       struct cfi_atmel_pri_ext atmel_pri_ext;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion,
-        * but a different primary extended query table.
-        * We read the atmel table, and prepare a valid AMD/Spansion query table.
-        */
-
-       memset(pri_ext, 0, sizeof(struct cfi_spansion_pri_ext));
-
-       cfi_info->pri_ext = pri_ext;
-
-       atmel_pri_ext.pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
-       atmel_pri_ext.pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
-       atmel_pri_ext.pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
-
-       if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I'))
-       {
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               LOG_ERROR("Could not read atmel bank information");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       pri_ext->pri[0] = atmel_pri_ext.pri[0];
-       pri_ext->pri[1] = atmel_pri_ext.pri[1];
-       pri_ext->pri[2] = atmel_pri_ext.pri[2];
-
-       atmel_pri_ext.major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
-       atmel_pri_ext.minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
-
-       LOG_DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version);
-
-       pri_ext->major_version = atmel_pri_ext.major_version;
-       pri_ext->minor_version = atmel_pri_ext.minor_version;
-
-       atmel_pri_ext.features = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5);
-       atmel_pri_ext.bottom_boot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6);
-       atmel_pri_ext.burst_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7);
-       atmel_pri_ext.page_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8);
-
-       LOG_DEBUG("features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x",
-               atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode);
-
-       if (atmel_pri_ext.features & 0x02)
-               pri_ext->EraseSuspend = 2;
-
-       if (atmel_pri_ext.bottom_boot)
-               pri_ext->TopBottom = 2;
-       else
-               pri_ext->TopBottom = 3;
-
-       pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
-       pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
-
-       return ERROR_OK;
-}
-
-static int cfi_read_0002_pri_ext(struct flash_bank *bank)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       if (cfi_info->manufacturer == CFI_MFR_ATMEL)
-       {
-               return cfi_read_atmel_pri_ext(bank);
-       }
-       else
-       {
-               return cfi_read_spansion_pri_ext(bank);
-       }
-}
-
-static int cfi_spansion_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       int printed;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-
-       printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n");
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0],
-                          pri_ext->pri[1], pri_ext->pri[2],
-                          pri_ext->major_version, pri_ext->minor_version);
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n",
-                          (pri_ext->SiliconRevision) >> 2,
-                          (pri_ext->SiliconRevision) & 0x03);
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n",
-                          pri_ext->EraseSuspend,
-                          pri_ext->BlkProt);
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "VppMin: %2.2d.%1.1x, VppMax: %2.2d.%1.1x\n",
-               (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f,
-               (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f);
-
-       return ERROR_OK;
-}
-
-static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       int printed;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
-
-       printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "feature_support: 0x%" PRIx32 ", suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
-               (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
-               (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
-
-       return ERROR_OK;
-}
-
-/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options]
- */
-FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
-{
-       struct cfi_flash_bank *cfi_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank cfi configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       uint16_t chip_width, bus_width;
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], bus_width);
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[4], chip_width);
-
-       if ((chip_width > CFI_MAX_CHIP_WIDTH)
-                       || (bus_width > CFI_MAX_BUS_WIDTH))
-       {
-               LOG_ERROR("chip and bus width have to specified in bytes");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       cfi_info = malloc(sizeof(struct cfi_flash_bank));
-       cfi_info->probed = 0;
-       bank->driver_priv = cfi_info;
-
-       cfi_info->write_algorithm = NULL;
-
-       cfi_info->x16_as_x8 = 0;
-       cfi_info->jedec_probe = 0;
-       cfi_info->not_cfi = 0;
-
-       for (unsigned i = 6; i < CMD_ARGC; i++)
-       {
-               if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0)
-               {
-                       cfi_info->x16_as_x8 = 1;
-               }
-               else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0)
-               {
-                       cfi_info->jedec_probe = 1;
-               }
-       }
-
-       cfi_info->write_algorithm = NULL;
-
-       /* bank wasn't probed yet */
-       cfi_info->qry[0] = -1;
-
-       return ERROR_OK;
-}
-
-static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint8_t command[8];
-       int i;
-
-       cfi_intel_clear_status_register(bank);
-
-       for (i = first; i <= last; i++)
-       {
-               cfi_command(bank, 0x20, command);
-               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_command(bank, 0xd0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80)
-                       bank->sectors[i].is_erased = 1;
-               else
-               {
-                       cfi_command(bank, 0xff, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-
-                       LOG_ERROR("couldn't erase block %i of flash bank at base 0x%" PRIx32 , i, bank->base);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-       }
-
-       cfi_command(bank, 0xff, command);
-       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
-}
-
-static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct target *target = bank->target;
-       uint8_t command[8];
-       int i;
-
-       for (i = first; i <= last; i++)
-       {
-               cfi_command(bank, 0xaa, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_command(bank, 0x55, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_command(bank, 0x80, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_command(bank, 0xaa, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_command(bank, 0x55, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_command(bank, 0x30, command);
-               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == ERROR_OK)
-                       bank->sectors[i].is_erased = 1;
-               else
-               {
-                       cfi_command(bank, 0xf0, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-
-                       LOG_ERROR("couldn't erase block %i of flash bank at base 0x%" PRIx32, i, bank->base);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-       }
-
-       cfi_command(bank, 0xf0, command);
-       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-}
-
-static int cfi_erase(struct flash_bank *bank, int first, int last)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       if (cfi_info->qry[0] != 'Q')
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       switch (cfi_info->pri_id)
-       {
-               case 1:
-               case 3:
-                       return cfi_intel_erase(bank, first, last);
-                       break;
-               case 2:
-                       return cfi_spansion_erase(bank, first, last);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct target *target = bank->target;
-       uint8_t command[8];
-       int retry = 0;
-       int i;
-
-       /* if the device supports neither legacy lock/unlock (bit 3) nor
-        * instant individual block locking (bit 5).
-        */
-       if (!(pri_ext->feature_support & 0x28))
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       cfi_intel_clear_status_register(bank);
-
-       for (i = first; i <= last; i++)
-       {
-               cfi_command(bank, 0x60, command);
-               LOG_DEBUG("address: 0x%4.4" PRIx32 ", command: 0x%4.4" PRIx32, flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
-               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if (set)
-               {
-                       cfi_command(bank, 0x01, command);
-                       LOG_DEBUG("address: 0x%4.4" PRIx32 ", command: 0x%4.4" PRIx32 , flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
-                       if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       bank->sectors[i].is_protected = 1;
-               }
-               else
-               {
-                       cfi_command(bank, 0xd0, command);
-                       LOG_DEBUG("address: 0x%4.4" PRIx32 ", command: 0x%4.4" PRIx32, flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
-                       if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       bank->sectors[i].is_protected = 0;
-               }
-
-               /* instant individual block locking doesn't require reading of the status register */
-               if (!(pri_ext->feature_support & 0x20))
-               {
-                       /* Clear lock bits operation may take up to 1.4s */
-                       cfi_intel_wait_status_busy(bank, 1400);
-               }
-               else
-               {
-                       uint8_t block_status;
-                       /* read block lock bit, to verify status */
-                       cfi_command(bank, 0x90, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       block_status = cfi_get_u8(bank, i, 0x2);
-
-                       if ((block_status & 0x1) != set)
-                       {
-                               LOG_ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status);
-                               cfi_command(bank, 0x70, command);
-                               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
-                               {
-                                       return retval;
-                               }
-                               cfi_intel_wait_status_busy(bank, 10);
-
-                               if (retry > 10)
-                                       return ERROR_FLASH_OPERATION_FAILED;
-                               else
-                               {
-                                       i--;
-                                       retry++;
-                               }
-                       }
-               }
-       }
-
-       /* if the device doesn't support individual block lock bits set/clear,
-        * all blocks have been unlocked in parallel, so we set those that should be protected
-        */
-       if ((!set) && (!(pri_ext->feature_support & 0x20)))
-       {
-               for (i = 0; i < bank->num_sectors; i++)
-               {
-                       if (bank->sectors[i].is_protected == 1)
-                       {
-                               cfi_intel_clear_status_register(bank);
-
-                               cfi_command(bank, 0x60, command);
-                               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                               {
-                                       return retval;
-                               }
-
-                               cfi_command(bank, 0x01, command);
-                               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                               {
-                                       return retval;
-                               }
-
-                               cfi_intel_wait_status_busy(bank, 100);
-                       }
-               }
-       }
-
-       cfi_command(bank, 0xff, command);
-       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-}
-
-static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       if (cfi_info->qry[0] != 'Q')
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       switch (cfi_info->pri_id)
-       {
-               case 1:
-               case 3:
-                       cfi_intel_protect(bank, set, first, last);
-                       break;
-               default:
-                       LOG_ERROR("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-
-       return ERROR_OK;
-}
-
-/* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */
-static void cfi_add_byte(struct flash_bank *bank, uint8_t *word, uint8_t byte)
-{
-       /* struct target *target = bank->target; */
-
-       int i;
-
-       /* NOTE:
-        * The data to flash must not be changed in endian! We write a bytestrem in
-        * target byte order already. Only the control and status byte lane of the flash
-        * WSM is interpreted by the CPU in different ways, when read a uint16_t or uint32_t
-        * word (data seems to be in the upper or lower byte lane for uint16_t accesses).
-        */
-
-#if 0
-       if (target->endianness == TARGET_LITTLE_ENDIAN)
-       {
-#endif
-               /* shift bytes */
-               for (i = 0; i < bank->bus_width - 1; i++)
-                       word[i] = word[i + 1];
-               word[bank->bus_width - 1] = byte;
-#if 0
-       }
-       else
-       {
-               /* shift bytes */
-               for (i = bank->bus_width - 1; i > 0; i--)
-                       word[i] = word[i - 1];
-               word[0] = byte;
-       }
-#endif
-}
-
-/* Convert code image to target endian */
-/* FIXME create general block conversion fcts in target.c?) */
-static void cfi_fix_code_endian(struct target *target, uint8_t *dest, const uint32_t *src, uint32_t count)
-{
-       uint32_t i;
-       for (i = 0; i< count; i++)
-       {
-               target_buffer_set_u32(target, dest, *src);
-               dest += 4;
-               src++;
-       }
-}
-
-static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd)
-{
-       struct target *target = bank->target;
-
-       uint8_t buf[CFI_MAX_BUS_WIDTH];
-       cfi_command(bank, cmd, buf);
-       switch (bank->bus_width)
-       {
-       case 1 :
-               return buf[0];
-               break;
-       case 2 :
-               return target_buffer_get_u16(target, buf);
-               break;
-       case 4 :
-               return target_buffer_get_u32(target, buf);
-               break;
-       default :
-               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
-               return 0;
-       }
-}
-
-static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       struct reg_param reg_params[7];
-       struct armv4_5_algorithm armv4_5_info;
-       struct working_area *source;
-       uint32_t buffer_size = 32768;
-       uint32_t write_command_val, busy_pattern_val, error_pattern_val;
-
-       /* algorithm register usage:
-        * r0: source address (in RAM)
-        * r1: target address (in Flash)
-        * r2: count
-        * r3: flash write command
-        * r4: status byte (returned to host)
-        * r5: busy test pattern
-        * r6: error test pattern
-        */
-
-       static const uint32_t word_32_code[] = {
-               0xe4904004,   /* loop:  ldr r4, [r0], #4 */
-               0xe5813000,   /*                str r3, [r1] */
-               0xe5814000,   /*                str r4, [r1] */
-               0xe5914000,   /* busy:  ldr r4, [r1] */
-               0xe0047005,   /*                and r7, r4, r5 */
-               0xe1570005,   /*                cmp r7, r5 */
-               0x1afffffb,   /*                bne busy */
-               0xe1140006,   /*                tst r4, r6 */
-               0x1a000003,   /*                bne done */
-               0xe2522001,   /*                subs r2, r2, #1 */
-               0x0a000001,   /*                beq done */
-               0xe2811004,   /*                add r1, r1 #4 */
-               0xeafffff2,   /*                b loop */
-               0xeafffffe    /* done:  b -2 */
-       };
-
-       static const uint32_t word_16_code[] = {
-               0xe0d040b2,   /* loop:  ldrh r4, [r0], #2 */
-               0xe1c130b0,   /*                strh r3, [r1] */
-               0xe1c140b0,   /*                strh r4, [r1] */
-               0xe1d140b0,   /* busy   ldrh r4, [r1] */
-               0xe0047005,   /*                and r7, r4, r5 */
-               0xe1570005,   /*                cmp r7, r5 */
-               0x1afffffb,   /*                bne busy */
-               0xe1140006,   /*                tst r4, r6 */
-               0x1a000003,   /*                bne done */
-               0xe2522001,   /*                subs r2, r2, #1 */
-               0x0a000001,   /*                beq done */
-               0xe2811002,   /*                add r1, r1 #2 */
-               0xeafffff2,   /*                b loop */
-               0xeafffffe    /* done:  b -2 */
-       };
-
-       static const uint32_t word_8_code[] = {
-               0xe4d04001,   /* loop:  ldrb r4, [r0], #1 */
-               0xe5c13000,   /*                strb r3, [r1] */
-               0xe5c14000,   /*                strb r4, [r1] */
-               0xe5d14000,   /* busy   ldrb r4, [r1] */
-               0xe0047005,   /*                and r7, r4, r5 */
-               0xe1570005,   /*                cmp r7, r5 */
-               0x1afffffb,   /*                bne busy */
-               0xe1140006,   /*                tst r4, r6 */
-               0x1a000003,   /*                bne done */
-               0xe2522001,   /*                subs r2, r2, #1 */
-               0x0a000001,   /*                beq done */
-               0xe2811001,   /*                add r1, r1 #1 */
-               0xeafffff2,   /*                b loop */
-               0xeafffffe    /* done:  b -2 */
-       };
-       uint8_t target_code[4*CFI_MAX_INTEL_CODESIZE];
-       const uint32_t *target_code_src;
-       uint32_t target_code_size;
-       int retval = ERROR_OK;
-
-
-       cfi_intel_clear_status_register(bank);
-
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-       /* If we are setting up the write_algorith, we need target_code_src */
-       /* if not we only need target_code_size. */
-
-       /* However, we don't want to create multiple code paths, so we */
-       /* do the unecessary evaluation of target_code_src, which the */
-       /* compiler will probably nicely optimize away if not needed */
-
-       /* prepare algorithm code for target endian */
-       switch (bank->bus_width)
-       {
-       case 1 :
-               target_code_src = word_8_code;
-               target_code_size = sizeof(word_8_code);
-               break;
-       case 2 :
-               target_code_src = word_16_code;
-               target_code_size = sizeof(word_16_code);
-               break;
-       case 4 :
-               target_code_src = word_32_code;
-               target_code_size = sizeof(word_32_code);
-               break;
-       default:
-               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       }
-
-       /* flash write code */
-       if (!cfi_info->write_algorithm)
-       {
-               if (target_code_size > sizeof(target_code))
-               {
-                       LOG_WARNING("Internal error - target code buffer to small. Increase CFI_MAX_INTEL_CODESIZE and recompile.");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-               cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
-
-               /* Get memory for block write handler */
-               retval = target_alloc_working_area(target, target_code_size, &cfi_info->write_algorithm);
-               if (retval != ERROR_OK)
-               {
-                       LOG_WARNING("No working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               };
-
-               /* write algorithm code to working area */
-               retval = target_write_buffer(target, cfi_info->write_algorithm->address, target_code_size, target_code);
-               if (retval != ERROR_OK)
-               {
-                       LOG_ERROR("Unable to write block write code to target");
-                       goto cleanup;
-               }
-       }
-
-       /* Get a workspace buffer for the data to flash starting with 32k size.
-          Half size until buffer would be smaller 256 Bytem then fail back */
-       /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */
-       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
-       {
-               buffer_size /= 2;
-               if (buffer_size <= 256)
-               {
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
-                       retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-                       goto cleanup;
-               }
-       };
-
-       /* setup algo registers */
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
-       init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
-       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
-       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT);
-
-       /* prepare command and status register patterns */
-       write_command_val = cfi_command_val(bank, 0x40);
-       busy_pattern_val  = cfi_command_val(bank, 0x80);
-       error_pattern_val = cfi_command_val(bank, 0x7e);
-
-       LOG_INFO("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
-
-       /* Programming main loop */
-       while (count > 0)
-       {
-               uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
-               uint32_t wsm_error;
-
-               if ((retval = target_write_buffer(target, source->address, thisrun_count, buffer)) != ERROR_OK)
-               {
-                       goto cleanup;
-               }
-
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
-
-               buf_set_u32(reg_params[3].value, 0, 32, write_command_val);
-               buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val);
-               buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val);
-
-               LOG_INFO("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32 , thisrun_count, address);
-
-               /* Execute algorithm, assume breakpoint for last instruction */
-               retval = target_run_algorithm(target, 0, NULL, 7, reg_params,
-                       cfi_info->write_algorithm->address,
-                       cfi_info->write_algorithm->address + target_code_size - sizeof(uint32_t),
-                       10000, /* 10s should be enough for max. 32k of data */
-                       &armv4_5_info);
-
-               /* On failure try a fall back to direct word writes */
-               if (retval != ERROR_OK)
-               {
-                       cfi_intel_clear_status_register(bank);
-                       LOG_ERROR("Execution of flash algorythm failed. Can't fall back. Please report.");
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       /* retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; */
-                       /* FIXME To allow fall back or recovery, we must save the actual status
-                          somewhere, so that a higher level code can start recovery. */
-                       goto cleanup;
-               }
-
-               /* Check return value from algo code */
-               wsm_error = buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val;
-               if (wsm_error)
-               {
-                       /* read status register (outputs debug inforation) */
-                       cfi_intel_wait_status_busy(bank, 100);
-                       cfi_intel_clear_status_register(bank);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       goto cleanup;
-               }
-
-               buffer += thisrun_count;
-               address += thisrun_count;
-               count -= thisrun_count;
-       }
-
-       /* free up resources */
-cleanup:
-       if (source)
-               target_free_working_area(target, source);
-
-       if (cfi_info->write_algorithm)
-       {
-               target_free_working_area(target, cfi_info->write_algorithm);
-               cfi_info->write_algorithm = NULL;
-       }
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-       destroy_reg_param(&reg_params[4]);
-       destroy_reg_param(&reg_params[5]);
-       destroy_reg_param(&reg_params[6]);
-
-       return retval;
-}
-
-static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct target *target = bank->target;
-       struct reg_param reg_params[10];
-       struct armv4_5_algorithm armv4_5_info;
-       struct working_area *source;
-       uint32_t buffer_size = 32768;
-       uint32_t status;
-       int retval, retvaltemp;
-       int exit_code = ERROR_OK;
-
-       /* input parameters - */
-       /*      R0 = source address */
-       /*      R1 = destination address */
-       /*      R2 = number of writes */
-       /*      R3 = flash write command */
-       /*      R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
-       /* output parameters - */
-       /*      R5 = 0x80 ok 0x00 bad */
-       /* temp registers - */
-       /*      R6 = value read from flash to test status */
-       /*      R7 = holding register */
-       /* unlock registers - */
-       /*  R8 = unlock1_addr */
-       /*  R9 = unlock1_cmd */
-       /*  R10 = unlock2_addr */
-       /*  R11 = unlock2_cmd */
-
-       static const uint32_t word_32_code[] = {
-                                               /* 00008100 <sp_32_code>:               */
-               0xe4905004,             /* ldr  r5, [r0], #4                    */
-               0xe5889000,     /* str  r9, [r8]                                */
-               0xe58ab000,     /* str  r11, [r10]                              */
-               0xe5883000,     /* str  r3, [r8]                                */
-               0xe5815000,     /* str  r5, [r1]                                */
-               0xe1a00000,     /* nop                                                  */
-                                               /*                                                              */
-                                               /* 00008110 <sp_32_busy>:               */
-               0xe5916000,     /* ldr  r6, [r1]                                */
-               0xe0257006,     /* eor  r7, r5, r6                              */
-               0xe0147007,     /* ands r7, r4, r7                              */
-               0x0a000007,     /* beq  8140 <sp_32_cont> ; b if DQ7 == Data7 */
-               0xe0166124,     /* ands r6, r6, r4, lsr #2              */
-               0x0afffff9,     /* beq  8110 <sp_32_busy> ;     b if DQ5 low */
-               0xe5916000,     /* ldr  r6, [r1]                                */
-               0xe0257006,     /* eor  r7, r5, r6                              */
-               0xe0147007,     /* ands r7, r4, r7                              */
-               0x0a000001,     /* beq  8140 <sp_32_cont> ; b if DQ7 == Data7 */
-               0xe3a05000,     /* mov  r5, #0  ; 0x0 - return 0x00, error */
-               0x1a000004,     /* bne  8154 <sp_32_done>               */
-                                               /*                                                              */
-                               /* 00008140 <sp_32_cont>:                               */
-               0xe2522001,     /* subs r2, r2, #1      ; 0x1           */
-               0x03a05080,     /* moveq        r5, #128        ; 0x80  */
-               0x0a000001,     /* beq  8154 <sp_32_done>               */
-               0xe2811004,     /* add  r1, r1, #4      ; 0x4           */
-               0xeaffffe8,     /* b    8100 <sp_32_code>               */
-                                               /*                                                              */
-                                               /* 00008154 <sp_32_done>:               */
-               0xeafffffe              /* b    8154 <sp_32_done>               */
-               };
-
-               static const uint32_t word_16_code[] = {
-                               /* 00008158 <sp_16_code>:              */
-               0xe0d050b2,     /* ldrh r5, [r0], #2               */
-               0xe1c890b0,     /* strh r9, [r8]                                */
-               0xe1cab0b0,     /* strh r11, [r10]                              */
-               0xe1c830b0,     /* strh r3, [r8]                                */
-               0xe1c150b0,     /* strh r5, [r1]                       */
-               0xe1a00000,     /* nop                  (mov r0,r0)    */
-                               /*                                     */
-                               /* 00008168 <sp_16_busy>:              */
-               0xe1d160b0,     /* ldrh r6, [r1]                       */
-               0xe0257006,     /* eor  r7, r5, r6                     */
-               0xe0147007,     /* ands r7, r4, r7                     */
-               0x0a000007,     /* beq  8198 <sp_16_cont>              */
-               0xe0166124,     /* ands r6, r6, r4, lsr #2             */
-               0x0afffff9,     /* beq  8168 <sp_16_busy>              */
-               0xe1d160b0,     /* ldrh r6, [r1]                       */
-               0xe0257006,     /* eor  r7, r5, r6                     */
-               0xe0147007,     /* ands r7, r4, r7                     */
-               0x0a000001,     /* beq  8198 <sp_16_cont>              */
-               0xe3a05000,     /* mov  r5, #0  ; 0x0                  */
-               0x1a000004,     /* bne  81ac <sp_16_done>              */
-                               /*                                     */
-                               /* 00008198 <sp_16_cont>:              */
-               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
-               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
-               0x0a000001,     /* beq  81ac <sp_16_done>              */
-               0xe2811002,     /* add  r1, r1, #2      ; 0x2          */
-               0xeaffffe8,     /* b    8158 <sp_16_code>              */
-                               /*                                     */
-                               /* 000081ac <sp_16_done>:              */
-               0xeafffffe      /* b    81ac <sp_16_done>              */
-               };
-
-               static const uint32_t word_16_code_dq7only[] = {
-                               /* <sp_16_code>:                       */
-               0xe0d050b2,     /* ldrh r5, [r0], #2                   */
-               0xe1c890b0,     /* strh r9, [r8]                       */
-               0xe1cab0b0,     /* strh r11, [r10]                              */
-               0xe1c830b0,     /* strh r3, [r8]                                */
-               0xe1c150b0,     /* strh r5, [r1]                       */
-               0xe1a00000,     /* nop                  (mov r0,r0)    */
-                               /*                                     */
-                               /* <sp_16_busy>:                       */
-               0xe1d160b0,     /* ldrh r6, [r1]                       */
-               0xe0257006,     /* eor  r7, r5, r6                     */
-               0xe2177080,     /* ands r7, #0x80                      */
-               0x1afffffb,     /* bne  8168 <sp_16_busy>              */
-                               /*                                     */
-               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
-               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
-               0x0a000001,     /* beq  81ac <sp_16_done>              */
-               0xe2811002,     /* add  r1, r1, #2      ; 0x2          */
-               0xeafffff0,     /* b    8158 <sp_16_code>              */
-                               /*                                     */
-                               /* 000081ac <sp_16_done>:              */
-               0xeafffffe      /* b    81ac <sp_16_done>              */
-               };
-
-               static const uint32_t word_8_code[] = {
-                               /* 000081b0 <sp_16_code_end>:          */
-               0xe4d05001,     /* ldrb r5, [r0], #1                   */
-               0xe5c89000,     /* strb r9, [r8]                                */
-               0xe5cab000,     /* strb r11, [r10]                              */
-               0xe5c83000,     /* strb r3, [r8]                                */
-               0xe5c15000,     /* strb r5, [r1]                       */
-               0xe1a00000,     /* nop                  (mov r0,r0)    */
-                               /*                                     */
-                               /* 000081c0 <sp_8_busy>:               */
-               0xe5d16000,     /* ldrb r6, [r1]                       */
-               0xe0257006,     /* eor  r7, r5, r6                     */
-               0xe0147007,     /* ands r7, r4, r7                     */
-               0x0a000007,     /* beq  81f0 <sp_8_cont>               */
-               0xe0166124,     /* ands r6, r6, r4, lsr #2             */
-               0x0afffff9,     /* beq  81c0 <sp_8_busy>               */
-               0xe5d16000,     /* ldrb r6, [r1]                       */
-               0xe0257006,     /* eor  r7, r5, r6                     */
-               0xe0147007,     /* ands r7, r4, r7                     */
-               0x0a000001,     /* beq  81f0 <sp_8_cont>               */
-               0xe3a05000,     /* mov  r5, #0  ; 0x0                  */
-               0x1a000004,     /* bne  8204 <sp_8_done>               */
-                               /*                                     */
-                               /* 000081f0 <sp_8_cont>:               */
-               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
-               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
-               0x0a000001,     /* beq  8204 <sp_8_done>               */
-               0xe2811001,     /* add  r1, r1, #1      ; 0x1          */
-               0xeaffffe8,     /* b    81b0 <sp_16_code_end>          */
-                               /*                                     */
-                               /* 00008204 <sp_8_done>:               */
-               0xeafffffe      /* b    8204 <sp_8_done>               */
-       };
-
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-       int target_code_size;
-       const uint32_t *target_code_src;
-
-       switch (bank->bus_width)
-       {
-       case 1 :
-               target_code_src = word_8_code;
-               target_code_size = sizeof(word_8_code);
-               break;
-       case 2 :
-               /* Check for DQ5 support */
-               if( cfi_info->status_poll_mask & (1 << 5) )
-               {
-                       target_code_src = word_16_code;
-                       target_code_size = sizeof(word_16_code);
-               }
-               else
-               {
-                       /* No DQ5 support. Use DQ7 DATA# polling only. */
-                       target_code_src = word_16_code_dq7only;
-                       target_code_size = sizeof(word_16_code_dq7only);
-               }
-               break;
-       case 4 :
-               target_code_src = word_32_code;
-               target_code_size = sizeof(word_32_code);
-               break;
-       default:
-               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       }
-
-       /* flash write code */
-       if (!cfi_info->write_algorithm)
-       {
-               uint8_t *target_code;
-
-               /* convert bus-width dependent algorithm code to correct endiannes */
-               target_code = malloc(target_code_size);
-               cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
-
-               /* allocate working area */
-               retval = target_alloc_working_area(target, target_code_size,
-                               &cfi_info->write_algorithm);
-               if (retval != ERROR_OK)
-               {
-                       free(target_code);
-                       return retval;
-               }
-
-               /* write algorithm code to working area */
-               if ((retval = target_write_buffer(target, cfi_info->write_algorithm->address,
-                                   target_code_size, target_code)) != ERROR_OK)
-               {
-                       free(target_code);
-                       return retval;
-               }
-
-               free(target_code);
-       }
-       /* the following code still assumes target code is fixed 24*4 bytes */
-
-       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 (cfi_info->write_algorithm)
-                               target_free_working_area(target, cfi_info->write_algorithm);
-
-                       LOG_WARNING("not enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-       };
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
-       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
-       init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);
-       init_reg_param(&reg_params[6], "r8", 32, PARAM_OUT);
-       init_reg_param(&reg_params[7], "r9", 32, PARAM_OUT);
-       init_reg_param(&reg_params[8], "r10", 32, PARAM_OUT);
-       init_reg_param(&reg_params[9], "r11", 32, PARAM_OUT);
-
-       while (count > 0)
-       {
-               uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
-
-               retvaltemp = target_write_buffer(target, source->address, thisrun_count, buffer);
-
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
-               buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0));
-               buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80));
-               buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
-               buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa);
-               buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
-               buf_set_u32(reg_params[9].value, 0, 32, 0x55555555);
-
-               retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
-                                                    cfi_info->write_algorithm->address,
-                                                    cfi_info->write_algorithm->address + ((target_code_size) - 4),
-                                                    10000, &armv4_5_info);
-
-               status = buf_get_u32(reg_params[5].value, 0, 32);
-
-               if ((retval != ERROR_OK) || (retvaltemp != ERROR_OK) || status != 0x80)
-               {
-                       LOG_DEBUG("status: 0x%" PRIx32 , status);
-                       exit_code = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer += thisrun_count;
-               address += thisrun_count;
-               count -= thisrun_count;
-       }
-
-       target_free_all_working_areas(target);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-       destroy_reg_param(&reg_params[4]);
-       destroy_reg_param(&reg_params[5]);
-       destroy_reg_param(&reg_params[6]);
-       destroy_reg_param(&reg_params[7]);
-       destroy_reg_param(&reg_params[8]);
-       destroy_reg_param(&reg_params[9]);
-
-       return exit_code;
-}
-
-static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       cfi_intel_clear_status_register(bank);
-       cfi_command(bank, 0x40, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, word)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
-       {
-               cfi_command(bank, 0xff, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address %" PRIx32 , bank->base, address);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       /* Calculate buffer size and boundary mask */
-       uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
-       uint32_t buffermask = buffersize-1;
-       uint32_t bufferwsize;
-
-       /* Check for valid range */
-       if (address & buffermask)
-       {
-               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary",
-                         bank->base, address, cfi_info->max_buf_write_size);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       switch (bank->chip_width)
-       {
-       case 4 : bufferwsize = buffersize / 4; break;
-       case 2 : bufferwsize = buffersize / 2; break;
-       case 1 : bufferwsize = buffersize; break;
-       default:
-               LOG_ERROR("Unsupported chip width %d", bank->chip_width);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       bufferwsize/=(bank->bus_width / bank->chip_width);
-
-
-       /* Check for valid size */
-       if (wordcount > bufferwsize)
-       {
-               LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" PRId32 , wordcount, buffersize);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Write to flash buffer */
-       cfi_intel_clear_status_register(bank);
-
-       /* Initiate buffer operation _*/
-       cfi_command(bank, 0xE8, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-       if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80)
-       {
-               cfi_command(bank, 0xff, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               LOG_ERROR("couldn't start buffer write operation at base 0x%" PRIx32 ", address %" PRIx32 , bank->base, address);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Write buffer wordcount-1 and data words */
-       cfi_command(bank, bufferwsize-1, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if ((retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       /* Commit write operation */
-       cfi_command(bank, 0xd0, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-       if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80)
-       {
-               cfi_command(bank, 0xff, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               LOG_ERROR("Buffer write at base 0x%" PRIx32 ", address %" PRIx32 " failed.", bank->base, address);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct target *target = bank->target;
-       uint8_t command[8];
-
-       cfi_command(bank, 0xaa, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       cfi_command(bank, 0x55, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       cfi_command(bank, 0xa0, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, word)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
-       {
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address %" PRIx32 , bank->base, address);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint8_t command[8];
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-
-       /* Calculate buffer size and boundary mask */
-       uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
-       uint32_t buffermask = buffersize-1;
-       uint32_t bufferwsize;
-
-       /* Check for valid range */
-       if (address & buffermask)
-       {
-               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       switch (bank->chip_width)
-       {
-       case 4 : bufferwsize = buffersize / 4; break;
-       case 2 : bufferwsize = buffersize / 2; break;
-       case 1 : bufferwsize = buffersize; break;
-       default:
-               LOG_ERROR("Unsupported chip width %d", bank->chip_width);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       bufferwsize/=(bank->bus_width / bank->chip_width);
-
-       /* Check for valid size */
-       if (wordcount > bufferwsize)
-       {
-               LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" PRId32, wordcount, buffersize);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       // Unlock
-       cfi_command(bank, 0xaa, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       cfi_command(bank, 0x55, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       // Buffer load command
-       cfi_command(bank, 0x25, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       /* Write buffer wordcount-1 and data words */
-       cfi_command(bank, bufferwsize-1, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if ((retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       /* Commit write operation */
-       cfi_command(bank, 0x29, command);
-       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
-       {
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               LOG_ERROR("couldn't write block at base 0x%" PRIx32 ", address %" PRIx32 ", size %" PRIx32 , bank->base, address, bufferwsize);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       switch (cfi_info->pri_id)
-       {
-               case 1:
-               case 3:
-                       return cfi_intel_write_word(bank, word, address);
-                       break;
-               case 2:
-                       return cfi_spansion_write_word(bank, word, address);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-
-       return ERROR_FLASH_OPERATION_FAILED;
-}
-
-static int cfi_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       switch (cfi_info->pri_id)
-       {
-               case 1:
-               case 3:
-                       return cfi_intel_write_words(bank, word, wordcount, address);
-                       break;
-               case 2:
-                       return cfi_spansion_write_words(bank, word, wordcount, address);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-
-       return ERROR_FLASH_OPERATION_FAILED;
-}
-
-int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t address = bank->base + offset; /* address of first byte to be programmed */
-       uint32_t write_p, copy_p;
-       int align;      /* number of unaligned bytes */
-       int blk_count; /* number of bus_width bytes for block copy */
-       uint8_t current_word[CFI_MAX_BUS_WIDTH * 4];    /* word (bus_width size) currently being programmed */
-       int i;
-       int retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset + count > bank->size)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       if (cfi_info->qry[0] != 'Q')
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       /* start at the first byte of the first word (bus_width size) */
-       write_p = address & ~(bank->bus_width - 1);
-       if ((align = address - write_p) != 0)
-       {
-               LOG_INFO("Fixup %d unaligned head bytes", align);
-
-               for (i = 0; i < bank->bus_width; i++)
-                       current_word[i] = 0;
-               copy_p = write_p;
-
-               /* copy bytes before the first write address */
-               for (i = 0; i < align; ++i, ++copy_p)
-               {
-                       uint8_t byte;
-                       if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       cfi_add_byte(bank, current_word, byte);
-               }
-
-               /* add bytes from the buffer */
-               for (; (i < bank->bus_width) && (count > 0); i++)
-               {
-                       cfi_add_byte(bank, current_word, *buffer++);
-                       count--;
-                       copy_p++;
-               }
-
-               /* if the buffer is already finished, copy bytes after the last write address */
-               for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
-               {
-                       uint8_t byte;
-                       if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       cfi_add_byte(bank, current_word, byte);
-               }
-
-               retval = cfi_write_word(bank, current_word, write_p);
-               if (retval != ERROR_OK)
-                       return retval;
-               write_p = copy_p;
-       }
-
-       /* handle blocks of bus_size aligned bytes */
-       blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */
-       switch (cfi_info->pri_id)
-       {
-               /* try block writes (fails without working area) */
-               case 1:
-               case 3:
-                       retval = cfi_intel_write_block(bank, buffer, write_p, blk_count);
-                       break;
-               case 2:
-                       retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-       }
-       if (retval == ERROR_OK)
-       {
-               /* Increment pointers and decrease count on succesful block write */
-               buffer += blk_count;
-               write_p += blk_count;
-               count -= blk_count;
-       }
-       else
-       {
-               if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-               {
-                       //adjust buffersize for chip width
-                       uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
-                       uint32_t buffermask = buffersize-1;
-                       uint32_t bufferwsize;
-
-                       switch (bank->chip_width)
-                       {
-                       case 4 : bufferwsize = buffersize / 4; break;
-                       case 2 : bufferwsize = buffersize / 2; break;
-                       case 1 : bufferwsize = buffersize; break;
-                       default:
-                               LOG_ERROR("Unsupported chip width %d", bank->chip_width);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-
-                       bufferwsize/=(bank->bus_width / bank->chip_width);
-
-                       /* fall back to memory writes */
-                       while (count >= (uint32_t)bank->bus_width)
-                       {
-                               int fallback;
-                               if ((write_p & 0xff) == 0)
-                               {
-                                       LOG_INFO("Programming at %08" PRIx32 ", count %08" PRIx32 " bytes remaining", write_p, count);
-                               }
-                               fallback = 1;
-                               if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask))
-                               {
-                                       retval = cfi_write_words(bank, buffer, bufferwsize, write_p);
-                                       if (retval == ERROR_OK)
-                                       {
-                                               buffer += buffersize;
-                                               write_p += buffersize;
-                                               count -= buffersize;
-                                               fallback = 0;
-                                       }
-                               }
-                               /* try the slow way? */
-                               if (fallback)
-                               {
-                                       for (i = 0; i < bank->bus_width; i++)
-                                               current_word[i] = 0;
-
-                                       for (i = 0; i < bank->bus_width; i++)
-                                       {
-                                               cfi_add_byte(bank, current_word, *buffer++);
-                                       }
-
-                                       retval = cfi_write_word(bank, current_word, write_p);
-                                       if (retval != ERROR_OK)
-                                               return retval;
-
-                                       write_p += bank->bus_width;
-                                       count -= bank->bus_width;
-                               }
-                       }
-               }
-               else
-                       return retval;
-       }
-
-       /* return to read array mode, so we can read from flash again for padding */
-       cfi_command(bank, 0xf0, current_word);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word)) != ERROR_OK)
-       {
-               return retval;
-       }
-       cfi_command(bank, 0xff, current_word);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       /* handle unaligned tail bytes */
-       if (count > 0)
-       {
-               LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
-
-               copy_p = write_p;
-               for (i = 0; i < bank->bus_width; i++)
-                       current_word[i] = 0;
-
-               for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
-               {
-                       cfi_add_byte(bank, current_word, *buffer++);
-                       count--;
-               }
-               for (; i < bank->bus_width; ++i, ++copy_p)
-               {
-                       uint8_t byte;
-                       if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       cfi_add_byte(bank, current_word, byte);
-               }
-               retval = cfi_write_word(bank, current_word, write_p);
-               if (retval != ERROR_OK)
-                       return retval;
-       }
-
-       /* return to read array mode */
-       cfi_command(bank, 0xf0, current_word);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word)) != ERROR_OK)
-       {
-               return retval;
-       }
-       cfi_command(bank, 0xff, current_word);
-       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
-}
-
-static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *bank, void *param)
-{
-       (void) param;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-
-       pri_ext->_reversed_geometry = 1;
-}
-
-static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param)
-{
-       int i;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-       (void) param;
-
-       if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3))
-       {
-               LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device");
-
-               for (i = 0; i < cfi_info->num_erase_regions / 2; i++)
-               {
-                       int j = (cfi_info->num_erase_regions - 1) - i;
-                       uint32_t swap;
-
-                       swap = cfi_info->erase_region_info[i];
-                       cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j];
-                       cfi_info->erase_region_info[j] = swap;
-               }
-       }
-}
-
-static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct cfi_unlock_addresses *unlock_addresses = param;
-
-       pri_ext->_unlock1 = unlock_addresses->unlock1;
-       pri_ext->_unlock2 = unlock_addresses->unlock2;
-}
-
-
-static int cfi_query_string(struct flash_bank *bank, int address)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       int retval;
-       uint8_t command[8];
-
-       cfi_command(bank, 0x98, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, address), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
-       cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
-       cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
-
-       LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
-
-       if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
-       {
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               cfi_command(bank, 0xff, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               LOG_ERROR("Could not probe bank: no QRY");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_probe(struct flash_bank *bank)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint8_t command[8];
-       int num_sectors = 0;
-       int i;
-       int sector = 0;
-       uint32_t unlock1 = 0x555;
-       uint32_t unlock2 = 0x2aa;
-       int retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       cfi_info->probed = 0;
-
-       /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses,
-        * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa
-        */
-       if (cfi_info->jedec_probe)
-       {
-               unlock1 = 0x5555;
-               unlock2 = 0x2aaa;
-       }
-
-       /* switch to read identifier codes mode ("AUTOSELECT") */
-       cfi_command(bank, 0xaa, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-       cfi_command(bank, 0x55, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-       cfi_command(bank, 0x90, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       if (bank->chip_width == 1)
-       {
-               uint8_t manufacturer, device_id;
-               if ((retval = target_read_u8(target, flash_address(bank, 0, 0x00), &manufacturer)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = target_read_u8(target, flash_address(bank, 0, 0x01), &device_id)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               cfi_info->manufacturer = manufacturer;
-               cfi_info->device_id = device_id;
-       }
-       else if (bank->chip_width == 2)
-       {
-               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x00), &cfi_info->manufacturer)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x01), &cfi_info->device_id)) != ERROR_OK)
-               {
-                       return retval;
-               }
-       }
-
-       LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id);
-       /* switch back to read array mode */
-       cfi_command(bank, 0xf0, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-       cfi_command(bank, 0xff, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       /* check device/manufacturer ID for known non-CFI flashes. */
-       cfi_fixup_non_cfi(bank);
-
-       /* query only if this is a CFI compatible flash,
-        * otherwise the relevant info has already been filled in
-        */
-       if (cfi_info->not_cfi == 0)
-       {
-               int retval;
-
-               /* enter CFI query mode
-                * according to JEDEC Standard No. 68.01,
-                * a single bus sequence with address = 0x55, data = 0x98 should put
-                * the device into CFI query mode.
-                *
-                * SST flashes clearly violate this, and we will consider them incompatbile for now
-                */
-
-               retval = cfi_query_string(bank, 0x55);
-               if (retval != ERROR_OK)
-               {
-                       /*
-                        * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should
-                        * be harmless enough:
-                        *
-                        * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html
-                        */
-                       LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY.");
-                       retval = cfi_query_string(bank, 0x555);
-               }
-               if (retval != ERROR_OK)
-                       return retval;
-
-               cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
-               cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
-               cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
-               cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
-
-               LOG_DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
-
-               cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
-               cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
-               cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
-               cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
-               cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
-               cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
-               cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
-               cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
-               cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
-               cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
-               cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
-               cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
-
-               LOG_DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
-                       (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
-                       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
-                       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
-                       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
-               LOG_DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
-                       1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
-               LOG_DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
-                       (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
-                       (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
-                       (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
-
-               cfi_info->dev_size = 1 << cfi_query_u8(bank, 0, 0x27);
-               cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
-               cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
-               cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
-
-               LOG_DEBUG("size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: %x", cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
-
-               if (cfi_info->num_erase_regions)
-               {
-                       cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
-                       for (i = 0; i < cfi_info->num_erase_regions; i++)
-                       {
-                               cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
-                               LOG_DEBUG("erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "",
-                                         i,
-                                         (cfi_info->erase_region_info[i] & 0xffff) + 1,
-                                         (cfi_info->erase_region_info[i] >> 16) * 256);
-                       }
-               }
-               else
-               {
-                       cfi_info->erase_region_info = NULL;
-               }
-
-               /* We need to read the primary algorithm extended query table before calculating
-                * the sector layout to be able to apply fixups
-                */
-               switch (cfi_info->pri_id)
-               {
-                       /* Intel command set (standard and extended) */
-                       case 0x0001:
-                       case 0x0003:
-                               cfi_read_intel_pri_ext(bank);
-                               break;
-                       /* AMD/Spansion, Atmel, ... command set */
-                       case 0x0002:
-                               cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* default for all CFI flashs */
-                               cfi_read_0002_pri_ext(bank);
-                               break;
-                       default:
-                               LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                               break;
-               }
-
-               /* return to read array mode
-                * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
-                */
-               cfi_command(bank, 0xf0, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               cfi_command(bank, 0xff, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-       } /* end CFI case */
-
-       /* apply fixups depending on the primary command set */
-       switch (cfi_info->pri_id)
-       {
-               /* Intel command set (standard and extended) */
-               case 0x0001:
-               case 0x0003:
-                       cfi_fixup(bank, cfi_0001_fixups);
-                       break;
-               /* AMD/Spansion, Atmel, ... command set */
-               case 0x0002:
-                       cfi_fixup(bank, cfi_0002_fixups);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-
-       if ((cfi_info->dev_size * bank->bus_width / bank->chip_width) != bank->size)
-       {
-               LOG_WARNING("configuration specifies 0x%" PRIx32 " size, but a 0x%" PRIx32 " size flash was found", bank->size, cfi_info->dev_size);
-       }
-
-       if (cfi_info->num_erase_regions == 0)
-       {
-               /* a device might have only one erase block, spanning the whole device */
-               bank->num_sectors = 1;
-               bank->sectors = malloc(sizeof(struct flash_sector));
-
-               bank->sectors[sector].offset = 0x0;
-               bank->sectors[sector].size = bank->size;
-               bank->sectors[sector].is_erased = -1;
-               bank->sectors[sector].is_protected = -1;
-       }
-       else
-       {
-               uint32_t offset = 0;
-
-               for (i = 0; i < cfi_info->num_erase_regions; i++)
-               {
-                       num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
-               }
-
-               bank->num_sectors = num_sectors;
-               bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
-
-               for (i = 0; i < cfi_info->num_erase_regions; i++)
-               {
-                       uint32_t j;
-                       for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
-                       {
-                               bank->sectors[sector].offset = offset;
-                               bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width;
-                               offset += bank->sectors[sector].size;
-                               bank->sectors[sector].is_erased = -1;
-                               bank->sectors[sector].is_protected = -1;
-                               sector++;
-                       }
-               }
-               if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width))
-               {
-                       LOG_WARNING("CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \
-                               (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset);
-               }
-       }
-
-       cfi_info->probed = 1;
-
-       return ERROR_OK;
-}
-
-static int cfi_auto_probe(struct flash_bank *bank)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       if (cfi_info->probed)
-               return ERROR_OK;
-       return cfi_probe(bank);
-}
-
-
-static int cfi_intel_protect_check(struct flash_bank *bank)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct target *target = bank->target;
-       uint8_t command[CFI_MAX_BUS_WIDTH];
-       int i;
-
-       /* check if block lock bits are supported on this device */
-       if (!(pri_ext->blk_status_reg_mask & 0x1))
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       cfi_command(bank, 0x90, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               uint8_t block_status = cfi_get_u8(bank, i, 0x2);
-
-               if (block_status & 1)
-                       bank->sectors[i].is_protected = 1;
-               else
-                       bank->sectors[i].is_protected = 0;
-       }
-
-       cfi_command(bank, 0xff, command);
-       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-}
-
-static int cfi_spansion_protect_check(struct flash_bank *bank)
-{
-       int retval;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
-       struct target *target = bank->target;
-       uint8_t command[8];
-       int i;
-
-       cfi_command(bank, 0xaa, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       cfi_command(bank, 0x55, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       cfi_command(bank, 0x90, command);
-       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               uint8_t block_status = cfi_get_u8(bank, i, 0x2);
-
-               if (block_status & 1)
-                       bank->sectors[i].is_protected = 1;
-               else
-                       bank->sectors[i].is_protected = 0;
-       }
-
-       cfi_command(bank, 0xf0, command);
-       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-}
-
-static int cfi_protect_check(struct flash_bank *bank)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (cfi_info->qry[0] != 'Q')
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       switch (cfi_info->pri_id)
-       {
-               case 1:
-               case 3:
-                       return cfi_intel_protect_check(bank);
-                       break;
-               case 2:
-                       return cfi_spansion_protect_check(bank);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-
-       return ERROR_OK;
-}
-
-static int cfi_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       int printed;
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-
-       if (cfi_info->qry[0] == (char)-1)
-       {
-               printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
-               return ERROR_OK;
-       }
-
-       if (cfi_info->not_cfi == 0)
-               printed = snprintf(buf, buf_size, "\ncfi information:\n");
-       else
-               printed = snprintf(buf, buf_size, "\nnon-cfi flash:\n");
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf, buf_size, "\nmfr: 0x%4.4x, id:0x%4.4x\n",
-               cfi_info->manufacturer, cfi_info->device_id);
-       buf += printed;
-       buf_size -= printed;
-
-       if (cfi_info->not_cfi == 0)
-       {
-       printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
-       buf += printed;
-       buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n",
-                                  (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
-       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
-       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
-       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
-       buf += printed;
-       buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n",
-                                  1 << cfi_info->word_write_timeout_typ,
-                                  1 << cfi_info->buf_write_timeout_typ,
-                                  1 << cfi_info->block_erase_timeout_typ,
-                                  1 << cfi_info->chip_erase_timeout_typ);
-       buf += printed;
-       buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n",
-                                  (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
-                 (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
-                 (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
-                 (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
-       buf += printed;
-       buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: %x\n",
-                                  cfi_info->dev_size,
-                                  cfi_info->interface_desc,
-                                  1 << cfi_info->max_buf_write_size);
-       buf += printed;
-       buf_size -= printed;
-
-       switch (cfi_info->pri_id)
-       {
-               case 1:
-               case 3:
-                       cfi_intel_info(bank, buf, buf_size);
-                       break;
-               case 2:
-                       cfi_spansion_info(bank, buf, buf_size);
-                       break;
-               default:
-                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
-       }
-       }
-
-       return ERROR_OK;
-}
-
-struct flash_driver cfi_flash = {
-               .name = "cfi",
-               .flash_bank_command = &cfi_flash_bank_command,
-               .erase = &cfi_erase,
-               .protect = &cfi_protect,
-               .write = &cfi_write,
-               .probe = &cfi_probe,
-               .auto_probe = &cfi_auto_probe,
-               .erase_check = &default_flash_blank_check,
-               .protect_check = &cfi_protect_check,
-               .info = &cfi_info,
-       };
diff --git a/src/flash/cfi.h b/src/flash/cfi.h
deleted file mode 100644 (file)
index d55fd34..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef CFI_H
-#define CFI_H
-
-#include "flash.h"
-
-#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
-#define CFI_STATUS_POLL_MASK_DQ6_DQ7     0xC0 /* DQ6..DQ7 */
-
-struct cfi_flash_bank
-{
-       struct working_area *write_algorithm;
-
-       int x16_as_x8;
-       int jedec_probe;
-       int not_cfi;
-       int probed;
-
-       uint16_t manufacturer;
-       uint16_t device_id;
-
-       char qry[3];
-
-       /* identification string */
-       uint16_t pri_id;
-       uint16_t pri_addr;
-       uint16_t alt_id;
-       uint16_t alt_addr;
-
-       /* device-system interface */
-       uint8_t vcc_min;
-       uint8_t vcc_max;
-       uint8_t vpp_min;
-       uint8_t vpp_max;
-       uint8_t word_write_timeout_typ;
-       uint8_t buf_write_timeout_typ;
-       uint8_t block_erase_timeout_typ;
-       uint8_t chip_erase_timeout_typ;
-       uint8_t word_write_timeout_max;
-       uint8_t buf_write_timeout_max;
-       uint8_t block_erase_timeout_max;
-       uint8_t chip_erase_timeout_max;
-
-       uint8_t status_poll_mask;
-
-       /* flash geometry */
-       uint32_t dev_size;
-       uint16_t interface_desc;
-       uint16_t max_buf_write_size;
-       uint8_t num_erase_regions;
-       uint32_t *erase_region_info;
-
-       void *pri_ext;
-       void *alt_ext;
-};
-
-/* Intel primary extended query table
- * as defined for the Advanced+ Boot Block Flash Memory (C3)
- * and used by the linux kernel cfi driver (as of 2.6.14)
- */
-struct cfi_intel_pri_ext
-{
-       char pri[3];
-       uint8_t major_version;
-       uint8_t minor_version;
-       uint32_t feature_support;
-       uint8_t suspend_cmd_support;
-       uint16_t blk_status_reg_mask;
-       uint8_t vcc_optimal;
-       uint8_t vpp_optimal;
-       uint8_t num_protection_fields;
-       uint16_t prot_reg_addr;
-       uint8_t fact_prot_reg_size;
-       uint8_t user_prot_reg_size;
-       uint8_t extra[0];
-};
-
-/* Spansion primary extended query table as defined for and used by
- * the linux kernel cfi driver (as of 2.6.15)
- */
-struct cfi_spansion_pri_ext
-{
-       uint8_t  pri[3];
-       uint8_t  major_version;
-       uint8_t  minor_version;
-       uint8_t  SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
-       uint8_t  EraseSuspend;
-       uint8_t  BlkProt;
-       uint8_t  TmpBlkUnprotect;
-       uint8_t  BlkProtUnprot;
-       uint8_t  SimultaneousOps;
-       uint8_t  BurstMode;
-       uint8_t  PageMode;
-       uint8_t  VppMin;
-       uint8_t  VppMax;
-       uint8_t  TopBottom;
-       int _reversed_geometry;
-       uint32_t _unlock1;
-       uint32_t _unlock2;
-};
-
-/* Atmel primary extended query table as defined for and used by
- * the linux kernel cfi driver (as of 2.6.20+)
- */
-struct cfi_atmel_pri_ext
-{
-       uint8_t pri[3];
-       uint8_t major_version;
-       uint8_t minor_version;
-       uint8_t features;
-       uint8_t bottom_boot;
-       uint8_t burst_mode;
-       uint8_t page_mode;
-};
-
-enum {
-       CFI_UNLOCK_555_2AA,
-       CFI_UNLOCK_5555_2AAA,
-};
-
-struct cfi_unlock_addresses
-{
-       uint32_t unlock1;
-       uint32_t unlock2;
-};
-
-struct cfi_fixup
-{
-       uint16_t mfr;
-       uint16_t id;
-       void (*fixup)(struct flash_bank *flash, void *param);
-       void *param;
-};
-
-#define CFI_MFR_AMD            0x0001
-#define CFI_MFR_FUJITSU        0x0004
-#define CFI_MFR_ATMEL  0x001F
-#define CFI_MFR_ST             0x0020  /* STMicroelectronics */
-#define CFI_MFR_AMIC   0x0037
-#define CFI_MFR_SST            0x00BF
-#define CFI_MFR_MX             0x00C2
-
-#define CFI_MFR_ANY            0xffff
-#define CFI_ID_ANY             0xffff
-
-#endif /* CFI_H */
diff --git a/src/flash/ecos.c b/src/flash/ecos.c
deleted file mode 100644 (file)
index 7a0b26f..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
- *   oyvind.harboe@zylin.com                                               *
- *                                                                         *
- *   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 "flash.h"
-#include "embeddedice.h"
-#include "image.h"
-#include "algorithm.h"
-
-
-#if 0
-static uint32_t ecosflash_get_flash_status(struct flash_bank *bank);
-static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode);
-static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
-static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc);
-#endif
-
-struct ecosflash_flash_bank
-{
-       struct target *target;
-       struct working_area *write_algorithm;
-       struct working_area *erase_check_algorithm;
-       char *driverPath;
-       uint32_t start_address;
-};
-
-static const int sectorSize = 0x10000;
-
-char *
-flash_errmsg(int err);
-
-#ifndef __ECOS
-#define FLASH_ERR_OK              0x00  /* No error - operation complete */
-#define FLASH_ERR_INVALID         0x01  /* Invalid FLASH address */
-#define FLASH_ERR_ERASE           0x02  /* Error trying to erase */
-#define FLASH_ERR_LOCK            0x03  /* Error trying to lock/unlock */
-#define FLASH_ERR_PROGRAM         0x04  /* Error trying to program */
-#define FLASH_ERR_PROTOCOL        0x05  /* Generic error */
-#define FLASH_ERR_PROTECT         0x06  /* Device/region is write-protected */
-#define FLASH_ERR_NOT_INIT        0x07  /* FLASH info not yet initialized */
-#define FLASH_ERR_HWR             0x08  /* Hardware (configuration?) problem */
-#define FLASH_ERR_ERASE_SUSPEND   0x09  /* Device is in erase suspend mode */
-#define FLASH_ERR_PROGRAM_SUSPEND 0x0a  /* Device is in in program suspend mode */
-#define FLASH_ERR_DRV_VERIFY      0x0b  /* Driver failed to verify data */
-#define FLASH_ERR_DRV_TIMEOUT     0x0c  /* Driver timed out waiting for device */
-#define FLASH_ERR_DRV_WRONG_PART  0x0d  /* Driver does not support device */
-#define FLASH_ERR_LOW_VOLTAGE     0x0e  /* Not enough juice to complete job */
-
-char *
-flash_errmsg(int err)
-{
-       switch (err) {
-       case FLASH_ERR_OK:
-               return "No error - operation complete";
-       case FLASH_ERR_ERASE_SUSPEND:
-               return "Device is in erase suspend state";
-       case FLASH_ERR_PROGRAM_SUSPEND:
-               return "Device is in program suspend state";
-       case FLASH_ERR_INVALID:
-               return "Invalid FLASH address";
-       case FLASH_ERR_ERASE:
-               return "Error trying to erase";
-       case FLASH_ERR_LOCK:
-               return "Error trying to lock/unlock";
-       case FLASH_ERR_PROGRAM:
-               return "Error trying to program";
-       case FLASH_ERR_PROTOCOL:
-               return "Generic error";
-       case FLASH_ERR_PROTECT:
-               return "Device/region is write-protected";
-       case FLASH_ERR_NOT_INIT:
-               return "FLASH sub-system not initialized";
-       case FLASH_ERR_DRV_VERIFY:
-               return "Data verify failed after operation";
-       case FLASH_ERR_DRV_TIMEOUT:
-               return "Driver timed out waiting for device";
-       case FLASH_ERR_DRV_WRONG_PART:
-               return "Driver does not support device";
-       case FLASH_ERR_LOW_VOLTAGE:
-               return "Device reports low voltage";
-       default:
-               return "Unknown error";
-       }
-}
-#endif
-
-/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>
- */
-FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
-{
-       struct ecosflash_flash_bank *info;
-
-       if (CMD_ARGC < 7)
-       {
-               LOG_WARNING("incomplete flash_bank ecosflash configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       info = malloc(sizeof(struct ecosflash_flash_bank));
-       if (info == NULL)
-       {
-               LOG_ERROR("no memory for flash bank info");
-               exit(-1);
-       }
-       bank->driver_priv = info;
-       info->driverPath = strdup(CMD_ARGV[6]);
-
-       /* eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as
-        * a way to improve impedance match between OpenOCD and eCos flash
-        * driver.
-        */
-       int i = 0;
-       uint32_t offset = 0;
-       bank->num_sectors = bank->size/sectorSize;
-       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 = sectorSize;
-               offset += bank->sectors[i].size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 0;
-       }
-
-       info->target = get_target(CMD_ARGV[5]);
-       if (info->target == NULL)
-       {
-               LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
-               return ERROR_FAIL;
-       }
-       return ERROR_OK;
-}
-
-static int loadDriver(struct ecosflash_flash_bank *info)
-{
-       size_t buf_cnt;
-       size_t image_size;
-       struct image image;
-
-       image.base_address_set = 0;
-       image.start_address_set = 0;
-       struct target *target = info->target;
-       int retval;
-
-       if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       info->start_address = image.start_address;
-
-       image_size = 0x0;
-       int i;
-       for (i = 0; i < image.num_sections; i++)
-       {
-               void *buffer = malloc(image.sections[i].size);
-               int retval;
-               if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
-               {
-                       free(buffer);
-                       image_close(&image);
-                       return retval;
-               }
-               target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
-               image_size += buf_cnt;
-               LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "",
-                               buf_cnt, image.sections[i].base_address);
-
-               free(buffer);
-       }
-
-       image_close(&image);
-
-       return ERROR_OK;
-}
-
-static int const OFFSET_ERASE = 0x0;
-static int const OFFSET_ERASE_SIZE = 0x8;
-static int const OFFSET_FLASH = 0xc;
-static int const OFFSET_FLASH_SIZE = 0x8;
-static int const OFFSET_GET_WORKAREA = 0x18;
-static int const OFFSET_GET_WORKAREA_SIZE = 0x4;
-
-static int runCode(struct ecosflash_flash_bank *info,
-               uint32_t codeStart, uint32_t codeStop, uint32_t r0, uint32_t r1, uint32_t r2,
-               uint32_t *result,
-               /* timeout in ms */
-               int timeout)
-{
-       struct target *target = info->target;
-
-       struct reg_param reg_params[3];
-       struct armv4_5_algorithm armv4_5_info;
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-
-       buf_set_u32(reg_params[0].value, 0, 32, r0);
-       buf_set_u32(reg_params[1].value, 0, 32, r1);
-       buf_set_u32(reg_params[2].value, 0, 32, r2);
-
-       int retval;
-       if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
-                       codeStart,
-                       codeStop, timeout,
-                       &armv4_5_info)) != ERROR_OK)
-       {
-               LOG_ERROR("error executing eCos flash algorithm");
-               return retval;
-       }
-
-       *result = buf_get_u32(reg_params[0].value, 0, 32);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-
-       return ERROR_OK;
-}
-
-static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address, uint32_t len)
-{
-       int retval;
-       int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/
-
-       retval = loadDriver(info);
-       if (retval != ERROR_OK)
-               return retval;
-
-       uint32_t flashErr;
-       retval = runCode(info,
-                       info->start_address + OFFSET_ERASE,
-                       info->start_address + OFFSET_ERASE + OFFSET_ERASE_SIZE,
-                       address,
-                       len,
-                       0,
-                       &flashErr,
-                       timeout
-);
-       if (retval != ERROR_OK)
-               return retval;
-
-       if (flashErr != 0x0)
-       {
-               LOG_ERROR("Flash erase failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
-               return ERROR_FAIL;
-       }
-
-       return ERROR_OK;
-}
-
-static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32_t address, uint32_t len)
-{
-       struct target *target = info->target;
-       const int chunk = 8192;
-       int retval = ERROR_OK;
-       int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/
-
-       retval = loadDriver(info);
-       if (retval != ERROR_OK)
-               return retval;
-
-       uint32_t buffer;
-       retval = runCode(info,
-                       info->start_address + OFFSET_GET_WORKAREA,
-                       info->start_address + OFFSET_GET_WORKAREA + OFFSET_GET_WORKAREA_SIZE,
-                       0,
-                       0,
-                       0,
-                       &buffer,
-                       1000);
-       if (retval != ERROR_OK)
-               return retval;
-
-
-       uint32_t i;
-       for (i = 0; i < len; i += chunk)
-       {
-               int t = len-i;
-               if (t > chunk)
-               {
-                       t = chunk;
-               }
-
-               int retval;
-               retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
-               if (retval != ERROR_OK)
-                       return retval;
-
-               uint32_t flashErr;
-               retval = runCode(info,
-                               info->start_address + OFFSET_FLASH,
-                               info->start_address + OFFSET_FLASH + OFFSET_FLASH_SIZE,
-                               buffer,
-                               address + i,
-                               t,
-                               &flashErr,
-                               timeout);
-               if (retval != ERROR_OK)
-                       return retval;
-
-               if (flashErr != 0x0)
-               {
-                       LOG_ERROR("Flash prog failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
-                       return ERROR_FAIL;
-               }
-       }
-       return ERROR_OK;
-}
-
-static int ecosflash_probe(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-#if 0
-static void command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
-{
-       struct ecosflash_flash_bank *info = bank->driver_priv;
-       int i;
-
-       if (info->target->endianness == TARGET_LITTLE_ENDIAN)
-       {
-               for (i = bank->bus_width; i > 0; i--)
-               {
-                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
-               }
-       }
-       else
-       {
-               for (i = 1; i <= bank->bus_width; i++)
-               {
-                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
-               }
-       }
-}
-#endif
-
-#if 0
-static uint32_t ecosflash_address(struct flash_bank *bank, uint32_t address)
-{
-       uint32_t retval = 0;
-       switch (bank->bus_width)
-       {
-               case 4:
-                       retval = address & 0xfffffffc;
-               case 2:
-                       retval = address & 0xfffffffe;
-               case 1:
-                       retval = address;
-       }
-
-       return retval + bank->base;
-}
-#endif
-
-static int ecosflash_erase(struct flash_bank *bank, int first, int last)
-{
-       struct flash_bank *c = bank;
-       struct ecosflash_flash_bank *info = bank->driver_priv;
-       return eCosBoard_erase(info, c->base + first*sectorSize, sectorSize*(last-first + 1));
-}
-
-static int ecosflash_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       return ERROR_OK;
-}
-
-static int ecosflash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct ecosflash_flash_bank *info = bank->driver_priv;
-       struct flash_bank *c = bank;
-       return eCosBoard_flash(info, buffer, c->base + offset, count);
-}
-
-static int ecosflash_protect_check(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-static int ecosflash_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       struct ecosflash_flash_bank *info = bank->driver_priv;
-       snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);
-       return ERROR_OK;
-}
-
-#if 0
-static uint32_t ecosflash_get_flash_status(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode)
-{
-
-}
-
-static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
-{
-       return ERROR_OK;
-}
-
-static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc)
-{
-       return ERROR_OK;
-}
-#endif
-
-struct flash_driver ecosflash_flash = {
-               .name = "ecosflash",
-               .flash_bank_command = &ecosflash_flash_bank_command,
-               .erase = &ecosflash_erase,
-               .protect = &ecosflash_protect,
-               .write = &ecosflash_write,
-               .probe = &ecosflash_probe,
-               .auto_probe = &ecosflash_probe,
-               .erase_check = &default_flash_blank_check,
-               .protect_check = &ecosflash_protect_check,
-               .info = &ecosflash_info
-       };
diff --git a/src/flash/faux.c b/src/flash/faux.c
deleted file mode 100644 (file)
index caec2c7..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2009 Ã˜yvind Harboe                                      *
- *   oyvind.harboe@zylin.com                                               *
- *                                                                         *
- *   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 "flash.h"
-#include "image.h"
-#include "../hello.h"
-
-
-struct faux_flash_bank
-{
-       struct target *target;
-       uint8_t *memory;
-       uint32_t start_address;
-};
-
-static const int sectorSize = 0x10000;
-
-
-/* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath>
- */
-FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
-{
-       struct faux_flash_bank *info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank faux configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       info = malloc(sizeof(struct faux_flash_bank));
-       if (info == NULL)
-       {
-               LOG_ERROR("no memory for flash bank info");
-               return ERROR_FAIL;
-       }
-       info->memory = malloc(bank->size);
-       if (info == NULL)
-       {
-               free(info);
-               LOG_ERROR("no memory for flash bank info");
-               return ERROR_FAIL;
-       }
-       bank->driver_priv = info;
-
-       /* Use 0x10000 as a fixed sector size. */
-       int i = 0;
-       uint32_t offset = 0;
-       bank->num_sectors = bank->size/sectorSize;
-       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 = sectorSize;
-               offset += bank->sectors[i].size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 0;
-       }
-
-       info->target = get_target(CMD_ARGV[5]);
-       if (info->target == NULL)
-       {
-               LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
-               free(info->memory);
-               free(info);
-               return ERROR_FAIL;
-       }
-       return ERROR_OK;
-}
-
-static int faux_erase(struct flash_bank *bank, int first, int last)
-{
-       struct faux_flash_bank *info = bank->driver_priv;
-       memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1));
-       return ERROR_OK;
-}
-
-static int faux_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       LOG_USER("set protection sector %d to %d to %s", first, last, set?"on":"off");
-       return ERROR_OK;
-}
-
-static int faux_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct faux_flash_bank *info = bank->driver_priv;
-       memcpy(info->memory + offset, buffer, count);
-       return ERROR_OK;
-}
-
-static int faux_protect_check(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-static int faux_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "faux flash driver");
-       return ERROR_OK;
-}
-
-static int faux_probe(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-static const struct command_registration faux_command_handlers[] = {
-       {
-               .name = "faux",
-               .mode = COMMAND_ANY,
-               .help = "faux flash command group",
-               .chain = hello_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver faux_flash = {
-               .name = "faux",
-               .commands = faux_command_handlers,
-               .flash_bank_command = &faux_flash_bank_command,
-               .erase = &faux_erase,
-               .protect = &faux_protect,
-               .write = &faux_write,
-               .probe = &faux_probe,
-               .auto_probe = &faux_probe,
-               .erase_check = &default_flash_blank_check,
-               .protect_check = &faux_protect_check,
-               .info = &faux_info
-       };
diff --git a/src/flash/lpc2000.c b/src/flash/lpc2000.c
deleted file mode 100644 (file)
index 418b5b0..0000000
+++ /dev/null
@@ -1,812 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius            *
- *   didele.deze@gmail.com                                                 *
- *                                                                         *
- *   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 "lpc2000.h"
-#include "armv7m.h"
-#include "binarybuffer.h"
-#include "algorithm.h"
-
-
-/* flash programming support for NXP LPC17xx and LPC2xxx devices
- * currently supported devices:
- * variant 1 (lpc2000_v1):
- * - 2104 | 5 | 6
- * - 2114 | 9
- * - 2124 | 9
- * - 2194
- * - 2212 | 4
- * - 2292 | 4
- *
- * variant 2 (lpc2000_v2):
- * - 213x
- * - 214x
- * - 2101 | 2 | 3
- * - 2364 | 6 | 8
- * - 2378
- *
- * lpc1700:
- * - 175x
- * - 176x (tested with LPC1768)
- */
-
-static int lpc2000_build_sector_list(struct flash_bank *bank)
-{
-       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
-       int i;
-       uint32_t offset = 0;
-
-       /* default to a 4096 write buffer */
-       lpc2000_info->cmd51_max_buffer = 4096;
-
-       if (lpc2000_info->variant == lpc2000_v1)
-       {
-               /* variant 1 has different layout for 128kb and 256kb flashes */
-               if (bank->size == 128 * 1024)
-               {
-                       bank->num_sectors = 16;
-                       bank->sectors = malloc(sizeof(struct flash_sector) * 16);
-                       for (i = 0; i < 16; i++)
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 8 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-               }
-               else if (bank->size == 256 * 1024)
-               {
-                       bank->num_sectors = 18;
-                       bank->sectors = malloc(sizeof(struct flash_sector) * 18);
-
-                       for (i = 0; i < 8; i++)
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 8 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-                       for (i = 8; i < 10; i++)
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 64 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-                       for (i = 10; i < 18; i++)
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 8 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-               }
-               else
-               {
-                       LOG_ERROR("BUG: unknown bank->size encountered");
-                       exit(-1);
-               }
-       }
-       else if (lpc2000_info->variant == lpc2000_v2)
-       {
-               /* variant 2 has a uniform layout, only number of sectors differs */
-               switch (bank->size)
-               {
-                       case 4 * 1024:
-                               lpc2000_info->cmd51_max_buffer = 1024;
-                               bank->num_sectors = 1;
-                               break;
-                       case 8 * 1024:
-                               lpc2000_info->cmd51_max_buffer = 1024;
-                               bank->num_sectors = 2;
-                               break;
-                       case 16 * 1024:
-                               bank->num_sectors = 4;
-                               break;
-                       case 32 * 1024:
-                               bank->num_sectors = 8;
-                               break;
-                       case 64 * 1024:
-                               bank->num_sectors = 9;
-                               break;
-                       case 128 * 1024:
-                               bank->num_sectors = 11;
-                               break;
-                       case 256 * 1024:
-                               bank->num_sectors = 15;
-                               break;
-                       case 512 * 1024:
-                       case 500 * 1024:
-                               bank->num_sectors = 27;
-                               break;
-                       default:
-                               LOG_ERROR("BUG: unknown bank->size encountered");
-                               exit(-1);
-                               break;
-               }
-
-               bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
-
-               for (i = 0; i < bank->num_sectors; i++)
-               {
-                       if ((i >= 0) && (i < 8))
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 4 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-                       if ((i >= 8) && (i < 22))
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 32 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-                       if ((i >= 22) && (i < 27))
-                       {
-                               bank->sectors[i].offset = offset;
-                               bank->sectors[i].size = 4 * 1024;
-                               offset += bank->sectors[i].size;
-                               bank->sectors[i].is_erased = -1;
-                               bank->sectors[i].is_protected = 1;
-                       }
-               }
-       }
-       else if (lpc2000_info->variant == lpc1700)
-       {
-               switch(bank->size)
-               {
-                       case 32 * 1024:
-                               bank->num_sectors = 8;
-                               break;
-                       case 64 * 1024:
-                               bank->num_sectors = 16;
-                               break;
-                       case 128 * 1024:
-                               bank->num_sectors = 18;
-                               break;
-                       case 256 * 1024:
-                               bank->num_sectors = 22;
-                               break;
-                       case 512 * 1024:
-                               bank->num_sectors = 30;
-                               break;
-                       default:
-                               LOG_ERROR("BUG: unknown bank->size encountered");
-                               exit(-1);
-               }
-
-               bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
-
-               for(i = 0; i < bank->num_sectors; i++)
-               {
-                       bank->sectors[i].offset = offset;
-                       /* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
-                       bank->sectors[i].size = (i < 16)? 4 * 1024 : 32 * 1024;
-                       offset += bank->sectors[i].size;
-                       bank->sectors[i].is_erased = -1;
-                       bank->sectors[i].is_protected = 1;
-               }
-       }
-       else
-       {
-               LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
-               exit(-1);
-       }
-
-       return ERROR_OK;
-}
-
-/* call LPC1700/LPC2000 IAP function
- * uses 180 bytes working area
- * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
- * 0x8 to 0x1f: command parameter table (1+5 words)
- * 0x20 to 0x33: command result table (1+4 words)
- * 0x34 to 0xb3: stack (only 128b needed)
- */
-static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
-{
-       int retval;
-       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
-       struct target *target = bank->target;
-       struct mem_param mem_params[2];
-       struct reg_param reg_params[5];
-       struct armv4_5_algorithm armv4_5_info; /* for LPC2000 */
-       struct armv7m_algorithm armv7m_info;   /* for LPC1700 */
-       uint32_t status_code;
-       uint32_t iap_entry_point = 0; /* to make compiler happier */
-
-       /* regrab previously allocated working_area, or allocate a new one */
-       if (!lpc2000_info->iap_working_area)
-       {
-               uint8_t jump_gate[8];
-
-               /* make sure we have a working area */
-               if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK)
-               {
-                       LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               /* write IAP code to working area */
-               switch(lpc2000_info->variant)
-               {
-                       case lpc1700:
-                               target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
-                               target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
-                               break;
-                       case lpc2000_v1:
-                       case lpc2000_v2:
-                               target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
-                               target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
-                               break;
-                       default:
-                               LOG_ERROR("BUG: unknown bank->size encountered");
-                               exit(-1);
-               }
-
-               if ((retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
-               {
-                       LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address);
-                       return retval;
-               }
-       }
-
-       switch(lpc2000_info->variant)
-       {
-               case lpc1700:
-                       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
-                       armv7m_info.core_mode = ARMV7M_MODE_ANY;
-                       iap_entry_point = 0x1fff1ff1;
-                       break;
-               case lpc2000_v1:
-               case lpc2000_v2:
-                       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-                       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-                       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-                       iap_entry_point = 0x7ffffff1;
-                       break;
-               default:
-                       LOG_ERROR("BUG: unknown lpc2000->variant encountered");
-                       exit(-1);
-       }
-
-       /* command parameter table */
-       init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT);
-       target_buffer_set_u32(target, mem_params[0].value, code);
-       target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
-       target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
-       target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]);
-       target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);
-       target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);
-
-       /* command result table */
-       init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN);
-
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
-
-       /* IAP entry point */
-       init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);
-       buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
-
-       switch(lpc2000_info->variant)
-       {
-               case lpc1700:
-                       /* IAP stack */
-                       init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
-                       buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
-
-                       /* return address */
-                       init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
-                       buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
-
-                       target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
-                       break;
-               case lpc2000_v1:
-               case lpc2000_v2:
-                       /* IAP stack */
-                       init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);
-                       buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
-
-                       /* return address */
-                       init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
-                       buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04);
-
-                       target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
-                       break;
-               default:
-                       LOG_ERROR("BUG: unknown lpc2000->variant encountered");
-                       exit(-1);
-       }
-
-
-       status_code     = target_buffer_get_u32(target, mem_params[1].value);
-       result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
-       result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
-       result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
-       result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);
-
-       LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32") completed with result = %8.8" PRIx32,
-                         code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);
-
-       destroy_mem_param(&mem_params[0]);
-       destroy_mem_param(&mem_params[1]);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-       destroy_reg_param(&reg_params[4]);
-
-       return status_code;
-}
-
-static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
-{
-       uint32_t param_table[5];
-       uint32_t result_table[4];
-       int status_code;
-       int i;
-
-       if ((first < 0) || (last >= bank->num_sectors))
-               return ERROR_FLASH_SECTOR_INVALID;
-
-       for (i = first; i <= last; i++)
-       {
-               /* check single sector */
-               param_table[0] = param_table[1] = i;
-               status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
-
-               switch (status_code)
-               {
-                       case ERROR_FLASH_OPERATION_FAILED:
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       case LPC2000_CMD_SUCCESS:
-                               bank->sectors[i].is_erased = 1;
-                               break;
-                       case LPC2000_SECTOR_NOT_BLANK:
-                               bank->sectors[i].is_erased = 0;
-                               break;
-                       case LPC2000_INVALID_SECTOR:
-                               bank->sectors[i].is_erased = 0;
-                               break;
-                       case LPC2000_BUSY:
-                               return ERROR_FLASH_BUSY;
-                               break;
-                       default:
-                               LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code);
-                               exit(-1);
-               }
-       }
-
-       return ERROR_OK;
-}
-
-/*
- * flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
- */
-FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
-{
-       struct lpc2000_flash_bank *lpc2000_info;
-
-       if (CMD_ARGC < 8)
-       {
-               LOG_WARNING("incomplete flash_bank lpc2000 configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
-       bank->driver_priv = lpc2000_info;
-
-       if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0)
-       {
-               lpc2000_info->variant = lpc2000_v1;
-               lpc2000_info->cmd51_dst_boundary = 512;
-               lpc2000_info->cmd51_can_256b = 0;
-               lpc2000_info->cmd51_can_8192b = 1;
-               lpc2000_info->checksum_vector = 5;
-       }
-       else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0)
-       {
-               lpc2000_info->variant = lpc2000_v2;
-               lpc2000_info->cmd51_dst_boundary = 256;
-               lpc2000_info->cmd51_can_256b = 1;
-               lpc2000_info->cmd51_can_8192b = 0;
-               lpc2000_info->checksum_vector = 5;
-       }
-       else if (strcmp(CMD_ARGV[6], "lpc1700") == 0)
-       {
-               lpc2000_info->variant = lpc1700;
-               lpc2000_info->cmd51_dst_boundary = 256;
-               lpc2000_info->cmd51_can_256b = 1;
-               lpc2000_info->cmd51_can_8192b = 0;
-               lpc2000_info->checksum_vector = 7;
-       }
-       else
-       {
-               LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
-               free(lpc2000_info);
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       lpc2000_info->iap_working_area = NULL;
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk);
-       lpc2000_info->calc_checksum = 0;
-       lpc2000_build_sector_list(bank);
-
-       if (CMD_ARGC >= 9)
-       {
-               if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
-                       lpc2000_info->calc_checksum = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static int lpc2000_erase(struct flash_bank *bank, int first, int last)
-{
-       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
-       uint32_t param_table[5];
-       uint32_t result_table[4];
-       int status_code;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       param_table[0] = first;
-       param_table[1] = last;
-       param_table[2] = lpc2000_info->cclk;
-
-       /* Prepare sectors */
-       status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
-       switch (status_code)
-       {
-               case ERROR_FLASH_OPERATION_FAILED:
-                       return ERROR_FLASH_OPERATION_FAILED;
-               case LPC2000_CMD_SUCCESS:
-                       break;
-               case LPC2000_INVALID_SECTOR:
-                       return ERROR_FLASH_SECTOR_INVALID;
-                       break;
-               default:
-                       LOG_WARNING("lpc2000 prepare sectors returned %i", status_code);
-                       return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Erase sectors */
-       status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
-       switch (status_code)
-       {
-               case ERROR_FLASH_OPERATION_FAILED:
-                       return ERROR_FLASH_OPERATION_FAILED;
-               case LPC2000_CMD_SUCCESS:
-                       break;
-               case LPC2000_INVALID_SECTOR:
-                       return ERROR_FLASH_SECTOR_INVALID;
-                       break;
-               default:
-                       LOG_WARNING("lpc2000 erase sectors returned %i", status_code);
-                       return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       /* can't protect/unprotect on the lpc2000 */
-       return ERROR_OK;
-}
-
-static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t dst_min_alignment;
-       uint32_t bytes_remaining = count;
-       uint32_t bytes_written = 0;
-       int first_sector = 0;
-       int last_sector = 0;
-       uint32_t param_table[5];
-       uint32_t result_table[4];
-       int status_code;
-       int i;
-       struct working_area *download_area;
-       int retval = ERROR_OK;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset + count > bank->size)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       dst_min_alignment = lpc2000_info->cmd51_dst_boundary;
-
-       if (offset % dst_min_alignment)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               if (offset >= bank->sectors[i].offset)
-                       first_sector = i;
-               if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
-                       last_sector = i;
-       }
-
-       LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
-
-       /* check if exception vectors should be flashed */
-       if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
-       {
-               uint32_t checksum = 0;
-               int i;
-               for (i = 0; i < 8; i++)
-               {
-                       LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
-                       if (i != lpc2000_info->checksum_vector)
-                               checksum += buf_get_u32(buffer + (i * 4), 0, 32);
-               }
-               checksum = 0 - checksum;
-               LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
-
-               uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32);
-               if (original_value != checksum)
-               {
-                       LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is different from calculated vector checksum (0x%8.8" PRIx32 ").",
-                                       original_value, checksum);
-                       LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
-               }
-
-               buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum);
-       }
-
-       /* allocate a working area */
-       if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK)
-       {
-               LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       while (bytes_remaining > 0)
-       {
-               uint32_t thisrun_bytes;
-               if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
-                       thisrun_bytes = lpc2000_info->cmd51_max_buffer;
-               else if (bytes_remaining >= 1024)
-                       thisrun_bytes = 1024;
-               else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
-                       thisrun_bytes = 512;
-               else
-                       thisrun_bytes = 256;
-
-               /* Prepare sectors */
-               param_table[0] = first_sector;
-               param_table[1] = last_sector;
-               status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
-               switch (status_code)
-               {
-                       case ERROR_FLASH_OPERATION_FAILED:
-                               retval = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-                       case LPC2000_CMD_SUCCESS:
-                               break;
-                       case LPC2000_INVALID_SECTOR:
-                               retval = ERROR_FLASH_SECTOR_INVALID;
-                               break;
-                       default:
-                               LOG_WARNING("lpc2000 prepare sectors returned %i", status_code);
-                               retval = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-               }
-
-               /* Exit if error occured */
-               if (retval != ERROR_OK)
-                       break;
-
-               if (bytes_remaining >= thisrun_bytes)
-               {
-                       if ((retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written)) != ERROR_OK)
-                       {
-                               retval = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-                       }
-               }
-               else
-               {
-                       uint8_t *last_buffer = malloc(thisrun_bytes);
-                       memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
-                       memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining);
-                       target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
-                       free(last_buffer);
-               }
-
-               LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32 , thisrun_bytes, bank->base + offset + bytes_written);
-
-               /* Write data */
-               param_table[0] = bank->base + offset + bytes_written;
-               param_table[1] = download_area->address;
-               param_table[2] = thisrun_bytes;
-               param_table[3] = lpc2000_info->cclk;
-               status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
-               switch (status_code)
-               {
-                       case ERROR_FLASH_OPERATION_FAILED:
-                               retval = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-                       case LPC2000_CMD_SUCCESS:
-                               break;
-                       case LPC2000_INVALID_SECTOR:
-                               retval = ERROR_FLASH_SECTOR_INVALID;
-                               break;
-                       default:
-                               LOG_WARNING("lpc2000 returned %i", status_code);
-                               retval = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-               }
-
-               /* Exit if error occured */
-               if (retval != ERROR_OK)
-                       break;
-
-               if (bytes_remaining > thisrun_bytes)
-                       bytes_remaining -= thisrun_bytes;
-               else
-                       bytes_remaining = 0;
-               bytes_written += thisrun_bytes;
-       }
-
-       target_free_working_area(target, download_area);
-
-       return retval;
-}
-
-static int lpc2000_probe(struct flash_bank *bank)
-{
-       /* we can't probe on an lpc2000
-        * if this is an lpc2xxx, it has the configured flash
-        */
-       return ERROR_OK;
-}
-
-static int lpc2000_erase_check(struct flash_bank *bank)
-{
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-static int lpc2000_protect_check(struct flash_bank *bank)
-{
-       /* sectors are always protected */
-       return ERROR_OK;
-}
-
-static int lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
-
-       snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(lpc2000_handle_part_id_command)
-{
-       uint32_t param_table[5];
-       uint32_t result_table[4];
-       int status_code;
-
-       if (CMD_ARGC < 1)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
-       {
-               if (status_code == ERROR_FLASH_OPERATION_FAILED)
-               {
-                       command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface");
-                       return ERROR_OK;
-               }
-               command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code);
-       }
-       else
-       {
-               command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
-       }
-
-       return ERROR_OK;
-}
-
-static const struct command_registration lpc2000_exec_command_handlers[] = {
-       {
-               .name = "part_id",
-               .handler = &lpc2000_handle_part_id_command,
-               .mode = COMMAND_EXEC,
-               .help = "print part id of lpc2000 flash bank <num>",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration lpc2000_command_handlers[] = {
-       {
-               .name = "lpc2000",
-               .mode = COMMAND_ANY,
-               .help = "lpc2000 flash command group",
-               .chain = lpc2000_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver lpc2000_flash = {
-               .name = "lpc2000",
-               .commands = lpc2000_command_handlers,
-               .flash_bank_command = &lpc2000_flash_bank_command,
-               .erase = &lpc2000_erase,
-               .protect = &lpc2000_protect,
-               .write = &lpc2000_write,
-               .probe = &lpc2000_probe,
-               .auto_probe = &lpc2000_probe,
-               .erase_check = &lpc2000_erase_check,
-               .protect_check = &lpc2000_protect_check,
-               .info = &lpc2000_info,
-       };
-
-
diff --git a/src/flash/lpc2000.h b/src/flash/lpc2000.h
deleted file mode 100644 (file)
index 08e278a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius            *
- *   didele.deze@gmail.com                                                 *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef LPC2000_H
-#define LPC2000_H
-
-#include "flash.h"
-
-typedef enum
-{
-       lpc2000_v1,
-       lpc2000_v2,
-       lpc1700
-} lpc2000_variant;
-
-struct lpc2000_flash_bank
-{
-       lpc2000_variant variant;
-       struct working_area *iap_working_area;
-       uint32_t cclk;
-       int cmd51_dst_boundary;
-       int cmd51_can_256b;
-       int cmd51_can_8192b;
-       int calc_checksum;
-       uint32_t cmd51_max_buffer;
-       int checksum_vector;
-};
-
-enum lpc2000_status_codes
-{
-       LPC2000_CMD_SUCCESS = 0,
-       LPC2000_INVALID_COMMAND = 1,
-       LPC2000_SRC_ADDR_ERROR = 2,
-       LPC2000_DST_ADDR_ERROR = 3,
-       LPC2000_SRC_ADDR_NOT_MAPPED = 4,
-       LPC2000_DST_ADDR_NOT_MAPPED = 5,
-       LPC2000_COUNT_ERROR = 6,
-       LPC2000_INVALID_SECTOR = 7,
-       LPC2000_SECTOR_NOT_BLANK = 8,
-       LPC2000_SECTOR_NOT_PREPARED = 9,
-       LPC2000_COMPARE_ERROR = 10,
-       LPC2000_BUSY = 11,
-       LPC2000_PARAM_ERROR = 12,
-       LPC2000_ADDR_ERROR = 13,
-       LPC2000_ADDR_NOT_MAPPED = 14,
-       LPC2000_CMD_NOT_LOCKED = 15,
-       LPC2000_INVALID_CODE = 16,
-       LPC2000_INVALID_BAUD_RATE = 17,
-       LPC2000_INVALID_STOP_BIT = 18,
-       LPC2000_CRP_ENABLED = 19
-
-};
-
-#endif /* LPC2000_H */
diff --git a/src/flash/lpc288x.c b/src/flash/lpc288x.c
deleted file mode 100644 (file)
index 446fc9d..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2008 by                                                            *
- *   Karl RobinSod <karl.robinsod@gmail.com>                               *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-
-/***************************************************************************
-* There are some things to notice
-*
-* You need to unprotect flash sectors each time you connect the OpenOCD
-* Dumping 1MB takes about 60 Seconds
-* Full erase (sectors 0-22 inclusive) takes 2-4 seconds
-* Writing 1MB takes 88 seconds
-*
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "lpc288x.h"
-#include "binarybuffer.h"
-
-
-#define LOAD_TIMER_ERASE       0
-#define LOAD_TIMER_WRITE       1
-
-#define FLASH_PAGE_SIZE                512
-
-/* LPC288X control registers */
-#define DBGU_CIDR              0x8000507C
-/* LPC288X flash registers */
-#define F_CTRL                 0x80102000      /* Flash control register R/W 0x5 */
-#define F_STAT                 0x80102004      /* Flash status register RO 0x45 */
-#define F_PROG_TIME            0x80102008      /* Flash program time register R/W 0 */
-#define F_WAIT                 0x80102010      /* Flash read wait state register R/W 0xC004 */
-#define F_CLK_TIME             0x8010201C      /* Flash clock divider for 66 kHz generation R/W 0 */
-#define F_INTEN_CLR            0x80102FD8      /* Clear interrupt enable bits WO - */
-#define F_INTEN_SET            0x80102FDC      /* Set interrupt enable bits WO - */
-#define F_INT_STAT             0x80102FE0      /* Interrupt status bits RO 0 */
-#define F_INTEN                        0x80102FE4      /* Interrupt enable bits RO 0 */
-#define F_INT_CLR              0x80102FE8      /* Clear interrupt status bits WO */
-#define F_INT_SET              0x80102FEC      /* Set interrupt status bits WO - */
-#define FLASH_PD               0x80005030      /* Allows turning off the Flash memory for power savings. R/W 1*/
-#define FLASH_INIT             0x80005034      /* Monitors Flash readiness, such as recovery from Power Down mode. R/W -*/
-
-/* F_CTRL bits */
-#define FC_CS                  0x0001
-#define FC_FUNC                        0x0002
-#define FC_WEN                 0x0004
-#define FC_RD_LATCH            0x0020
-#define FC_PROTECT             0x0080
-#define FC_SET_DATA            0x0400
-#define FC_RSSL                        0x0800
-#define FC_PROG_REQ            0x1000
-#define FC_CLR_BUF             0x4000
-#define FC_LOAD_REQ            0x8000
-/* F_STAT bits */
-#define FS_DONE                        0x0001
-#define FS_PROGGNT             0x0002
-#define FS_RDY                 0x0004
-#define FS_ERR                 0x0020
-/* F_PROG_TIME */
-#define FPT_TIME_MASK  0x7FFF
-
-#define FPT_ENABLE             0x8000
-/* F_WAIT */
-#define FW_WAIT_STATES_MASK            0x00FF
-#define FW_SET_MASK                            0xC000
-
-/* F_CLK_TIME */
-#define FCT_CLK_DIV_MASK    0x0FFF
-
-static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout);
-static void lpc288x_load_timer(int erase, struct target *target);
-static void lpc288x_set_flash_clk(struct flash_bank *bank);
-static uint32_t lpc288x_system_ready(struct flash_bank *bank);
-
-static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
-{
-       uint32_t status;
-       struct target *target = bank->target;
-       do
-       {
-               alive_sleep(1);
-               timeout--;
-               target_read_u32(target, F_STAT, &status);
-       } while (((status & FS_DONE) == 0) && timeout);
-
-       if (timeout == 0)
-       {
-               LOG_DEBUG("Timedout!");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       return ERROR_OK;
-}
-
-/* Read device id register and fill in driver info structure */
-static int lpc288x_read_part_info(struct flash_bank *bank)
-{
-       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t cidr;
-
-       int i = 0;
-       uint32_t offset;
-
-       if (lpc288x_info->cidr == 0x0102100A)
-               return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */
-
-       /* Read and parse chip identification register */
-       target_read_u32(target, DBGU_CIDR, &cidr);
-
-       if (cidr != 0x0102100A)
-       {
-               LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")",cidr);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       lpc288x_info->cidr = cidr;
-       lpc288x_info->sector_size_break = 0x000F0000;
-       lpc288x_info->target_name = "LPC288x";
-
-       /* setup the sector info... */
-       offset = bank->base;
-       bank->num_sectors = 23;
-       bank->sectors = malloc(sizeof(struct flash_sector) * 23);
-
-       for (i = 0; i < 15; i++)
-       {
-               bank->sectors[i].offset = offset;
-               bank->sectors[i].size = 64 * 1024;
-               offset += bank->sectors[i].size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 1;
-       }
-       for (i = 15; i < 23; i++)
-       {
-               bank->sectors[i].offset = offset;
-               bank->sectors[i].size = 8 * 1024;
-               offset += bank->sectors[i].size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static int lpc288x_protect_check(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-/* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
-FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
-{
-       struct lpc288x_flash_bank *lpc288x_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank LPC288x configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
-       bank->driver_priv = lpc288x_info;
-
-       /* part wasn't probed for info yet */
-       lpc288x_info->cidr = 0;
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk);
-
-       return ERROR_OK;
-}
-
-/* The frequency is the AHB clock frequency divided by (CLK_DIV Ã—3) + 1.
- * This must be programmed such that the Flash Programming clock frequency is 66 kHz Â± 20%.
- * AHB = 12 MHz ?
- * 12000000/66000 = 182
- * CLK_DIV = 60 ? */
-static void lpc288x_set_flash_clk(struct flash_bank *bank)
-{
-       uint32_t clk_time;
-       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
-       clk_time = (lpc288x_info->cclk / 66000) / 3;
-       target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN);
-       target_write_u32(bank->target, F_CLK_TIME, clk_time);
-}
-
-/* AHB tcyc (in ns) 83 ns
- * LOAD_TIMER_ERASE            FPT_TIME        = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512
- *                                                                     = 9412 (9500) (AN10548 9375)
- * LOAD_TIMER_WRITE            FPT_TIME        = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512
- *                                                                     = 23 (75) (AN10548 72 - is this wrong?)
- * TODO: Sort out timing calcs ;) */
-static void lpc288x_load_timer(int erase, struct target *target)
-{
-       if (erase == LOAD_TIMER_ERASE)
-       {
-               target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500);
-       }
-       else
-       {
-               target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75);
-       }
-}
-
-static uint32_t lpc288x_system_ready(struct flash_bank *bank)
-{
-       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
-       if (lpc288x_info->cidr == 0)
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-       return ERROR_OK;
-}
-
-static int lpc288x_erase_check(struct flash_bank *bank)
-{
-       uint32_t status = lpc288x_system_ready(bank);   /* probed? halted? */
-       if (status != ERROR_OK)
-       {
-               LOG_INFO("Processor not halted/not probed");
-               return status;
-       }
-
-       return ERROR_OK;
-}
-
-static int lpc288x_erase(struct flash_bank *bank, int first, int last)
-{
-       uint32_t status;
-       int sector;
-       struct target *target = bank->target;
-
-       status = lpc288x_system_ready(bank);    /* probed? halted? */
-       if (status != ERROR_OK)
-       {
-               return status;
-       }
-
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               LOG_INFO("Bad sector range");
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* Configure the flash controller timing */
-       lpc288x_set_flash_clk(bank);
-
-       for (sector = first; sector <= last; sector++)
-       {
-               if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               lpc288x_load_timer(LOAD_TIMER_ERASE,target);
-
-               target_write_u32(target, bank->sectors[sector].offset, 0x00);
-
-               target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS);
-       }
-       if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       return ERROR_OK;
-}
-
-static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       uint8_t page_buffer[FLASH_PAGE_SIZE];
-       uint32_t status, source_offset,dest_offset;
-       struct target *target = bank->target;
-       uint32_t bytes_remaining = count;
-       uint32_t first_sector, last_sector, sector, page;
-       int i;
-
-       /* probed? halted? */
-       status = lpc288x_system_ready(bank);
-       if (status != ERROR_OK)
-       {
-               return status;
-       }
-
-       /* Initialise search indices */
-       first_sector = last_sector = 0xffffffff;
-
-       /* validate the write range... */
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               if ((offset >= bank->sectors[i].offset) &&
-                       (offset < (bank->sectors[i].offset + bank->sectors[i].size)) &&
-                       (first_sector == 0xffffffff))
-               {
-                       first_sector = i;
-                       /* all writes must start on a sector boundary... */
-                       if (offset % bank->sectors[i].size)
-                       {
-                               LOG_INFO("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size);
-                               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-                       }
-               }
-               if (((offset + count) > bank->sectors[i].offset) &&
-                       ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) &&
-                       (last_sector == 0xffffffff))
-               {
-                       last_sector = i;
-               }
-       }
-
-       /* Range check... */
-       if (first_sector == 0xffffffff || last_sector == 0xffffffff)
-       {
-               LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count);
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-       }
-
-       /* Configure the flash controller timing */
-       lpc288x_set_flash_clk(bank);
-
-       /* initialise the offsets */
-       source_offset = 0;
-       dest_offset = 0;
-
-       for (sector = first_sector; sector <= last_sector; sector++)
-       {
-               for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++)
-               {
-                       if (bytes_remaining == 0)
-                       {
-                               count = 0;
-                               memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
-                       }
-                       else if (bytes_remaining < FLASH_PAGE_SIZE)
-                       {
-                               count = bytes_remaining;
-                               memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
-                               memcpy(page_buffer, &buffer[source_offset], count);
-                       }
-                       else
-                       {
-                               count = FLASH_PAGE_SIZE;
-                               memcpy(page_buffer, &buffer[source_offset], count);
-                       }
-
-                       /* Wait for flash to become ready */
-                       if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
-                       {
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-
-                       /* fill flash data latches with 1's */
-                       target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC);
-
-                       target_write_u32(target, F_CTRL, FC_CS | FC_WEN | FC_FUNC);
-                       /*would be better to use the clean target_write_buffer() interface but
-                        * it seems not to be a LOT slower....
-                        * bulk_write_memory() is no quicker :(*/
-#if 1
-                       if (target_write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK)
-                       {
-                               LOG_ERROR("Write failed s %" PRIx32 " p %" PRIx32 "", sector, page);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-#else
-                       if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK)
-                       {
-                               LOG_INFO("Write to flash buffer failed");
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-#endif
-                       dest_offset += FLASH_PAGE_SIZE;
-                       source_offset += count;
-                       bytes_remaining -= count;
-
-                       lpc288x_load_timer(LOAD_TIMER_WRITE, target);
-
-                       target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC | FC_CS);
-               }
-       }
-
-       return ERROR_OK;
-}
-
-static int lpc288x_probe(struct flash_bank *bank)
-{
-       /* we only deal with LPC2888 so flash config is fixed */
-       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
-       int retval;
-
-       if (lpc288x_info->cidr != 0)
-       {
-               return ERROR_OK; /* already probed */
-       }
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       retval = lpc288x_read_part_info(bank);
-       if (retval != ERROR_OK)
-               return retval;
-       return ERROR_OK;
-}
-
-static int lpc288x_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "lpc288x flash driver");
-       return ERROR_OK;
-}
-
-static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       int lockregion, status;
-       uint32_t value;
-       struct target *target = bank->target;
-
-       /* probed? halted? */
-       status = lpc288x_system_ready(bank);
-       if (status != ERROR_OK)
-       {
-               return status;
-       }
-
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* Configure the flash controller timing */
-       lpc288x_set_flash_clk(bank);
-
-       for (lockregion = first; lockregion <= last; lockregion++)
-       {
-               if (set)
-               {
-                       /* write an odd value to base addy to protect... */
-                       value = 0x01;
-               }
-               else
-               {
-                       /* write an even value to base addy to unprotect... */
-                       value = 0x00;
-               }
-               target_write_u32(target, bank->sectors[lockregion].offset, value);
-               target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC | FC_CS);
-       }
-
-       return ERROR_OK;
-}
-
-struct flash_driver lpc288x_flash = {
-               .name = "lpc288x",
-               .flash_bank_command = &lpc288x_flash_bank_command,
-               .erase = &lpc288x_erase,
-               .protect = &lpc288x_protect,
-               .write = &lpc288x_write,
-               .probe = &lpc288x_probe,
-               .auto_probe = &lpc288x_probe,
-               .erase_check = &lpc288x_erase_check,
-               .protect_check = &lpc288x_protect_check,
-               .info = &lpc288x_info,
-       };
diff --git a/src/flash/lpc288x.h b/src/flash/lpc288x.h
deleted file mode 100644 (file)
index 5a71ee0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2008 by                                                            *
- *   Karl RobinSod <karl.robinsod@gmail.com>                               *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-
-#ifndef lpc288x_H
-#define lpc288x_H
-
-#include "flash.h"
-
-struct lpc288x_flash_bank
-{
-       uint32_t working_area;
-       uint32_t working_area_size;
-
-       /* chip id register */
-       uint32_t cidr;
-       char * target_name;
-       uint32_t cclk;
-
-       uint32_t sector_size_break;
-};
-
-#endif /* lpc288x_H */
diff --git a/src/flash/lpc2900.c b/src/flash/lpc2900.c
deleted file mode 100644 (file)
index 81e2def..0000000
+++ /dev/null
@@ -1,1834 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2009 by                                                 *
- *   Rolf Meeser <rolfm_9dq@yahoo.de>                                      *
- *                                                                         *
- *   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 "image.h"
-#include "flash.h"
-#include "binarybuffer.h"
-#include "armv4_5.h"
-#include "algorithm.h"
-
-
-/* 1024 bytes */
-#define KiB                 1024
-
-/* Some flash constants */
-#define FLASH_PAGE_SIZE     512     /* bytes */
-#define FLASH_ERASE_TIME    100000  /* microseconds */
-#define FLASH_PROGRAM_TIME  1000    /* microseconds */
-
-/* Chip ID / Feature Registers */
-#define CHIPID          0xE0000000  /* Chip ID */
-#define FEAT0           0xE0000100  /* Chip feature 0 */
-#define FEAT1           0xE0000104  /* Chip feature 1 */
-#define FEAT2           0xE0000108  /* Chip feature 2 (contains flash size indicator) */
-#define FEAT3           0xE000010C  /* Chip feature 3 */
-
-#define EXPECTED_CHIPID 0x209CE02B  /* Chip ID of all LPC2900 devices */
-
-/* Flash/EEPROM Control Registers */
-#define FCTR            0x20200000  /* Flash control */
-#define FPTR            0x20200008  /* Flash program-time */
-#define FTCTR           0x2020000C  /* Flash test control */
-#define FBWST           0x20200010  /* Flash bridge wait-state */
-#define FCRA            0x2020001C  /* Flash clock divider */
-#define FMSSTART        0x20200020  /* Flash Built-In Selft Test start address */
-#define FMSSTOP         0x20200024  /* Flash Built-In Selft Test stop address */
-#define FMS16           0x20200028  /* Flash 16-bit signature */
-#define FMSW0           0x2020002C  /* Flash 128-bit signature Word 0 */
-#define FMSW1           0x20200030  /* Flash 128-bit signature Word 1 */
-#define FMSW2           0x20200034  /* Flash 128-bit signature Word 2 */
-#define FMSW3           0x20200038  /* Flash 128-bit signature Word 3 */
-
-#define EECMD           0x20200080  /* EEPROM command */
-#define EEADDR          0x20200084  /* EEPROM address */
-#define EEWDATA         0x20200088  /* EEPROM write data */
-#define EERDATA         0x2020008C  /* EEPROM read data */
-#define EEWSTATE        0x20200090  /* EEPROM wait state */
-#define EECLKDIV        0x20200094  /* EEPROM clock divider */
-#define EEPWRDWN        0x20200098  /* EEPROM power-down/start */
-#define EEMSSTART       0x2020009C  /* EEPROM BIST start address */
-#define EEMSSTOP        0x202000A0  /* EEPROM BIST stop address */
-#define EEMSSIG         0x202000A4  /* EEPROM 24-bit BIST signature */
-
-#define INT_CLR_ENABLE  0x20200FD8  /* Flash/EEPROM interrupt clear enable */
-#define INT_SET_ENABLE  0x20200FDC  /* Flash/EEPROM interrupt set enable */
-#define INT_STATUS      0x20200FE0  /* Flash/EEPROM interrupt status */
-#define INT_ENABLE      0x20200FE4  /* Flash/EEPROM interrupt enable */
-#define INT_CLR_STATUS  0x20200FE8  /* Flash/EEPROM interrupt clear status */
-#define INT_SET_STATUS  0x20200FEC  /* Flash/EEPROM interrupt set status */
-
-/* Interrupt sources */
-#define INTSRC_END_OF_PROG    (1 << 28)
-#define INTSRC_END_OF_BIST    (1 << 27)
-#define INTSRC_END_OF_RDWR    (1 << 26)
-#define INTSRC_END_OF_MISR    (1 << 2)
-#define INTSRC_END_OF_BURN    (1 << 1)
-#define INTSRC_END_OF_ERASE   (1 << 0)
-
-
-/* FCTR bits */
-#define FCTR_FS_LOADREQ       (1 << 15)
-#define FCTR_FS_CACHECLR      (1 << 14)
-#define FCTR_FS_CACHEBYP      (1 << 13)
-#define FCTR_FS_PROGREQ       (1 << 12)
-#define FCTR_FS_RLS           (1 << 11)
-#define FCTR_FS_PDL           (1 << 10)
-#define FCTR_FS_PD            (1 << 9)
-#define FCTR_FS_WPB           (1 << 7)
-#define FCTR_FS_ISS           (1 << 6)
-#define FCTR_FS_RLD           (1 << 5)
-#define FCTR_FS_DCR           (1 << 4)
-#define FCTR_FS_WEB           (1 << 2)
-#define FCTR_FS_WRE           (1 << 1)
-#define FCTR_FS_CS            (1 << 0)
-/* FPTR bits */
-#define FPTR_EN_T             (1 << 15)
-/* FTCTR bits */
-#define FTCTR_FS_BYPASS_R     (1 << 29)
-#define FTCTR_FS_BYPASS_W     (1 << 28)
-/* FMSSTOP bits */
-#define FMSSTOP_MISR_START    (1 << 17)
-/* EEMSSTOP bits */
-#define EEMSSTOP_STRTBIST     (1 << 31)
-
-/* Index sector */
-#define ISS_CUSTOMER_START1   (0x830)
-#define ISS_CUSTOMER_END1     (0xA00)
-#define ISS_CUSTOMER_SIZE1    (ISS_CUSTOMER_END1 - ISS_CUSTOMER_START1)
-#define ISS_CUSTOMER_NWORDS1  (ISS_CUSTOMER_SIZE1 / 4)
-#define ISS_CUSTOMER_START2   (0xA40)
-#define ISS_CUSTOMER_END2     (0xC00)
-#define ISS_CUSTOMER_SIZE2    (ISS_CUSTOMER_END2 - ISS_CUSTOMER_START2)
-#define ISS_CUSTOMER_NWORDS2  (ISS_CUSTOMER_SIZE2 / 4)
-#define ISS_CUSTOMER_SIZE     (ISS_CUSTOMER_SIZE1 + ISS_CUSTOMER_SIZE2)
-
-
-
-/**
- * Private data for \c lpc2900 flash driver.
- */
-struct lpc2900_flash_bank
-{
-       /**
-        * Holds the value read from CHIPID register.
-        * The driver will not load if the chipid doesn't match the expected
-        * value of 0x209CE02B of the LPC2900 family. A probe will only be done
-        * if the chipid does not yet contain the expected value.
-        */
-       uint32_t chipid;
-
-       /**
-        * String holding device name.
-        * This string is set by the probe function to the type number of the
-        * device. It takes the form "LPC29xx".
-        */
-       char * target_name;
-
-       /**
-        * System clock frequency.
-        * Holds the clock frequency in Hz, as passed by the configuration file
-        * to the <tt>flash bank</tt> command.
-        */
-       uint32_t clk_sys_fmc;
-
-       /**
-        * Flag to indicate that dangerous operations are possible.
-        * This flag can be set by passing the correct password to the
-        * <tt>lpc2900 password</tt> command. If set, other dangerous commands,
-        * which operate on the index sector, can be executed.
-        */
-       uint32_t risky;
-
-       /**
-        * Maximum contiguous block of internal SRAM (bytes).
-        * Autodetected by the driver. Not the total amount of SRAM, only the
-        * the largest \em contiguous block!
-        */
-       uint32_t max_ram_block;
-
-};
-
-
-static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout);
-static void lpc2900_setup(struct flash_bank *bank);
-static uint32_t lpc2900_is_ready(struct flash_bank *bank);
-static uint32_t lpc2900_read_security_status(struct flash_bank *bank);
-static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
-                                    uint32_t addr_from, uint32_t addr_to,
-                                    uint32_t (*signature)[4] );
-static uint32_t lpc2900_address2sector(struct flash_bank *bank, uint32_t offset);
-static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time );
-
-
-/***********************  Helper functions  **************************/
-
-
-/**
- * Wait for an event in mask to occur in INT_STATUS.
- *
- * Return when an event occurs, or after a timeout.
- *
- * @param[in] bank Pointer to the flash bank descriptor
- * @param[in] mask Mask to be used for INT_STATUS
- * @param[in] timeout Timeout in ms
- */
-static uint32_t lpc2900_wait_status( struct flash_bank *bank,
-                                     uint32_t mask,
-                                     int timeout )
-{
-       uint32_t int_status;
-       struct target *target = bank->target;
-
-
-       do
-       {
-               alive_sleep(1);
-               timeout--;
-               target_read_u32(target, INT_STATUS, &int_status);
-       }
-       while( ((int_status & mask) == 0) && (timeout != 0) );
-
-       if (timeout == 0)
-       {
-               LOG_DEBUG("Timeout!");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-
-
-/**
- * Set up the flash for erase/program operations.
- *
- * Enable the flash, and set the correct CRA clock of 66 kHz.
- *
- * @param bank Pointer to the flash bank descriptor
- */
-static void lpc2900_setup( struct flash_bank *bank )
-{
-       uint32_t fcra;
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-
-       /* Power up the flash block */
-       target_write_u32( bank->target, FCTR, FCTR_FS_WEB | FCTR_FS_CS );
-
-
-       fcra = (lpc2900_info->clk_sys_fmc / (3 * 66000)) - 1;
-       target_write_u32( bank->target, FCRA, fcra );
-}
-
-
-
-/**
- * Check if device is ready.
- *
- * Check if device is ready for flash operation:
- * Must have been successfully probed.
- * Must be halted.
- */
-static uint32_t lpc2900_is_ready( struct flash_bank *bank )
-{
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-       if( lpc2900_info->chipid != EXPECTED_CHIPID )
-       {
-               return ERROR_FLASH_BANK_NOT_PROBED;
-       }
-
-       if( bank->target->state != TARGET_HALTED )
-       {
-               LOG_ERROR( "Target not halted" );
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       return ERROR_OK;
-}
-
-
-/**
- * Read the status of sector security from the index sector.
- *
- * @param bank Pointer to the flash bank descriptor
- */
-static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
-{
-       uint32_t status;
-       if( (status = lpc2900_is_ready( bank )) != ERROR_OK )
-       {
-               return status;
-       }
-
-       struct target *target = bank->target;
-
-       /* Enable ISS access */
-       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS);
-
-       /* Read the relevant block of memory from the ISS sector */
-       uint32_t iss_secured_field[ 0x230/16 ][ 4 ];
-       target_read_memory(target, bank->base + 0xC00, 4, 0x230/4,
-                                  (uint8_t *)iss_secured_field);
-
-       /* Disable ISS access */
-       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
-
-       /* Check status of each sector. Note that the sector numbering in the LPC2900
-        * is different from the logical sector numbers used in OpenOCD!
-        * Refer to the user manual for details.
-        *
-        * All zeros (16x 0x00) are treated as a secured sector (is_protected = 1)
-        * All ones (16x 0xFF) are treated as a non-secured sector (is_protected = 0)
-        * Anything else is undefined (is_protected = -1). This is treated as
-        * a protected sector!
-        */
-       int sector;
-       int index;
-       for( sector = 0; sector < bank->num_sectors; sector++ )
-       {
-               /* Convert logical sector number to physical sector number */
-               if( sector <= 4 )
-               {
-                       index = sector + 11;
-               }
-               else if( sector <= 7 )
-               {
-                       index = sector + 27;
-               }
-               else
-               {
-                       index = sector - 8;
-               }
-
-               bank->sectors[sector].is_protected = -1;
-
-               if (
-                   (iss_secured_field[index][0] == 0x00000000) &&
-                   (iss_secured_field[index][1] == 0x00000000) &&
-                   (iss_secured_field[index][2] == 0x00000000) &&
-                   (iss_secured_field[index][3] == 0x00000000) )
-               {
-                       bank->sectors[sector].is_protected = 1;
-               }
-
-               if (
-                   (iss_secured_field[index][0] == 0xFFFFFFFF) &&
-                   (iss_secured_field[index][1] == 0xFFFFFFFF) &&
-                   (iss_secured_field[index][2] == 0xFFFFFFFF) &&
-                   (iss_secured_field[index][3] == 0xFFFFFFFF) )
-               {
-                       bank->sectors[sector].is_protected = 0;
-               }
-       }
-
-       return ERROR_OK;
-}
-
-
-/**
- * Use BIST to calculate a 128-bit hash value over a range of flash.
- *
- * @param bank Pointer to the flash bank descriptor
- * @param addr_from
- * @param addr_to
- * @param signature
- */
-static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
-                                    uint32_t addr_from,
-                                    uint32_t addr_to,
-                                    uint32_t (*signature)[4] )
-{
-       struct target *target = bank->target;
-
-       /* Clear END_OF_MISR interrupt status */
-       target_write_u32( target, INT_CLR_STATUS, INTSRC_END_OF_MISR );
-
-       /* Start address */
-       target_write_u32( target, FMSSTART, addr_from >> 4);
-       /* End address, and issue start command */
-       target_write_u32( target, FMSSTOP, (addr_to >> 4) | FMSSTOP_MISR_START );
-
-       /* Poll for end of operation. Calculate a reasonable timeout. */
-       if( lpc2900_wait_status( bank, INTSRC_END_OF_MISR, 1000 ) != ERROR_OK )
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Return the signature */
-       target_read_memory( target, FMSW0, 4, 4, (uint8_t *)signature );
-
-       return ERROR_OK;
-}
-
-
-/**
- * Return sector number for given address.
- *
- * Return the (logical) sector number for a given relative address.
- * No sanity check is done. It assumed that the address is valid.
- *
- * @param bank Pointer to the flash bank descriptor
- * @param offset Offset address relative to bank start
- */
-static uint32_t lpc2900_address2sector( struct flash_bank *bank,
-                                        uint32_t offset )
-{
-       uint32_t address = bank->base + offset;
-
-
-       /* Run through all sectors of this bank */
-       int sector;
-       for( sector = 0; sector < bank->num_sectors; sector++ )
-       {
-               /* Return immediately if address is within the current sector */
-               if( address < (bank->sectors[sector].offset + bank->sectors[sector].size) )
-               {
-                       return sector;
-               }
-       }
-
-       /* We should never come here. If we do, return an arbitrary sector number. */
-       return 0;
-}
-
-
-
-
-/**
- * Write one page to the index sector.
- *
- * @param bank Pointer to the flash bank descriptor
- * @param pagenum Page number (0...7)
- * @param page Page array (FLASH_PAGE_SIZE bytes)
- */
-static int lpc2900_write_index_page( struct flash_bank *bank,
-                                     int pagenum,
-                                     uint8_t (*page)[FLASH_PAGE_SIZE] )
-{
-       /* Only pages 4...7 are user writable */
-       if ((pagenum < 4) || (pagenum > 7))
-       {
-               LOG_ERROR("Refuse to burn index sector page %d", pagenum);
-               return ERROR_COMMAND_ARGUMENT_INVALID;
-       }
-
-       /* Get target, and check if it's halted */
-       struct target *target = bank->target;
-       if( target->state != TARGET_HALTED )
-       {
-               LOG_ERROR( "Target not halted" );
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* Private info */
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-       /* Enable flash block and set the correct CRA clock of 66 kHz */
-       lpc2900_setup( bank );
-
-       /* Un-protect the index sector */
-       target_write_u32( target, bank->base, 0 );
-       target_write_u32( target, FCTR,
-                         FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_ISS |
-                         FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS );
-
-       /* Set latch load mode */
-       target_write_u32( target, FCTR,
-                         FCTR_FS_ISS | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS );
-
-       /* Write whole page to flash data latches */
-       if( target_write_memory( target,
-                                bank->base + pagenum * FLASH_PAGE_SIZE,
-                                4, FLASH_PAGE_SIZE / 4, (uint8_t *)page) != ERROR_OK )
-       {
-               LOG_ERROR("Index sector write failed @ page %d", pagenum);
-               target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
-
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Clear END_OF_BURN interrupt status */
-       target_write_u32( target, INT_CLR_STATUS, INTSRC_END_OF_BURN );
-
-       /* Set the program/erase time to FLASH_PROGRAM_TIME */
-       target_write_u32(target, FPTR,
-                        FPTR_EN_T | lpc2900_calc_tr( lpc2900_info->clk_sys_fmc,
-                                                     FLASH_PROGRAM_TIME ));
-
-       /* Trigger flash write */
-       target_write_u32( target, FCTR,
-                         FCTR_FS_PROGREQ | FCTR_FS_ISS |
-                         FCTR_FS_WPB | FCTR_FS_WRE | FCTR_FS_CS );
-
-       /* Wait for the end of the write operation. If it's not over after one
-        * second, something went dreadfully wrong... :-(
-        */
-       if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK)
-       {
-               LOG_ERROR("Index sector write failed @ page %d", pagenum);
-               target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
-
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
-
-       return ERROR_OK;
-}
-
-
-
-/**
- * Calculate FPTR.TR register value for desired program/erase time.
- *
- * @param clock System clock in Hz
- * @param time Program/erase time in Âµs
- */
-static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time )
-{
-       /*           ((time[µs]/1e6) * f[Hz]) + 511
-        * FPTR.TR = -------------------------------
-        *                         512
-        *
-        * The result is the
-        */
-
-       uint32_t tr_val = (uint32_t)((((time / 1e6) * clock) + 511.0) / 512.0);
-
-       return tr_val;
-}
-
-
-/***********************  Private flash commands  **************************/
-
-
-/**
- * Command to determine the signature of the whole flash.
- *
- * Uses the Built-In-Self-Test (BIST) to generate a 128-bit hash value
- * of the flash content.
- */
-COMMAND_HANDLER(lpc2900_handle_signature_command)
-{
-       uint32_t status;
-       uint32_t signature[4];
-
-
-       if( CMD_ARGC < 1 )
-       {
-               LOG_WARNING( "Too few arguments. Call: lpc2900 signature <bank#>" );
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if( bank->target->state != TARGET_HALTED )
-       {
-               LOG_ERROR( "Target not halted" );
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* Run BIST over whole flash range */
-       if( (status = lpc2900_run_bist128( bank,
-                                          bank->base,
-                                          bank->base + (bank->size - 1),
-                                          &signature)
-                                        ) != ERROR_OK )
-       {
-               return status;
-       }
-
-       command_print( CMD_CTX, "signature: 0x%8.8" PRIx32
-                                         ":0x%8.8" PRIx32
-                                         ":0x%8.8" PRIx32
-                                         ":0x%8.8" PRIx32,
-                     signature[3], signature[2], signature[1], signature[0] );
-
-       return ERROR_OK;
-}
-
-
-
-/**
- * Store customer info in file.
- *
- * Read customer info from index sector, and store that block of data into
- * a disk file. The format is binary.
- */
-COMMAND_HANDLER(lpc2900_handle_read_custom_command)
-{
-       if( CMD_ARGC < 2 )
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-       lpc2900_info->risky = 0;
-
-       /* Get target, and check if it's halted */
-       struct target *target = bank->target;
-       if( target->state != TARGET_HALTED )
-       {
-               LOG_ERROR( "Target not halted" );
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* Storage for customer info. Read in two parts */
-       uint32_t customer[ ISS_CUSTOMER_NWORDS1 + ISS_CUSTOMER_NWORDS2 ];
-
-       /* Enable access to index sector */
-       target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS );
-
-       /* Read two parts */
-       target_read_memory( target, bank->base+ISS_CUSTOMER_START1, 4,
-                                   ISS_CUSTOMER_NWORDS1,
-                                   (uint8_t *)&customer[0] );
-       target_read_memory( target, bank->base+ISS_CUSTOMER_START2, 4,
-                                   ISS_CUSTOMER_NWORDS2,
-                                   (uint8_t *)&customer[ISS_CUSTOMER_NWORDS1] );
-
-       /* Deactivate access to index sector */
-       target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
-
-       /* Try and open the file */
-       struct fileio fileio;
-       const char *filename = CMD_ARGV[1];
-       int ret = fileio_open( &fileio, filename, FILEIO_WRITE, FILEIO_BINARY );
-       if( ret != ERROR_OK )
-       {
-               LOG_WARNING( "Could not open file %s", filename );
-               return ret;
-       }
-
-       size_t nwritten;
-       ret = fileio_write( &fileio, sizeof(customer),
-                        (const uint8_t *)customer, &nwritten );
-       if( ret != ERROR_OK )
-       {
-               LOG_ERROR( "Write operation to file %s failed", filename );
-               fileio_close( &fileio );
-               return ret;
-       }
-
-       fileio_close( &fileio );
-
-       return ERROR_OK;
-}
-
-
-
-
-/**
- * Enter password to enable potentially dangerous options.
- */
-COMMAND_HANDLER(lpc2900_handle_password_command)
-{
-       if (CMD_ARGC < 2)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-#define ISS_PASSWORD "I_know_what_I_am_doing"
-
-       lpc2900_info->risky = !strcmp( CMD_ARGV[1], ISS_PASSWORD );
-
-       if( !lpc2900_info->risky )
-       {
-               command_print(CMD_CTX, "Wrong password (use '%s')", ISS_PASSWORD);
-               return ERROR_COMMAND_ARGUMENT_INVALID;
-       }
-
-       command_print(CMD_CTX,
-                  "Potentially dangerous operation allowed in next command!");
-
-       return ERROR_OK;
-}
-
-
-
-/**
- * Write customer info from file to the index sector.
- */
-COMMAND_HANDLER(lpc2900_handle_write_custom_command)
-{
-       if (CMD_ARGC < 2)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-       /* Check if command execution is allowed. */
-       if( !lpc2900_info->risky )
-       {
-               command_print( CMD_CTX, "Command execution not allowed!" );
-               return ERROR_COMMAND_ARGUMENT_INVALID;
-       }
-       lpc2900_info->risky = 0;
-
-       /* Get target, and check if it's halted */
-       struct target *target = bank->target;
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* The image will always start at offset 0 */
-       struct image image;
-       image.base_address_set = 1;
-       image.base_address = 0;
-       image.start_address_set = 0;
-
-       const char *filename = CMD_ARGV[1];
-       const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL;
-       retval = image_open(&image, filename, type);
-       if (retval != ERROR_OK)
-       {
-               return retval;
-       }
-
-       /* Do a sanity check: The image must be exactly the size of the customer
-          programmable area. Any other size is rejected. */
-       if( image.num_sections != 1 )
-       {
-               LOG_ERROR("Only one section allowed in image file.");
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-       if( (image.sections[0].base_address != 0) ||
-        (image.sections[0].size != ISS_CUSTOMER_SIZE) )
-       {
-               LOG_ERROR("Incorrect image file size. Expected %d, "
-                       "got %" PRIu32,
-                   ISS_CUSTOMER_SIZE, image.sections[0].size);
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       /* Well boys, I reckon this is it... */
-
-       /* Customer info is split into two blocks in pages 4 and 5. */
-       uint8_t page[FLASH_PAGE_SIZE];
-
-       /* Page 4 */
-       uint32_t offset = ISS_CUSTOMER_START1 % FLASH_PAGE_SIZE;
-       memset( page, 0xff, FLASH_PAGE_SIZE );
-       size_t size_read;
-       retval = image_read_section( &image, 0, 0,
-                                    ISS_CUSTOMER_SIZE1, &page[offset], &size_read);
-       if( retval != ERROR_OK )
-       {
-               LOG_ERROR("couldn't read from file '%s'", filename);
-               image_close(&image);
-               return retval;
-       }
-       if( (retval = lpc2900_write_index_page( bank, 4, &page )) != ERROR_OK )
-       {
-               image_close(&image);
-               return retval;
-       }
-
-       /* Page 5 */
-       offset = ISS_CUSTOMER_START2 % FLASH_PAGE_SIZE;
-       memset( page, 0xff, FLASH_PAGE_SIZE );
-       retval = image_read_section( &image, 0, ISS_CUSTOMER_SIZE1,
-                                    ISS_CUSTOMER_SIZE2, &page[offset], &size_read);
-       if( retval != ERROR_OK )
-       {
-               LOG_ERROR("couldn't read from file '%s'", filename);
-               image_close(&image);
-               return retval;
-       }
-       if( (retval = lpc2900_write_index_page( bank, 5, &page )) != ERROR_OK )
-       {
-               image_close(&image);
-               return retval;
-       }
-
-       image_close(&image);
-
-       return ERROR_OK;
-}
-
-
-
-/**
- * Activate 'sector security' for a range of sectors.
- */
-COMMAND_HANDLER(lpc2900_handle_secure_sector_command)
-{
-       if (CMD_ARGC < 3)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       /* Get the bank descriptor */
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-       /* Check if command execution is allowed. */
-       if( !lpc2900_info->risky )
-       {
-               command_print( CMD_CTX, "Command execution not allowed! "
-               "(use 'password' command first)");
-               return ERROR_COMMAND_ARGUMENT_INVALID;
-       }
-       lpc2900_info->risky = 0;
-
-       /* Read sector range, and do a sanity check. */
-       int first, last;
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
-       COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
-       if( (first >= bank->num_sectors) ||
-           (last >= bank->num_sectors) ||
-           (first > last) )
-       {
-               command_print( CMD_CTX, "Illegal sector range" );
-               return ERROR_COMMAND_ARGUMENT_INVALID;
-       }
-
-       uint8_t page[FLASH_PAGE_SIZE];
-       int sector;
-
-       /* Sectors in page 6 */
-       if( (first <= 4) || (last >= 8) )
-       {
-               memset( &page, 0xff, FLASH_PAGE_SIZE );
-               for( sector = first; sector <= last; sector++ )
-               {
-                       if( sector <= 4 )
-                       {
-                               memset( &page[0xB0 + 16*sector], 0, 16 );
-                       }
-                       else if( sector >= 8 )
-                       {
-                               memset( &page[0x00 + 16*(sector - 8)], 0, 16 );
-                       }
-               }
-
-               if( (retval = lpc2900_write_index_page( bank, 6, &page )) != ERROR_OK )
-               {
-                       LOG_ERROR("failed to update index sector page 6");
-                       return retval;
-               }
-       }
-
-       /* Sectors in page 7 */
-       if( (first <= 7) && (last >= 5) )
-       {
-               memset( &page, 0xff, FLASH_PAGE_SIZE );
-               for( sector = first; sector <= last; sector++ )
-               {
-                       if( (sector >= 5) && (sector <= 7) )
-                       {
-                               memset( &page[0x00 + 16*(sector - 5)], 0, 16 );
-                       }
-               }
-
-               if( (retval = lpc2900_write_index_page( bank, 7, &page )) != ERROR_OK )
-               {
-                       LOG_ERROR("failed to update index sector page 7");
-                       return retval;
-               }
-       }
-
-       command_print( CMD_CTX,
-               "Sectors security will become effective after next power cycle");
-
-       /* Update the sector security status */
-       if ( lpc2900_read_security_status(bank) != ERROR_OK )
-       {
-               LOG_ERROR( "Cannot determine sector security status" );
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-
-
-/**
- * Activate JTAG protection.
- */
-COMMAND_HANDLER(lpc2900_handle_secure_jtag_command)
-{
-       if (CMD_ARGC < 1)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       /* Get the bank descriptor */
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-       /* Check if command execution is allowed. */
-       if( !lpc2900_info->risky )
-       {
-               command_print( CMD_CTX, "Command execution not allowed! "
-                                       "(use 'password' command first)");
-               return ERROR_COMMAND_ARGUMENT_INVALID;
-       }
-       lpc2900_info->risky = 0;
-
-       /* Prepare page */
-       uint8_t page[FLASH_PAGE_SIZE];
-       memset( &page, 0xff, FLASH_PAGE_SIZE );
-
-
-       /* Insert "soft" protection word */
-       page[0x30 + 15] = 0x7F;
-       page[0x30 + 11] = 0x7F;
-       page[0x30 +  7] = 0x7F;
-       page[0x30 +  3] = 0x7F;
-
-       /* Write to page 5 */
-       if( (retval = lpc2900_write_index_page( bank, 5, &page ))
-                       != ERROR_OK )
-       {
-               LOG_ERROR("failed to update index sector page 5");
-               return retval;
-       }
-
-       LOG_INFO("JTAG security set. Good bye!");
-
-       return ERROR_OK;
-}
-
-
-
-/***********************  Flash interface functions  **************************/
-
-static const struct command_registration lpc2900_exec_command_handlers[] = {
-       {
-               .name = "signature",
-               .handler = &lpc2900_handle_signature_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<bank>",
-               .help = "print device signature of flash bank",
-       },
-       {
-               .name = "read_custom",
-               .handler = &lpc2900_handle_read_custom_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<bank> <filename>",
-               .help = "read customer information from index sector to file",
-       },
-       {
-               .name = "password",
-               .handler = &lpc2900_handle_password_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<bank> <password>",
-               .help = "enter password to enable 'dangerous' options",
-       },
-       {
-               .name = "write_custom",
-               .handler = &lpc2900_handle_write_custom_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<bank> <filename> [<type>]",
-               .help = "write customer info from file to index sector",
-       },
-       {
-               .name = "secure_sector",
-               .handler = &lpc2900_handle_secure_sector_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<bank> <first> <last>",
-               .help = "activate sector security for a range of sectors",
-       },
-       {
-               .name = "secure_jtag",
-               .handler = &lpc2900_handle_secure_jtag_command,
-               .mode = COMMAND_EXEC,
-               .usage = "<bank> <level>",
-               .help = "activate JTAG security",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration lpc2900_command_handlers[] = {
-       {
-               .name = "lpc2900",
-               .mode = COMMAND_ANY,
-               .help = "LPC2900 flash command group",
-               .chain = lpc2900_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-/// Evaluate flash bank command.
-FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
-{
-       struct lpc2900_flash_bank *lpc2900_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank LPC2900 configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       lpc2900_info = malloc(sizeof(struct lpc2900_flash_bank));
-       bank->driver_priv = lpc2900_info;
-
-       /* Get flash clock.
-        * Reject it if we can't meet the requirements for program time
-        * (if clock too slow), or for erase time (clock too fast).
-        */
-       uint32_t clk_sys_fmc;
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], clk_sys_fmc);
-       lpc2900_info->clk_sys_fmc = clk_sys_fmc * 1000;
-
-       uint32_t clock_limit;
-       /* Check program time limit */
-       clock_limit = 512000000l / FLASH_PROGRAM_TIME;
-       if (lpc2900_info->clk_sys_fmc < clock_limit)
-       {
-               LOG_WARNING("flash clock must be at least %" PRIu32 " kHz",
-                    (clock_limit / 1000));
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       /* Check erase time limit */
-       clock_limit = (uint32_t)((32767.0 * 512.0 * 1e6) / FLASH_ERASE_TIME);
-       if (lpc2900_info->clk_sys_fmc > clock_limit)
-       {
-               LOG_WARNING("flash clock must be a maximum of %" PRIu32" kHz",
-                    (clock_limit / 1000));
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       /* Chip ID will be obtained by probing the device later */
-       lpc2900_info->chipid = 0;
-
-       return ERROR_OK;
-}
-
-
-/**
- * Erase sector(s).
- *
- * @param bank Pointer to the flash bank descriptor
- * @param first First sector to be erased
- * @param last Last sector (including) to be erased
- */
-static int lpc2900_erase(struct flash_bank *bank, int first, int last)
-{
-       uint32_t status;
-       int sector;
-       int last_unsecured_sector;
-       struct target *target = bank->target;
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-
-
-       status = lpc2900_is_ready(bank);
-       if (status != ERROR_OK)
-       {
-               return status;
-       }
-
-       /* Sanity check on sector range */
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               LOG_INFO("Bad sector range");
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* Update the info about secured sectors */
-       lpc2900_read_security_status( bank );
-
-       /* The selected sector range might include secured sectors. An attempt
-        * to erase such a sector will cause the erase to fail also for unsecured
-        * sectors. It is necessary to determine the last unsecured sector now,
-        * because we have to treat the last relevant sector in the list in
-        * a special way.
-        */
-       last_unsecured_sector = -1;
-       for (sector = first; sector <= last; sector++)
-       {
-               if ( !bank->sectors[sector].is_protected )
-               {
-                       last_unsecured_sector = sector;
-               }
-       }
-
-       /* Exit now, in case of the rare constellation where all sectors in range
-        * are secured. This is regarded a success, since erasing/programming of
-        * secured sectors shall be handled transparently.
-        */
-       if ( last_unsecured_sector == -1 )
-       {
-               return ERROR_OK;
-       }
-
-       /* Enable flash block and set the correct CRA clock of 66 kHz */
-       lpc2900_setup(bank);
-
-       /* Clear END_OF_ERASE interrupt status */
-       target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_ERASE);
-
-       /* Set the program/erase timer to FLASH_ERASE_TIME */
-       target_write_u32(target, FPTR,
-                        FPTR_EN_T | lpc2900_calc_tr( lpc2900_info->clk_sys_fmc,
-                                                     FLASH_ERASE_TIME ));
-
-       /* Sectors are marked for erasure, then erased all together */
-       for (sector = first; sector <= last_unsecured_sector; sector++)
-       {
-               /* Only mark sectors that aren't secured. Any attempt to erase a group
-                * of sectors will fail if any single one of them is secured!
-                */
-               if ( !bank->sectors[sector].is_protected )
-               {
-                       /* Unprotect the sector */
-                       target_write_u32(target, bank->sectors[sector].offset, 0);
-                       target_write_u32(target, FCTR,
-                                        FCTR_FS_LOADREQ | FCTR_FS_WPB |
-                                        FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS);
-
-                       /* Mark the sector for erasure. The last sector in the list
-                          triggers the erasure. */
-                       target_write_u32(target, bank->sectors[sector].offset, 0);
-                       if ( sector == last_unsecured_sector )
-                       {
-                               target_write_u32(target, FCTR,
-                                                FCTR_FS_PROGREQ | FCTR_FS_WPB | FCTR_FS_CS);
-                       }
-                       else
-                       {
-                               target_write_u32(target, FCTR,
-                                                FCTR_FS_LOADREQ | FCTR_FS_WPB |
-                                                FCTR_FS_WEB | FCTR_FS_CS);
-                       }
-               }
-       }
-
-       /* Wait for the end of the erase operation. If it's not over after two seconds,
-        * something went dreadfully wrong... :-(
-        */
-       if( lpc2900_wait_status(bank, INTSRC_END_OF_ERASE, 2000) != ERROR_OK )
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Normal flash operating mode */
-       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
-
-       return ERROR_OK;
-}
-
-
-
-static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       /* This command is not supported.
-     * "Protection" in LPC2900 terms is handled transparently. Sectors will
-     * automatically be unprotected as needed.
-     * Instead we use the concept of sector security. A secured sector is shown
-     * as "protected" in OpenOCD. Sector security is a permanent feature, and
-     * cannot be disabled once activated.
-     */
-
-       return ERROR_OK;
-}
-
-
-/**
- * Write data to flash.
- *
- * @param bank Pointer to the flash bank descriptor
- * @param buffer Buffer with data
- * @param offset Start address (relative to bank start)
- * @param count Number of bytes to be programmed
- */
-static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
-                         uint32_t offset, uint32_t count)
-{
-       uint8_t page[FLASH_PAGE_SIZE];
-       uint32_t status;
-       uint32_t num_bytes;
-       struct target *target = bank->target;
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-       int sector;
-       int retval;
-
-       static const uint32_t write_target_code[] = {
-               /* Set auto latch mode: FCTR=CS|WRE|WEB */
-               0xe3a0a007,   /* loop       mov r10, #0x007 */
-               0xe583a000,   /*            str r10,[r3,#0] */
-
-               /* Load complete page into latches */
-               0xe3a06020,   /*            mov r6,#(512/16) */
-               0xe8b00f00,   /* next       ldmia r0!,{r8-r11} */
-               0xe8a10f00,   /*            stmia r1!,{r8-r11} */
-               0xe2566001,   /*            subs r6,#1 */
-               0x1afffffb,   /*            bne next */
-
-               /* Clear END_OF_BURN interrupt status */
-               0xe3a0a002,   /*            mov r10,#(1 << 1) */
-               0xe583afe8,   /*            str r10,[r3,#0xfe8] */
-
-               /* Set the erase time to FLASH_PROGRAM_TIME */
-               0xe5834008,   /*            str r4,[r3,#8] */
-
-               /* Trigger flash write
-                       FCTR = CS | WRE | WPB | PROGREQ */
-               0xe3a0a083,   /*            mov r10,#0x83 */
-               0xe38aaa01,   /*            orr r10,#0x1000 */
-               0xe583a000,   /*            str r10,[r3,#0] */
-
-               /* Wait for end of burn */
-               0xe593afe0,   /* wait       ldr r10,[r3,#0xfe0] */
-               0xe21aa002,   /*            ands r10,#(1 << 1) */
-               0x0afffffc,   /*            beq wait */
-
-               /* End? */
-               0xe2522001,   /*            subs r2,#1 */
-               0x1affffed,   /*            bne loop */
-
-               0xeafffffe    /* done       b done */
-       };
-
-
-       status = lpc2900_is_ready(bank);
-       if (status != ERROR_OK)
-       {
-               return status;
-       }
-
-       /* Enable flash block and set the correct CRA clock of 66 kHz */
-       lpc2900_setup(bank);
-
-       /* Update the info about secured sectors */
-       lpc2900_read_security_status( bank );
-
-       /* Unprotect all involved sectors */
-       for (sector = 0; sector < bank->num_sectors; sector++)
-       {
-               /* Start address in or before this sector? */
-               /* End address in or behind this sector? */
-               if ( ((bank->base + offset) <
-                         (bank->sectors[sector].offset + bank->sectors[sector].size)) &&
-                    ((bank->base + (offset + count - 1)) >= bank->sectors[sector].offset) )
-               {
-                       /* This sector is involved and needs to be unprotected.
-                               * Don't do it for secured sectors.
-                               */
-                       if ( !bank->sectors[sector].is_protected )
-                       {
-                               target_write_u32(target, bank->sectors[sector].offset, 0);
-                               target_write_u32(target, FCTR,
-                                                FCTR_FS_LOADREQ | FCTR_FS_WPB |
-                                                FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS);
-                       }
-               }
-       }
-
-       /* Set the program/erase time to FLASH_PROGRAM_TIME */
-       uint32_t prog_time = FPTR_EN_T | lpc2900_calc_tr( lpc2900_info->clk_sys_fmc,
-                                                         FLASH_PROGRAM_TIME );
-
-       /* If there is a working area of reasonable size, use it to program via
-          a target algorithm. If not, fall back to host programming. */
-
-       /* We need some room for target code. */
-       uint32_t target_code_size = sizeof(write_target_code);
-
-       /* Try working area allocation. Start with a large buffer, and try with
-          reduced size if that fails. */
-       struct working_area *warea;
-       uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
-       while( (retval = target_alloc_working_area(target,
-                                                  buffer_size + target_code_size,
-                                                  &warea)) != ERROR_OK )
-       {
-               /* Try a smaller buffer now, and stop if it's too small. */
-               buffer_size -= 1 * KiB;
-               if (buffer_size < 2 * KiB)
-               {
-                       LOG_INFO( "no (large enough) working area"
-                                 ", falling back to host mode" );
-                       warea = NULL;
-                       break;
-               }
-       };
-
-       if( warea )
-       {
-               struct reg_param reg_params[5];
-               struct armv4_5_algorithm armv4_5_info;
-
-               /* We can use target mode. Download the algorithm. */
-               retval = target_write_buffer( target,
-                                             (warea->address)+buffer_size,
-                                             target_code_size,
-                                             (uint8_t *)write_target_code);
-               if (retval != ERROR_OK)
-               {
-                       LOG_ERROR("Unable to write block write code to target");
-                       target_free_all_working_areas(target);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-               init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-               init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-               init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
-               init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
-
-               /* Write to flash in large blocks */
-               while ( count != 0 )
-               {
-                       uint32_t this_npages;
-                       uint8_t *this_buffer;
-                       int start_sector = lpc2900_address2sector( bank, offset );
-
-                       /* First page / last page / rest */
-                       if( offset % FLASH_PAGE_SIZE )
-                       {
-                               /* Block doesn't start on page boundary.
-                                  Burn first partial page separately. */
-                               memset( &page, 0xff, sizeof(page) );
-                               memcpy( &page[offset % FLASH_PAGE_SIZE],
-                                       buffer,
-                                       FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE) );
-                               this_npages = 1;
-                               this_buffer = &page[0];
-                               count = count + (offset % FLASH_PAGE_SIZE);
-                               offset = offset - (offset % FLASH_PAGE_SIZE);
-                       }
-                       else if( count < FLASH_PAGE_SIZE )
-                       {
-                               /* Download last incomplete page separately. */
-                               memset( &page, 0xff, sizeof(page) );
-                               memcpy( &page, buffer, count );
-                               this_npages = 1;
-                               this_buffer = &page[0];
-                               count = FLASH_PAGE_SIZE;
-                       }
-                       else
-                       {
-                               /* Download as many full pages as possible */
-                               this_npages = (count < buffer_size) ?
-                                              count / FLASH_PAGE_SIZE :
-                                              buffer_size / FLASH_PAGE_SIZE;
-                               this_buffer = buffer;
-
-                               /* Make sure we stop at the next secured sector */
-                               int sector = start_sector + 1;
-                               while( sector < bank->num_sectors )
-                               {
-                                       /* Secured? */
-                                       if( bank->sectors[sector].is_protected )
-                                       {
-                                               /* Is that next sector within the current block? */
-                                               if( (bank->sectors[sector].offset - bank->base) <
-                                                       (offset + (this_npages * FLASH_PAGE_SIZE)) )
-                                               {
-                                                       /* Yes! Split the block */
-                                                       this_npages =
-                                                         (bank->sectors[sector].offset - bank->base - offset)
-                                                             / FLASH_PAGE_SIZE;
-                                                       break;
-                                               }
-                                       }
-
-                                       sector++;
-                               }
-                       }
-
-                       /* Skip the current sector if it is secured */
-                       if (bank->sectors[start_sector].is_protected)
-                       {
-                               LOG_DEBUG("Skip secured sector %d",
-                                               start_sector);
-
-                               /* Stop if this is the last sector */
-                               if (start_sector == bank->num_sectors - 1)
-                               {
-                                       break;
-                               }
-
-                               /* Skip */
-                               uint32_t nskip = bank->sectors[start_sector].size -
-                                                (offset % bank->sectors[start_sector].size);
-                               offset += nskip;
-                               buffer += nskip;
-                               count = (count >= nskip) ? (count - nskip) : 0;
-                               continue;
-                       }
-
-                       /* Execute buffer download */
-                       if ((retval = target_write_buffer(target,
-                                                         warea->address,
-                                                         this_npages * FLASH_PAGE_SIZE,
-                                                         this_buffer)) != ERROR_OK)
-                       {
-                               LOG_ERROR("Unable to write data to target");
-                               target_free_all_working_areas(target);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-
-                       /* Prepare registers */
-                       buf_set_u32(reg_params[0].value, 0, 32, warea->address);
-                       buf_set_u32(reg_params[1].value, 0, 32, offset);
-                       buf_set_u32(reg_params[2].value, 0, 32, this_npages);
-                       buf_set_u32(reg_params[3].value, 0, 32, FCTR);
-                       buf_set_u32(reg_params[4].value, 0, 32, FPTR_EN_T | prog_time);
-
-                       /* Execute algorithm, assume breakpoint for last instruction */
-                       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-                       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-                       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-                       retval = target_run_algorithm(target, 0, NULL, 5, reg_params,
-                               (warea->address) + buffer_size,
-                               (warea->address) + buffer_size + target_code_size - 4,
-                               10000, /* 10s should be enough for max. 16 KiB of data */
-                               &armv4_5_info);
-
-                       if (retval != ERROR_OK)
-                       {
-                               LOG_ERROR("Execution of flash algorithm failed.");
-                               target_free_all_working_areas(target);
-                               retval = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-                       }
-
-                       count -= this_npages * FLASH_PAGE_SIZE;
-                       buffer += this_npages * FLASH_PAGE_SIZE;
-                       offset += this_npages * FLASH_PAGE_SIZE;
-               }
-
-               /* Free all resources */
-               destroy_reg_param(&reg_params[0]);
-               destroy_reg_param(&reg_params[1]);
-               destroy_reg_param(&reg_params[2]);
-               destroy_reg_param(&reg_params[3]);
-               destroy_reg_param(&reg_params[4]);
-               target_free_all_working_areas(target);
-       }
-       else
-       {
-               /* Write to flash memory page-wise */
-               while ( count != 0 )
-               {
-                       /* How many bytes do we copy this time? */
-                       num_bytes = (count >= FLASH_PAGE_SIZE) ?
-                                   FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE) :
-                                   count;
-
-                       /* Don't do anything with it if the page is in a secured sector. */
-                       if ( !bank->sectors[lpc2900_address2sector(bank, offset)].is_protected )
-                       {
-                               /* Set latch load mode */
-                               target_write_u32(target, FCTR,
-                                                FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WEB);
-
-                               /* Always clear the buffer (a little overhead, but who cares) */
-                               memset(page, 0xFF, FLASH_PAGE_SIZE);
-
-                               /* Copy them to the buffer */
-                               memcpy( &page[offset % FLASH_PAGE_SIZE],
-                                       &buffer[offset % FLASH_PAGE_SIZE],
-                                       num_bytes );
-
-                               /* Write whole page to flash data latches */
-                               if (target_write_memory(
-                                                target,
-                                                bank->base + (offset - (offset % FLASH_PAGE_SIZE)),
-                                                4, FLASH_PAGE_SIZE / 4, page) != ERROR_OK)
-                               {
-                                       LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset);
-                                       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
-
-                                       return ERROR_FLASH_OPERATION_FAILED;
-                               }
-
-                               /* Clear END_OF_BURN interrupt status */
-                               target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_BURN);
-
-                               /* Set the programming time */
-                               target_write_u32(target, FPTR, FPTR_EN_T | prog_time);
-
-                               /* Trigger flash write */
-                               target_write_u32(target, FCTR,
-                                   FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WPB | FCTR_FS_PROGREQ);
-
-                               /* Wait for the end of the write operation. If it's not over
-                                * after one second, something went dreadfully wrong... :-(
-                                */
-                               if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK)
-                               {
-                                       LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset);
-                                       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
-
-                                       return ERROR_FLASH_OPERATION_FAILED;
-                               }
-                       }
-
-                       /* Update pointers and counters */
-                       offset += num_bytes;
-                       buffer += num_bytes;
-                       count -= num_bytes;
-               }
-
-               retval = ERROR_OK;
-       }
-
-       /* Normal flash operating mode */
-       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
-
-       return retval;
-}
-
-
-/**
- * Try and identify the device.
- *
- * Determine type number and its memory layout.
- *
- * @param bank Pointer to the flash bank descriptor
- */
-static int lpc2900_probe(struct flash_bank *bank)
-{
-       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
-       struct target *target = bank->target;
-       int i = 0;
-       uint32_t offset;
-
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* We want to do this only once. Check if we already have a valid CHIPID,
-        * because then we will have already successfully probed the device.
-        */
-       if (lpc2900_info->chipid == EXPECTED_CHIPID)
-       {
-               return ERROR_OK;
-       }
-
-       /* Probing starts with reading the CHIPID register. We will continue only
-        * if this identifies as an LPC2900 device.
-        */
-       target_read_u32(target, CHIPID, &lpc2900_info->chipid);
-
-       if (lpc2900_info->chipid != EXPECTED_CHIPID)
-       {
-               LOG_WARNING("Device is not an LPC29xx");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* It's an LPC29xx device. Now read the feature register FEAT0...FEAT3. */
-       uint32_t feat0, feat1, feat2, feat3;
-       target_read_u32(target, FEAT0, &feat0);
-       target_read_u32(target, FEAT1, &feat1);
-       target_read_u32(target, FEAT2, &feat2);
-       target_read_u32(target, FEAT3, &feat3);
-
-       /* Base address */
-       bank->base = 0x20000000;
-
-       /* Determine flash layout from FEAT2 register */
-       uint32_t num_64k_sectors = (feat2 >> 16) & 0xFF;
-       uint32_t num_8k_sectors = (feat2 >> 0) & 0xFF;
-       bank->num_sectors = num_64k_sectors + num_8k_sectors;
-       bank->size = KiB * (64 * num_64k_sectors + 8 * num_8k_sectors);
-
-       /* Determine maximum contiguous RAM block */
-       lpc2900_info->max_ram_block = 16 * KiB;
-       if( (feat1 & 0x30) == 0x30 )
-       {
-               lpc2900_info->max_ram_block = 32 * KiB;
-               if( (feat1 & 0x0C) == 0x0C )
-               {
-                       lpc2900_info->max_ram_block = 48 * KiB;
-               }
-       }
-
-       /* Determine package code and ITCM size */
-       uint32_t package_code = feat0 & 0x0F;
-       uint32_t itcm_code = (feat1 >> 16) & 0x1F;
-
-       /* Determine the exact type number. */
-       uint32_t found = 1;
-       if ( (package_code == 4) && (itcm_code == 5) )
-       {
-               /* Old LPC2917 or LPC2919 (non-/01 devices) */
-               lpc2900_info->target_name = (bank->size == 768*KiB) ? "LPC2919" : "LPC2917";
-       }
-       else
-       {
-               if ( package_code == 2 )
-               {
-                       /* 100-pin package */
-                       if ( bank->size == 128*KiB )
-                       {
-                               lpc2900_info->target_name = "LPC2921";
-                       }
-                       else if ( bank->size == 256*KiB )
-                       {
-                               lpc2900_info->target_name = "LPC2923";
-                       }
-                       else if ( bank->size == 512*KiB )
-                       {
-                               lpc2900_info->target_name = "LPC2925";
-                       }
-                       else
-                       {
-                               found = 0;
-                       }
-               }
-               else if ( package_code == 4 )
-               {
-                       /* 144-pin package */
-                       if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0) )
-                       {
-                               lpc2900_info->target_name = "LPC2917/01";
-                       }
-                       else if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFFF1) )
-                       {
-                               lpc2900_info->target_name = "LPC2927";
-                       }
-                       else if ( (bank->size == 768*KiB) && (feat3 == 0xFFFFFCF8) )
-                       {
-                               lpc2900_info->target_name = "LPC2919/01";
-                       }
-                       else if ( (bank->size == 768*KiB) && (feat3 == 0xFFFFFFF9) )
-                       {
-                               lpc2900_info->target_name = "LPC2929";
-                       }
-                       else
-                       {
-                               found = 0;
-                       }
-               }
-               else if ( package_code == 5 )
-               {
-                       /* 208-pin package */
-                       lpc2900_info->target_name = (bank->size == 0) ? "LPC2930" : "LPC2939";
-               }
-               else
-               {
-                       found = 0;
-               }
-       }
-
-       if ( !found )
-       {
-               LOG_WARNING("Unknown LPC29xx derivative");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Show detected device */
-       LOG_INFO("Flash bank %d"
-                ": Device %s, %" PRIu32
-                " KiB in %d sectors",
-                bank->bank_number,
-                lpc2900_info->target_name, bank->size / KiB,
-                bank->num_sectors);
-
-       /* Flashless devices cannot be handled */
-       if ( bank->num_sectors == 0 )
-       {
-               LOG_WARNING("Flashless device cannot be handled");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Sector layout.
-        * These are logical sector numbers. When doing real flash operations,
-        * the logical flash number are translated into the physical flash numbers
-        * of the device.
-        */
-       bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
-
-       offset = 0;
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               bank->sectors[i].offset = offset;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = -1;
-
-               if ( i <= 7 )
-               {
-                       bank->sectors[i].size = 8 * KiB;
-               }
-               else if ( i <= 18 )
-               {
-                       bank->sectors[i].size = 64 * KiB;
-               }
-               else
-               {
-                       /* We shouldn't come here. But there might be a new part out there
-                        * that has more than 19 sectors. Politely ask for a fix then.
-                        */
-                       bank->sectors[i].size = 0;
-                       LOG_ERROR("Never heard about sector %d", i);
-               }
-
-               offset += bank->sectors[i].size;
-       }
-
-       /* Read sector security status */
-       if ( lpc2900_read_security_status(bank) != ERROR_OK )
-       {
-               LOG_ERROR("Cannot determine sector security status");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-
-/**
- * Run a blank check for each sector.
- *
- * For speed reasons, the device isn't read word by word.
- * A hash value is calculated by the hardware ("BIST") for each sector.
- * This value is then compared against the known hash of an empty sector.
- *
- * @param bank Pointer to the flash bank descriptor
- */
-static int lpc2900_erase_check(struct flash_bank *bank)
-{
-       uint32_t status = lpc2900_is_ready(bank);
-       if (status != ERROR_OK)
-       {
-               LOG_INFO("Processor not halted/not probed");
-               return status;
-       }
-
-       /* Use the BIST (Built-In Selft Test) to generate a signature of each flash
-        * sector. Compare against the expected signature of an empty sector.
-        */
-       int sector;
-       for ( sector = 0; sector < bank->num_sectors; sector++ )
-       {
-               uint32_t signature[4];
-               if ( (status = lpc2900_run_bist128( bank,
-                                                   bank->sectors[sector].offset,
-                                                   bank->sectors[sector].offset +
-                                                      (bank->sectors[sector].size - 1),
-                                                   &signature)) != ERROR_OK )
-               {
-                       return status;
-               }
-
-               /* The expected signatures for an empty sector are different
-                * for 8 KiB and 64 KiB sectors.
-                */
-               if ( bank->sectors[sector].size == 8*KiB )
-               {
-                       bank->sectors[sector].is_erased =
-                           (signature[3] == 0x01ABAAAA) &&
-                           (signature[2] == 0xAAAAAAAA) &&
-                           (signature[1] == 0xAAAAAAAA) &&
-                           (signature[0] == 0xAAA00AAA);
-               }
-               if ( bank->sectors[sector].size == 64*KiB )
-               {
-                       bank->sectors[sector].is_erased =
-                           (signature[3] == 0x11801222) &&
-                           (signature[2] == 0xB88844FF) &&
-                           (signature[1] == 0x11A22008) &&
-                           (signature[0] == 0x2B1BFE44);
-               }
-       }
-
-       return ERROR_OK;
-}
-
-
-/**
- * Get protection (sector security) status.
- *
- * Determine the status of "sector security" for each sector.
- * A secured sector is one that can never be erased/programmed again.
- *
- * @param bank Pointer to the flash bank descriptor
- */
-static int lpc2900_protect_check(struct flash_bank *bank)
-{
-       return lpc2900_read_security_status(bank);
-}
-
-
-/**
- * Print info about the driver (not the device).
- *
- * @param bank Pointer to the flash bank descriptor
- * @param buf Buffer to take the string
- * @param buf_size Maximum number of characters that the buffer can take
- */
-static int lpc2900_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "lpc2900 flash driver");
-
-       return ERROR_OK;
-}
-
-
-struct flash_driver lpc2900_flash =
-{
-       .name               = "lpc2900",
-       .commands           = lpc2900_command_handlers,
-       .flash_bank_command = lpc2900_flash_bank_command,
-       .erase              = lpc2900_erase,
-       .protect            = lpc2900_protect,
-       .write              = lpc2900_write,
-       .probe              = lpc2900_probe,
-       .auto_probe         = lpc2900_probe,
-       .erase_check        = lpc2900_erase_check,
-       .protect_check      = lpc2900_protect_check,
-       .info               = lpc2900_info
-};
diff --git a/src/flash/non_cfi.c b/src/flash/non_cfi.c
deleted file mode 100644 (file)
index f98b108..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *   Copyright (C) 2009 Michael Schwingen                                  *
- *   michael@schwingen.org                                                 *
- *                                                                         *
- *   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 "non_cfi.h"
-#include "cfi.h"
-
-
-#define KB 1024
-#define MB (1024*1024)
-#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
-
-/* non-CFI compatible flashes */
-static struct non_cfi non_cfi_flashes[] = {
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0xd4,
-               .pri_id = 0x02,
-               .dev_size = 64*KB,
-               .interface_desc = 0x0,          /* x8 only device */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(16, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0xd5,
-               .pri_id = 0x02,
-               .dev_size = 128*KB,
-               .interface_desc = 0x0,          /* x8 only device */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(32, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0xd6,
-               .pri_id = 0x02,
-               .dev_size = 256*KB,
-               .interface_desc = 0x0,          /* x8 only device */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(64, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0xd7,
-               .pri_id = 0x02,
-               .dev_size = 512*KB,
-               .interface_desc = 0x0,          /* x8 only device */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(128, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x2780,
-               .pri_id = 0x02,
-               .dev_size = 512*KB,
-               .interface_desc = 0x2,          /* x8 or x16 device */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(128, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_ST,
-               .id = 0xd6,                                     /* ST29F400BB */
-               .pri_id = 0x02,
-               .dev_size = 512*KB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2,  8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(7, 64*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_ST,
-               .id = 0xd5,                                     /* ST29F400BT */
-               .pri_id = 0x02,
-               .dev_size = 512*KB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(7, 64*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(2,  8*KB),
-                       ERASE_REGION(1, 16*KB)
-               }
-       },
-
-       /* SST 39VF* do not support DQ5 status polling - this currently is
-          only supported by the host algorithm, not by the target code using
-          the work area.
-           Only true for 8-bit and 32-bit wide memories. 16-bit wide memories
-           without DQ5 status polling are supported by the target code.
-        */
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x2782,                           /* SST39xF160 */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(512, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x2783,                           /* SST39VF320 */
-               .pri_id = 0x02,
-               .dev_size = 4*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1024, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x234b,                           /* SST39VF1601 */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(512, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x234a,                           /* SST39VF1602 */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(512, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x235b,                           /* SST39VF3201 */
-               .pri_id = 0x02,
-               .dev_size = 4*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1024, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_SST,
-               .id = 0x235a,                           /* SST39VF3202 */
-               .pri_id = 0x02,
-               .dev_size = 4*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
-               .num_erase_regions = 1,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1024, 4*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_AMD,
-               .id = 0x22ab,                           /* AM29F400BB */
-               .pri_id = 0x02,
-               .dev_size = 512*KB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2,  8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(7, 64*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_AMD,
-               .id = 0x2223,                           /* AM29F400BT */
-               .pri_id = 0x02,
-               .dev_size = 512*KB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(7, 64*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(2,  8*KB),
-                       ERASE_REGION(1, 16*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_FUJITSU,
-               .id = 0x226b,                           /* AM29SL800DB */
-               .pri_id = 0x02,
-               .dev_size = 1*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2,  8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(15, 64*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_AMIC,
-               .id = 0xb31a,                           /* A29L800A */
-               .pri_id = 0x02,
-               .dev_size = 1*MB,
-               .interface_desc = 0x2,
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2,  8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(15, 64*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_MX,
-               .id = 0x225b,                           /* MX29LV800B */
-               .pri_id = 0x02,
-               .dev_size = 1*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2, 8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(15, 64*KB)
-               }
-       },
-
-       {
-               .mfr = CFI_MFR_MX,
-               .id = 0x2249,                           /* MX29LV160AB: 2MB */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2, 8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(31, 64*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_MX,
-               .id = 0x22C4,                           /* MX29LV160AT: 2MB */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(31, 64*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(2, 8*KB),
-                       ERASE_REGION(1, 16*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_ATMEL,
-               .id = 0x00c0,                           /* Atmel 49BV1614 */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 3,
-               .erase_region_info =
-               {
-                       ERASE_REGION(8,  8*KB),
-                       ERASE_REGION(2, 32*KB),
-                       ERASE_REGION(30, 64*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_ATMEL,
-               .id = 0xC2,                                     /* Atmel 49BV1614T */
-               .pri_id = 0x02,
-               .dev_size = 2*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 3,
-               .erase_region_info =
-               {
-                       ERASE_REGION(30, 64*KB),
-                       ERASE_REGION(2, 32*KB),
-                       ERASE_REGION(8,  8*KB)
-               }
-       },
-       {
-               .mfr = CFI_MFR_AMD,
-               .id = 0x225b,                           /* S29AL008D */
-               .pri_id = 0x02,
-               .dev_size = 1*MB,
-               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
-               .max_buf_write_size = 0x0,
-               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
-               .num_erase_regions = 4,
-               .erase_region_info =
-               {
-                       ERASE_REGION(1, 16*KB),
-                       ERASE_REGION(2, 8*KB),
-                       ERASE_REGION(1, 32*KB),
-                       ERASE_REGION(15, 64*KB)
-               }
-       },
-       {
-               .mfr = 0,
-               .id = 0,
-       }
-};
-
-void cfi_fixup_non_cfi(struct flash_bank *bank)
-{
-       struct cfi_flash_bank *cfi_info = bank->driver_priv;
-       struct non_cfi *non_cfi = non_cfi_flashes;
-
-       for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
-       {
-               if ((cfi_info->manufacturer == non_cfi->mfr)
-                       && (cfi_info->device_id == non_cfi->id))
-               {
-                       break;
-               }
-       }
-
-       /* only fixup jedec flashs found in table */
-       if (!non_cfi->mfr)
-               return;
-
-       cfi_info->not_cfi = 1;
-
-       /* fill in defaults for non-critical data */
-       cfi_info->vcc_min = 0x0;
-       cfi_info->vcc_max = 0x0;
-       cfi_info->vpp_min = 0x0;
-       cfi_info->vpp_max = 0x0;
-       cfi_info->word_write_timeout_typ = 0x0;
-       cfi_info->buf_write_timeout_typ = 0x0;
-       cfi_info->block_erase_timeout_typ = 0x0;
-       cfi_info->chip_erase_timeout_typ = 0x0;
-       cfi_info->word_write_timeout_max = 0x0;
-       cfi_info->buf_write_timeout_max = 0x0;
-       cfi_info->block_erase_timeout_max = 0x0;
-       cfi_info->chip_erase_timeout_max = 0x0;
-
-       cfi_info->qry[0] = 'Q';
-       cfi_info->qry[1] = 'R';
-       cfi_info->qry[2] = 'Y';
-
-       cfi_info->pri_id = non_cfi->pri_id;
-       cfi_info->pri_addr = 0x0;
-       cfi_info->alt_id = 0x0;
-       cfi_info->alt_addr = 0x0;
-       cfi_info->alt_ext = NULL;
-
-       cfi_info->interface_desc = non_cfi->interface_desc;
-       cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
-       cfi_info->status_poll_mask = non_cfi->status_poll_mask;
-       cfi_info->num_erase_regions = non_cfi->num_erase_regions;
-       cfi_info->erase_region_info = non_cfi->erase_region_info;
-       cfi_info->dev_size = non_cfi->dev_size;
-
-       if (cfi_info->pri_id == 0x2)
-       {
-               struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
-
-               pri_ext->pri[0] = 'P';
-               pri_ext->pri[1] = 'R';
-               pri_ext->pri[2] = 'I';
-
-               pri_ext->major_version = '1';
-               pri_ext->minor_version = '0';
-
-               pri_ext->SiliconRevision = 0x0;
-               pri_ext->EraseSuspend = 0x0;
-               pri_ext->EraseSuspend = 0x0;
-               pri_ext->BlkProt = 0x0;
-               pri_ext->TmpBlkUnprotect = 0x0;
-               pri_ext->BlkProtUnprot = 0x0;
-               pri_ext->SimultaneousOps = 0x0;
-               pri_ext->BurstMode = 0x0;
-               pri_ext->PageMode = 0x0;
-               pri_ext->VppMin = 0x0;
-               pri_ext->VppMax = 0x0;
-               pri_ext->TopBottom = 0x0;
-
-               pri_ext->_unlock1 = 0x5555;
-               pri_ext->_unlock2 = 0x2AAA;
-               pri_ext->_reversed_geometry = 0;
-
-               cfi_info->pri_ext = pri_ext;
-       } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
-       {
-               LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
-               exit(-1);
-       }
-}
diff --git a/src/flash/non_cfi.h b/src/flash/non_cfi.h
deleted file mode 100644 (file)
index 44c92db..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef NON_CFI_H
-#define NON_CFI_H
-
-#include "flash.h"
-
-struct non_cfi
-{
-       uint16_t mfr;
-       uint16_t id;
-       uint16_t pri_id;
-       uint32_t dev_size;
-       uint16_t interface_desc;
-       uint16_t max_buf_write_size;
-       uint8_t num_erase_regions;
-       uint32_t erase_region_info[6];
-       uint8_t  status_poll_mask;
-};
-
-void cfi_fixup_non_cfi(struct flash_bank *bank);
-
-#endif /* NON_CFI_H */
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
new file mode 100644 (file)
index 0000000..d2d9998
--- /dev/null
@@ -0,0 +1,46 @@
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/helper \
+       -I$(top_srcdir)/src/jtag \
+       -I$(top_srcdir)/src/flash \
+       -I$(top_srcdir)/src/target
+
+noinst_LTLIBRARIES = libocdflashnor.la
+libocdflashnor_la_SOURCES = \
+       aduc702x.c \
+       at91sam3.c \
+       at91sam7.c \
+       avrf.c \
+       cfi.c \
+       ecos.c \
+       faux.c \
+       lpc2000.c \
+       lpc288x.c \
+       lpc2900.c \
+       non_cfi.c \
+       ocl.c \
+       pic32mx.c \
+       stellaris.c \
+       stm32x.c \
+       str7x.c \
+       str9x.c \
+       str9xpec.c \
+       tms470.c
+
+noinst_HEADERS = \
+       at91sam7.h \
+       at91sam3.h \
+       avrf.h \
+       cfi.h \
+       lpc2000.h \
+       lpc288x.h \
+       non_cfi.h \
+       ocl.h \
+       pic32mx.h \
+       stellaris.h \
+       stm32x.h \
+       str7x.h \
+       str9x.h \
+       str9xpec.h \
+       tms470.h
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/src/flash/nor/aduc702x.c b/src/flash/nor/aduc702x.c
new file mode 100644 (file)
index 0000000..643705c
--- /dev/null
@@ -0,0 +1,425 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by Kevin McGuire                                   *
+ *   Copyright (C) 2008 by Marcel Wijlaars                                 *
+ *   Copyright (C) 2009 by Michael Ashton                                  *
+ *                                                                         *
+ *   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 "flash.h"
+#include "armv4_5.h"
+#include "binarybuffer.h"
+#include "time_support.h"
+#include "algorithm.h"
+
+
+static int aduc702x_build_sector_list(struct flash_bank *bank);
+static int aduc702x_check_flash_completion(struct target* target, unsigned int timeout_ms);
+static int aduc702x_set_write_enable(struct target *target, int enable);
+
+#define ADUC702x_FLASH                         0xfffff800
+#define ADUC702x_FLASH_FEESTA          (0*4)
+#define ADUC702x_FLASH_FEEMOD          (1*4)
+#define ADUC702x_FLASH_FEECON          (2*4)
+#define ADUC702x_FLASH_FEEDAT          (3*4)
+#define ADUC702x_FLASH_FEEADR          (4*4)
+#define ADUC702x_FLASH_FEESIGN         (5*4)
+#define ADUC702x_FLASH_FEEPRO          (6*4)
+#define ADUC702x_FLASH_FEEHIDE         (7*4)
+
+struct aduc702x_flash_bank {
+       struct working_area *write_algorithm;
+};
+
+/* flash bank aduc702x 0 0 0 0 <target#>
+ * The ADC7019-28 devices all have the same flash layout */
+FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
+{
+       struct aduc702x_flash_bank *nbank;
+
+       nbank = malloc(sizeof(struct aduc702x_flash_bank));
+
+        bank->base = 0x80000;
+        bank->size = 0xF800; // top 4k not accessible
+       bank->driver_priv = nbank;
+
+        aduc702x_build_sector_list(bank);
+
+        return ERROR_OK;
+}
+
+static int aduc702x_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 aduc702x_protect_check(struct flash_bank *bank)
+{
+       printf("aduc702x_protect_check not implemented yet.\n");
+       return ERROR_OK;
+}
+
+static int aduc702x_erase(struct flash_bank *bank, int first, int last)
+{
+        //int res;
+       int x;
+       int count;
+       //uint32_t v;
+       struct target *target = bank->target;
+
+        aduc702x_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, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff);
+               target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
+               target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
+
+                if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK)
+               {
+                       LOG_ERROR("mass erase failed\n");
+                        aduc702x_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, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
+                        target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
+
+                        if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
+                        {
+                                LOG_ERROR("failed to erase sector at address 0x%08lX\n", adr);
+                                aduc702x_set_write_enable(target, 0);
+                                return ERROR_FLASH_SECTOR_NOT_ERASED;
+                        }
+
+                        LOG_DEBUG("erased sector at address 0x%08lX\n", adr);
+                }
+        }
+
+        aduc702x_set_write_enable(target, 0);
+
+       return ERROR_OK;
+}
+
+static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       printf("aduc702x_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 aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 7000;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[6];
+       struct armv4_5_algorithm armv4_5_info;
+       int retval = ERROR_OK;
+
+       if (((count%2)!=0)||((offset%2)!=0))
+       {
+               LOG_ERROR("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 (0xFFFFF800)
+
+        registers:
+
+        r5 - scratch
+        r6 - set to 2, used to write flash command
+
+        */
+        uint32_t aduc702x_flash_write_code[] = {
+        //<_start>:
+                0xe3a05008,    // mov  r5, #8  ; 0x8
+                0xe5845004,    // str  r5, [r4, #4]
+                0xe3a06002,    // mov  r6, #2  ; 0x2
+        //<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  ; 0x4
+                0x1afffffc,    // bne  1001c <wait_complete>
+                0xe2822002,    // add  r2, r2, #2      ; 0x2
+                0xe2511001,    // subs r1, r1, #1      ; 0x1
+                0x0a000001,    // beq  1003c <done>
+                0xe3130001,    // tst  r3, #1  ; 0x1
+                0x1afffff3,    // bne  1000c <next>
+        //<done>:
+                0xeafffffe     // b    1003c <done>
+       };
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code),
+                &aduc702x_info->write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       retval=target_write_buffer(target, aduc702x_info->write_algorithm->address,
+                sizeof(aduc702x_flash_write_code), (uint8_t*)aduc702x_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 (aduc702x_info->write_algorithm)
+                               target_free_working_area(target, aduc702x_info->write_algorithm);
+
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
+       init_reg_param(&reg_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, 0xFFFFF800);
+
+               if ((retval = target_run_algorithm(target, 0, NULL, 5,
+                        reg_params, aduc702x_info->write_algorithm->address,
+                        aduc702x_info->write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4,
+                        10000, &armv4_5_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing aduc702x flash write algorithm");
+                       break;
+               }
+
+               if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1)
+               {
+                       /* FIX!!!! what does this mean??? replace w/sensible error message */
+                       LOG_ERROR("aduc702x detected error writing flash");
+                       retval = ERROR_FAIL;
+                       break;
+               }
+
+               buffer += thisrun_count;
+               address += thisrun_count;
+               count -= thisrun_count;
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, aduc702x_info->write_algorithm);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+
+       return retval;
+}
+
+/* All-JTAG, single-access method.  Very slow.  Used only if there is no
+ * working area available. */
+static int aduc702x_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;
+
+        aduc702x_set_write_enable(target, 1);
+
+       for (x = 0; x < count; x += 2) {
+                // FEEADR = address
+               target_write_u16(target, ADUC702x_FLASH + ADUC702x_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, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8));
+
+                // do single-write command
+               target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02);
+
+                if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
+                {
+                       LOG_ERROR("single write failed for address 0x%08lX\n", (unsigned long)(offset + x));
+                        aduc702x_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));
+
+        aduc702x_set_write_enable(target, 0);
+
+       return ERROR_OK;
+}
+
+int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       int retval;
+
+        /* try using a block write */
+        if ((retval = aduc702x_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("couldn't use block writes, falling back to single memory accesses");
+
+                        if ((retval = aduc702x_write_single(bank, buffer, offset, count)) != ERROR_OK)
+                        {
+                                LOG_ERROR("slow write failed");
+                                return ERROR_FLASH_OPERATION_FAILED;
+                        }
+                }
+        }
+
+        return retval;
+}
+
+static int aduc702x_probe(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "aduc702x flash driver info");
+       return ERROR_OK;
+}
+
+/* sets FEEMOD bit 3
+ * enable = 1 enables writes & erases, 0 disables them */
+static int aduc702x_set_write_enable(struct target *target, int enable)
+{
+        // don't bother to preserve int enable bit here
+        target_write_u16(target, ADUC702x_FLASH + ADUC702x_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 aduc702x_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, ADUC702x_FLASH + ADUC702x_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 aduc702x_flash = {
+               .name = "aduc702x",
+               .flash_bank_command = &aduc702x_flash_bank_command,
+               .erase = &aduc702x_erase,
+               .protect = &aduc702x_protect,
+               .write = &aduc702x_write,
+               .probe = &aduc702x_probe,
+               .auto_probe = &aduc702x_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &aduc702x_protect_check,
+               .info = &aduc702x_info
+       };
diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c
new file mode 100644 (file)
index 0000000..be17a5f
--- /dev/null
@@ -0,0 +1,2516 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Duane Ellis                                     *
+ *   openocd@duaneellis.com                                                *
+ *                                                                         *
+ *   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.             *
+****************************************************************************/
+
+/* Some of the the lower level code was based on code supplied by
+ * ATMEL under this copyright. */
+
+/* BEGIN ATMEL COPYRIGHT */
+/* ----------------------------------------------------------------------------
+ *         ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2009, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+/* END ATMEL COPYRIGHT */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include "types.h"
+#include "flash.h"
+#include "membuf.h"
+#include "at91sam3.h"
+#include "time_support.h"
+
+#define REG_NAME_WIDTH  (12)
+
+
+#define FLASH_BANK0_BASE   0x00080000
+#define FLASH_BANK1_BASE   0x00100000
+
+#define        AT91C_EFC_FCMD_GETD                 (0x0) // (EFC) Get Flash Descriptor
+#define        AT91C_EFC_FCMD_WP                   (0x1) // (EFC) Write Page
+#define        AT91C_EFC_FCMD_WPL                  (0x2) // (EFC) Write Page and Lock
+#define        AT91C_EFC_FCMD_EWP                  (0x3) // (EFC) Erase Page and Write Page
+#define        AT91C_EFC_FCMD_EWPL                 (0x4) // (EFC) Erase Page and Write Page then Lock
+#define        AT91C_EFC_FCMD_EA                   (0x5) // (EFC) Erase All
+// cmd6 is not present int he at91sam3u4/2/1 data sheet table 17-2
+// #define     AT91C_EFC_FCMD_EPL                  (0x6) // (EFC) Erase plane?
+// cmd7 is not present int he at91sam3u4/2/1 data sheet table 17-2
+// #define     AT91C_EFC_FCMD_EPA                  (0x7) // (EFC) Erase pages?
+#define        AT91C_EFC_FCMD_SLB                  (0x8) // (EFC) Set Lock Bit
+#define        AT91C_EFC_FCMD_CLB                  (0x9) // (EFC) Clear Lock Bit
+#define        AT91C_EFC_FCMD_GLB                  (0xA) // (EFC) Get Lock Bit
+#define        AT91C_EFC_FCMD_SFB                  (0xB) // (EFC) Set Fuse Bit
+#define        AT91C_EFC_FCMD_CFB                  (0xC) // (EFC) Clear Fuse Bit
+#define        AT91C_EFC_FCMD_GFB                  (0xD) // (EFC) Get Fuse Bit
+#define        AT91C_EFC_FCMD_STUI                 (0xE) // (EFC) Start Read Unique ID
+#define        AT91C_EFC_FCMD_SPUI                 (0xF) // (EFC) Stop Read Unique ID
+
+#define  offset_EFC_FMR   0
+#define  offset_EFC_FCR   4
+#define  offset_EFC_FSR   8
+#define  offset_EFC_FRR   12
+
+
+static float
+_tomhz(uint32_t freq_hz)
+{
+       float f;
+
+       f = ((float)(freq_hz)) / 1000000.0;
+       return f;
+}
+
+// How the chip is configured.
+struct sam3_cfg {
+       uint32_t unique_id[4];
+
+       uint32_t slow_freq;
+       uint32_t rc_freq;
+       uint32_t mainosc_freq;
+       uint32_t plla_freq;
+       uint32_t mclk_freq;
+       uint32_t cpu_freq;
+       uint32_t fclk_freq;
+       uint32_t pclk0_freq;
+       uint32_t pclk1_freq;
+       uint32_t pclk2_freq;
+
+
+#define SAM3_CHIPID_CIDR          (0x400E0740)
+       uint32_t CHIPID_CIDR;
+#define SAM3_CHIPID_EXID          (0x400E0744)
+       uint32_t CHIPID_EXID;
+
+#define SAM3_SUPC_CR              (0x400E1210)
+       uint32_t SUPC_CR;
+
+#define SAM3_PMC_BASE             (0x400E0400)
+#define SAM3_PMC_SCSR             (SAM3_PMC_BASE + 0x0008)
+       uint32_t PMC_SCSR;
+#define SAM3_PMC_PCSR             (SAM3_PMC_BASE + 0x0018)
+       uint32_t PMC_PCSR;
+#define SAM3_CKGR_UCKR            (SAM3_PMC_BASE + 0x001c)
+       uint32_t CKGR_UCKR;
+#define SAM3_CKGR_MOR             (SAM3_PMC_BASE + 0x0020)
+       uint32_t CKGR_MOR;
+#define SAM3_CKGR_MCFR            (SAM3_PMC_BASE + 0x0024)
+       uint32_t CKGR_MCFR;
+#define SAM3_CKGR_PLLAR           (SAM3_PMC_BASE + 0x0028)
+       uint32_t CKGR_PLLAR;
+#define SAM3_PMC_MCKR             (SAM3_PMC_BASE + 0x0030)
+       uint32_t PMC_MCKR;
+#define SAM3_PMC_PCK0             (SAM3_PMC_BASE + 0x0040)
+       uint32_t PMC_PCK0;
+#define SAM3_PMC_PCK1             (SAM3_PMC_BASE + 0x0044)
+       uint32_t PMC_PCK1;
+#define SAM3_PMC_PCK2             (SAM3_PMC_BASE + 0x0048)
+       uint32_t PMC_PCK2;
+#define SAM3_PMC_SR               (SAM3_PMC_BASE + 0x0068)
+       uint32_t PMC_SR;
+#define SAM3_PMC_IMR              (SAM3_PMC_BASE + 0x006c)
+       uint32_t PMC_IMR;
+#define SAM3_PMC_FSMR             (SAM3_PMC_BASE + 0x0070)
+       uint32_t PMC_FSMR;
+#define SAM3_PMC_FSPR             (SAM3_PMC_BASE + 0x0074)
+       uint32_t PMC_FSPR;
+};
+
+
+struct sam3_bank_private {
+       int probed;
+       // DANGER: THERE ARE DRAGONS HERE..
+       // NOTE: If you add more 'ghost' pointers
+       // be aware that you must *manually* update
+       // these pointers in the function sam3_GetDetails()
+       // See the comment "Here there be dragons"
+
+       // so we can find the chip we belong to
+       struct sam3_chip *pChip;
+       // so we can find the orginal bank pointer
+       struct flash_bank *pBank;
+       unsigned bank_number;
+       uint32_t controller_address;
+       uint32_t base_address;
+       bool present;
+       unsigned size_bytes;
+       unsigned nsectors;
+       unsigned sector_size;
+       unsigned page_size;
+};
+
+struct sam3_chip_details {
+       // THERE ARE DRAGONS HERE..
+       // note: If you add pointers here
+       // becareful about them as they
+       // may need to be updated inside
+       // the function: "sam3_GetDetails()
+       // which copy/overwrites the
+       // 'runtime' copy of this structure
+       uint32_t chipid_cidr;
+       const char *name;
+
+       unsigned n_gpnvms;
+#define SAM3_N_NVM_BITS 3
+       unsigned  gpnvm[SAM3_N_NVM_BITS];
+       unsigned  total_flash_size;
+       unsigned  total_sram_size;
+       unsigned  n_banks;
+#define SAM3_MAX_FLASH_BANKS 2
+       // these are "initialized" from the global const data
+       struct sam3_bank_private bank[SAM3_MAX_FLASH_BANKS];
+};
+
+
+struct sam3_chip {
+       struct sam3_chip *next;
+       int    probed;
+
+       // this is "initialized" from the global const structure
+       struct sam3_chip_details details;
+       struct target *target;
+       struct sam3_cfg cfg;
+
+       struct membuf *mbuf;
+};
+
+
+struct sam3_reg_list {
+       uint32_t address;  size_t struct_offset; const char *name;
+       void (*explain_func)(struct sam3_chip *pInfo);
+};
+
+
+static struct sam3_chip *all_sam3_chips;
+
+static struct sam3_chip *
+get_current_sam3(struct command_context *cmd_ctx)
+{
+       struct target *t;
+       static struct sam3_chip *p;
+
+       t = get_current_target(cmd_ctx);
+       if (!t) {
+               command_print(cmd_ctx, "No current target?");
+               return NULL;
+       }
+
+       p = all_sam3_chips;
+       if (!p) {
+               // this should not happen
+               // the command is not registered until the chip is created?
+               command_print(cmd_ctx, "No SAM3 chips exist?");
+               return NULL;
+       }
+
+       while (p) {
+               if (p->target == t) {
+                       return p;
+               }
+               p = p->next;
+       }
+       command_print(cmd_ctx, "Cannot find SAM3 chip?");
+       return NULL;
+}
+
+
+// these are used to *initialize* the "pChip->details" structure.
+static const struct sam3_chip_details all_sam3_details[] = {
+       {
+               .chipid_cidr    = 0x28100960,
+               .name           = "at91sam3u4e",
+               .total_flash_size     = 256 * 1024,
+               .total_sram_size      = 52 * 1024,
+               .n_gpnvms       = 3,
+               .n_banks        = 2,
+
+               // System boots at address 0x0
+               // gpnvm[1] = selects boot code
+               //     if gpnvm[1] == 0
+               //         boot is via "SAMBA" (rom)
+               //     else
+               //         boot is via FLASH
+               //         Selection is via gpnvm[2]
+               //     endif
+               //
+               // NOTE: banks 0 & 1 switch places
+               //     if gpnvm[2] == 0
+               //         Bank0 is the boot rom
+               //      else
+               //         Bank1 is the boot rom
+               //      endif
+//             .bank[0] = {
+               {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 0,
+                       .base_address = FLASH_BANK0_BASE,
+                       .controller_address = 0x400e0800,
+                       .present = 1,
+                       .size_bytes = 128 * 1024,
+                       .nsectors   = 16,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+
+//             .bank[1] = {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 1,
+                       .base_address = FLASH_BANK1_BASE,
+                       .controller_address = 0x400e0a00,
+                       .present = 1,
+                       .size_bytes = 128 * 1024,
+                       .nsectors   = 16,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+               },
+       },
+
+       {
+               .chipid_cidr    = 0x281a0760,
+               .name           = "at91sam3u2e",
+               .total_flash_size     = 128 * 1024,
+               .total_sram_size      =  36 * 1024,
+               .n_gpnvms       = 2,
+               .n_banks        = 1,
+
+               // System boots at address 0x0
+               // gpnvm[1] = selects boot code
+               //     if gpnvm[1] == 0
+               //         boot is via "SAMBA" (rom)
+               //     else
+               //         boot is via FLASH
+               //         Selection is via gpnvm[2]
+               //     endif
+//             .bank[0] = {
+               {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 0,
+                       .base_address = FLASH_BANK0_BASE,
+                       .controller_address = 0x400e0800,
+                       .present = 1,
+                       .size_bytes = 128 * 1024,
+                       .nsectors   = 16,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+//               .bank[1] = {
+                 {
+                       .present = 0,
+                       .probed = 0,
+                       .bank_number = 1,
+                 },
+               },
+       },
+       {
+               .chipid_cidr    = 0x28190560,
+               .name           = "at91sam3u1e",
+               .total_flash_size     = 64 * 1024,
+               .total_sram_size      = 20 * 1024,
+               .n_gpnvms       = 2,
+               .n_banks        = 1,
+
+               // System boots at address 0x0
+               // gpnvm[1] = selects boot code
+               //     if gpnvm[1] == 0
+               //         boot is via "SAMBA" (rom)
+               //     else
+               //         boot is via FLASH
+               //         Selection is via gpnvm[2]
+               //     endif
+               //
+
+//             .bank[0] = {
+               {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 0,
+                       .base_address = FLASH_BANK0_BASE,
+                       .controller_address = 0x400e0800,
+                       .present = 1,
+                       .size_bytes =  64 * 1024,
+                       .nsectors   =  8,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+
+//             .bank[1] = {
+                 {
+                       .present = 0,
+                       .probed = 0,
+                       .bank_number = 1,
+                 },
+               },
+       },
+
+       {
+               .chipid_cidr    = 0x28000960,
+               .name           = "at91sam3u4c",
+               .total_flash_size     = 256 * 1024,
+               .total_sram_size      = 52 * 1024,
+               .n_gpnvms       = 3,
+               .n_banks        = 2,
+
+               // System boots at address 0x0
+               // gpnvm[1] = selects boot code
+               //     if gpnvm[1] == 0
+               //         boot is via "SAMBA" (rom)
+               //     else
+               //         boot is via FLASH
+               //         Selection is via gpnvm[2]
+               //     endif
+               //
+               // NOTE: banks 0 & 1 switch places
+               //     if gpnvm[2] == 0
+               //         Bank0 is the boot rom
+               //      else
+               //         Bank1 is the boot rom
+               //      endif
+               {
+                 {
+//             .bank[0] = {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 0,
+                       .base_address = FLASH_BANK0_BASE,
+                       .controller_address = 0x400e0800,
+                       .present = 1,
+                       .size_bytes = 128 * 1024,
+                       .nsectors   = 16,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+//             .bank[1] = {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 1,
+                       .base_address = FLASH_BANK1_BASE,
+                       .controller_address = 0x400e0a00,
+                       .present = 1,
+                       .size_bytes = 128 * 1024,
+                       .nsectors   = 16,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+               },
+       },
+
+       {
+               .chipid_cidr    = 0x280a0760,
+               .name           = "at91sam3u2c",
+               .total_flash_size     = 128 * 1024,
+               .total_sram_size      = 36 * 1024,
+               .n_gpnvms       = 2,
+               .n_banks        = 1,
+
+               // System boots at address 0x0
+               // gpnvm[1] = selects boot code
+               //     if gpnvm[1] == 0
+               //         boot is via "SAMBA" (rom)
+               //     else
+               //         boot is via FLASH
+               //         Selection is via gpnvm[2]
+               //     endif
+               {
+//             .bank[0] = {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 0,
+                       .base_address = FLASH_BANK0_BASE,
+                       .controller_address = 0x400e0800,
+                       .present = 1,
+                       .size_bytes = 128 * 1024,
+                       .nsectors   = 16,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+//             .bank[1] = {
+                 {
+                       .present = 0,
+                       .probed = 0,
+                       .bank_number = 1,
+                 },
+               },
+       },
+       {
+               .chipid_cidr    = 0x28090560,
+               .name           = "at91sam3u1c",
+               .total_flash_size     = 64 * 1024,
+               .total_sram_size      = 20 * 1024,
+               .n_gpnvms       = 2,
+               .n_banks        = 1,
+
+               // System boots at address 0x0
+               // gpnvm[1] = selects boot code
+               //     if gpnvm[1] == 0
+               //         boot is via "SAMBA" (rom)
+               //     else
+               //         boot is via FLASH
+               //         Selection is via gpnvm[2]
+               //     endif
+               //
+
+               {
+//             .bank[0] = {
+                 {
+                       .probed = 0,
+                       .pChip  = NULL,
+                       .pBank  = NULL,
+                       .bank_number = 0,
+                       .base_address = FLASH_BANK0_BASE,
+                       .controller_address = 0x400e0800,
+                       .present = 1,
+                       .size_bytes =  64 * 1024,
+                       .nsectors   =  8,
+                       .sector_size = 8192,
+                       .page_size   = 256,
+                 },
+//             .bank[1] = {
+                 {
+                       .present = 0,
+                       .probed = 0,
+                       .bank_number = 1,
+
+                 },
+               },
+       },
+
+       // terminate
+       {
+               .chipid_cidr    = 0,
+               .name                   = NULL,
+       }
+};
+
+/* Globals above */
+/***********************************************************************
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+/* *ATMEL* style code - from the SAM3 driver code */
+
+/**
+ * Get the current status of the EEFC and
+ * the value of some status bits (LOCKE, PROGE).
+ * @param pPrivate - info about the bank
+ * @param v        - result goes here
+ */
+static int
+EFC_GetStatus(struct sam3_bank_private *pPrivate, uint32_t *v)
+{
+       int r;
+       r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FSR, v);
+       LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)",
+                         (unsigned int)(*v),
+                         ((unsigned int)((*v >> 2) & 1)),
+                         ((unsigned int)((*v >> 1) & 1)),
+                         ((unsigned int)((*v >> 0) & 1)));
+
+       return r;
+}
+
+/**
+ * Get the result of the last executed command.
+ * @param pPrivate - info about the bank
+ * @param v        - result goes here
+ */
+static int
+EFC_GetResult(struct sam3_bank_private *pPrivate, uint32_t *v)
+{
+       int r;
+       uint32_t rv;
+       r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FRR, &rv);
+       if (v) {
+               *v = rv;
+       }
+       LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv)));
+       return r;
+}
+
+static int
+EFC_StartCommand(struct sam3_bank_private *pPrivate,
+                                unsigned command, unsigned argument)
+{
+       uint32_t n,v;
+       int r;
+       int retry;
+
+       retry = 0;
+ do_retry:
+
+    // Check command & argument
+    switch (command) {
+
+       case AT91C_EFC_FCMD_WP:
+       case AT91C_EFC_FCMD_WPL:
+       case AT91C_EFC_FCMD_EWP:
+       case AT91C_EFC_FCMD_EWPL:
+               // case AT91C_EFC_FCMD_EPL:
+               // case AT91C_EFC_FCMD_EPA:
+       case AT91C_EFC_FCMD_SLB:
+       case AT91C_EFC_FCMD_CLB:
+               n = (pPrivate->size_bytes / pPrivate->page_size);
+               if (argument >= n) {
+                       LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n));
+               }
+               break;
+
+       case AT91C_EFC_FCMD_SFB:
+       case AT91C_EFC_FCMD_CFB:
+               if (argument >= pPrivate->pChip->details.n_gpnvms) {
+                       LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs",
+                                         pPrivate->pChip->details.n_gpnvms);
+               }
+               break;
+
+       case AT91C_EFC_FCMD_GETD:
+       case AT91C_EFC_FCMD_EA:
+       case AT91C_EFC_FCMD_GLB:
+       case AT91C_EFC_FCMD_GFB:
+       case AT91C_EFC_FCMD_STUI:
+       case AT91C_EFC_FCMD_SPUI:
+               if (argument != 0) {
+                       LOG_ERROR("Argument is meaningless for cmd: %d", command);
+               }
+               break;
+       default:
+               LOG_ERROR("Unknown command %d", command);
+               break;
+    }
+
+       if (command == AT91C_EFC_FCMD_SPUI) {
+               // this is a very special situation.
+               // Situation (1) - error/retry - see below
+               //      And we are being called recursively
+               // Situation (2) - normal, finished reading unique id
+       } else {
+               // it should be "ready"
+               EFC_GetStatus(pPrivate, &v);
+               if (v & 1) {
+                       // then it is ready
+                       // we go on
+               } else {
+                       if (retry) {
+                               // we have done this before
+                               // the controller is not responding.
+                               LOG_ERROR("flash controller(%d) is not ready! Error", pPrivate->bank_number);
+                               return ERROR_FAIL;
+                       } else {
+                               retry++;
+                               LOG_ERROR("Flash controller(%d) is not ready, attempting reset",
+                                                 pPrivate->bank_number);
+                               // we do that by issuing the *STOP* command
+                               EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0);
+                               // above is recursive, and further recursion is blocked by
+                               // if (command == AT91C_EFC_FCMD_SPUI) above
+                               goto do_retry;
+                       }
+               }
+       }
+
+       v = (0x5A << 24) | (argument << 8) | command;
+       LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v)));
+       r = target_write_u32(pPrivate->pBank->target,
+                                                 pPrivate->controller_address + offset_EFC_FCR,
+                                                 v);
+       if (r != ERROR_OK) {
+               LOG_DEBUG("Error Write failed");
+       }
+       return r;
+}
+
+/**
+ * Performs the given command and wait until its completion (or an error).
+ * @param pPrivate - info about the bank
+ * @param command  - Command to perform.
+ * @param argument - Optional command argument.
+ * @param status   - put command status bits here
+ */
+static int
+EFC_PerformCommand(struct sam3_bank_private *pPrivate,
+                                       unsigned command,
+                                       unsigned argument,
+                                       uint32_t *status)
+{
+
+       int r;
+       uint32_t v;
+       long long ms_now, ms_end;
+
+       // default
+       if (status) {
+               *status = 0;
+       }
+
+       r = EFC_StartCommand(pPrivate, command, argument);
+       if (r != ERROR_OK) {
+               return r;
+       }
+
+       ms_end = 500 + timeval_ms();
+
+
+    do {
+               r = EFC_GetStatus(pPrivate, &v);
+               if (r != ERROR_OK) {
+                       return r;
+               }
+               ms_now = timeval_ms();
+               if (ms_now > ms_end) {
+                       // error
+                       LOG_ERROR("Command timeout");
+                       return ERROR_FAIL;
+               }
+    }
+    while ((v & 1) == 0)
+               ;
+
+       // error bits..
+       if (status) {
+               *status = (v & 0x6);
+       }
+       return ERROR_OK;
+
+}
+
+
+
+
+
+/**
+ * Read the unique ID.
+ * @param pPrivate - info about the bank
+ * The unique ID is stored in the 'pPrivate' structure.
+ */
+static int
+FLASHD_ReadUniqueID (struct sam3_bank_private *pPrivate)
+{
+       int r;
+       uint32_t v;
+       int x;
+       // assume 0
+    pPrivate->pChip->cfg.unique_id[0] = 0;
+    pPrivate->pChip->cfg.unique_id[1] = 0;
+    pPrivate->pChip->cfg.unique_id[2] = 0;
+    pPrivate->pChip->cfg.unique_id[3] = 0;
+
+       LOG_DEBUG("Begin");
+       r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0);
+       if (r < 0) {
+               return r;
+       }
+
+       for (x = 0 ; x < 4 ; x++) {
+               r = target_read_u32(pPrivate->pChip->target,
+                                                        pPrivate->pBank->base + (x * 4),
+                                                        &v);
+               if (r < 0) {
+                       return r;
+               }
+               pPrivate->pChip->cfg.unique_id[x] = v;
+       }
+
+    r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL);
+       LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x",
+                         r,
+                         (unsigned int)(pPrivate->pChip->cfg.unique_id[0]),
+                         (unsigned int)(pPrivate->pChip->cfg.unique_id[1]),
+                         (unsigned int)(pPrivate->pChip->cfg.unique_id[2]),
+                         (unsigned int)(pPrivate->pChip->cfg.unique_id[3]));
+       return r;
+
+}
+
+/**
+ * Erases the entire flash.
+ * @param pPrivate - the info about the bank.
+ */
+static int
+FLASHD_EraseEntireBank(struct sam3_bank_private *pPrivate)
+{
+       LOG_DEBUG("Here");
+       return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL);
+}
+
+
+
+/**
+ * Gets current GPNVM state.
+ * @param pPrivate - info about the bank.
+ * @param gpnvm    -  GPNVM bit index.
+ * @param puthere  - result stored here.
+ */
+//------------------------------------------------------------------------------
+static int
+FLASHD_GetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere)
+{
+       uint32_t v;
+       int r;
+
+       LOG_DEBUG("Here");
+       if (pPrivate->bank_number != 0) {
+               LOG_ERROR("GPNVM only works with Bank0");
+               return ERROR_FAIL;
+       }
+
+       if (gpnvm >= pPrivate->pChip->details.n_gpnvms) {
+               LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
+                                 gpnvm,pPrivate->pChip->details.n_gpnvms);
+               return ERROR_FAIL;
+       }
+
+    // Get GPNVMs status
+       r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL);
+       if (r != ERROR_OK) {
+               LOG_ERROR("Failed");
+               return r;
+       }
+
+    r = EFC_GetResult(pPrivate, &v);
+
+       if (puthere) {
+               // Check if GPNVM is set
+               // get the bit and make it a 0/1
+               *puthere = (v >> gpnvm) & 1;
+       }
+
+       return r;
+}
+
+
+
+
+/**
+ * Clears the selected GPNVM bit.
+ * @param pPrivate info about the bank
+ * @param gpnvm GPNVM index.
+ * @returns 0 if successful; otherwise returns an error code.
+ */
+static int
+FLASHD_ClrGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm)
+{
+       int r;
+       unsigned v;
+
+       LOG_DEBUG("Here");
+       if (pPrivate->bank_number != 0) {
+               LOG_ERROR("GPNVM only works with Bank0");
+               return ERROR_FAIL;
+       }
+
+       if (gpnvm >= pPrivate->pChip->details.n_gpnvms) {
+               LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
+                                 gpnvm,pPrivate->pChip->details.n_gpnvms);
+               return ERROR_FAIL;
+       }
+
+       r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v);
+       if (r != ERROR_OK) {
+               LOG_DEBUG("Failed: %d",r);
+               return r;
+       }
+       r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL);
+       LOG_DEBUG("End: %d",r);
+       return r;
+}
+
+
+
+/**
+ * Sets the selected GPNVM bit.
+ * @param pPrivate info about the bank
+ * @param gpnvm GPNVM index.
+ */
+static int
+FLASHD_SetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm)
+{
+       int r;
+       unsigned v;
+
+       if (pPrivate->bank_number != 0) {
+               LOG_ERROR("GPNVM only works with Bank0");
+               return ERROR_FAIL;
+       }
+
+       if (gpnvm >= pPrivate->pChip->details.n_gpnvms) {
+               LOG_ERROR("Invalid GPNVM %d, max: %d, ignored",
+                                 gpnvm,pPrivate->pChip->details.n_gpnvms);
+               return ERROR_FAIL;
+       }
+
+       r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v);
+       if (r != ERROR_OK) {
+               return r;
+       }
+       if (v) {
+               // already set
+               r = ERROR_OK;
+       } else {
+               // set it
+               r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL);
+       }
+       return r;
+}
+
+
+/**
+ * Returns a bit field (at most 64) of locked regions within a page.
+ * @param pPrivate info about the bank
+ * @param v where to store locked bits
+ */
+static int
+FLASHD_GetLockBits(struct sam3_bank_private *pPrivate, uint32_t *v)
+{
+       int r;
+       LOG_DEBUG("Here");
+    r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL);
+       if (r == ERROR_OK) {
+               r = EFC_GetResult(pPrivate, v);
+       }
+       LOG_DEBUG("End: %d",r);
+       return r;
+}
+
+
+/**
+ * Unlocks all the regions in the given address range.
+ * @param pPrivate info about the bank
+ * @param start_sector first sector to unlock
+ * @param end_sector last (inclusive) to unlock
+ */
+
+static int
+FLASHD_Unlock(struct sam3_bank_private *pPrivate,
+                          unsigned start_sector,
+                          unsigned end_sector)
+{
+       int r;
+       uint32_t status;
+       uint32_t pg;
+       uint32_t pages_per_sector;
+
+       pages_per_sector = pPrivate->sector_size / pPrivate->page_size;
+
+    /* Unlock all pages */
+    while (start_sector <= end_sector) {
+               pg = start_sector * pages_per_sector;
+
+        r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status);
+        if (r != ERROR_OK) {
+            return r;
+        }
+        start_sector++;
+    }
+
+    return ERROR_OK;
+}
+
+
+/**
+ * Locks regions
+ * @param pPrivate - info about the bank
+ * @param start_sector - first sector to lock
+ * @param end_sector   - last sector (inclusive) to lock
+ */
+static int
+FLASHD_Lock(struct sam3_bank_private *pPrivate,
+                        unsigned start_sector,
+                        unsigned end_sector)
+{
+       uint32_t status;
+       uint32_t pg;
+       uint32_t pages_per_sector;
+       int r;
+
+       pages_per_sector = pPrivate->sector_size / pPrivate->page_size;
+
+    /* Lock all pages */
+    while (start_sector <= end_sector) {
+               pg = start_sector * pages_per_sector;
+
+        r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status);
+        if (r != ERROR_OK) {
+            return r;
+        }
+        start_sector++;
+    }
+    return ERROR_OK;
+}
+
+
+/****** END SAM3 CODE ********/
+
+/* begin helpful debug code */
+
+static void
+sam3_sprintf(struct sam3_chip *pChip , const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap,fmt);
+       if (pChip->mbuf == NULL) {
+               return;
+       }
+
+       membuf_vsprintf(pChip->mbuf, fmt, ap);
+       va_end(ap);
+}
+
+// print the fieldname, the field value, in dec & hex, and return field value
+static uint32_t
+sam3_reg_fieldname(struct sam3_chip *pChip,
+                                       const char *regname,
+                                       uint32_t value,
+                                       unsigned shift,
+                                       unsigned width)
+{
+       uint32_t v;
+       int hwidth, dwidth;
+
+
+       // extract the field
+       v = value >> shift;
+       v = v & ((1 << width)-1);
+       if (width <= 16) {
+               hwidth = 4;
+               dwidth = 5;
+       } else {
+               hwidth = 8;
+               dwidth = 12;
+       }
+
+       // show the basics
+       sam3_sprintf(pChip, "\t%*s: %*d [0x%0*x] ",
+                                 REG_NAME_WIDTH, regname,
+                                 dwidth, v,
+                                 hwidth, v);
+       return v;
+}
+
+
+static const char _unknown[] = "unknown";
+static const char * const eproc_names[] = {
+       _unknown,                                       // 0
+       "arm946es",                                     // 1
+       "arm7tdmi",                                     // 2
+       "cortex-m3",                            // 3
+       "arm920t",                                      // 4
+       "arm926ejs",                            // 5
+       _unknown,                                       // 6
+       _unknown,                                       // 7
+       _unknown,                                       // 8
+       _unknown,                                       // 9
+       _unknown,                                       // 10
+       _unknown,                                       // 11
+       _unknown,                                       // 12
+       _unknown,                                       // 13
+       _unknown,                                       // 14
+       _unknown,                                       // 15
+};
+
+#define nvpsize2 nvpsize               // these two tables are identical
+static const char * const nvpsize[] = {
+       "none",                                         //  0
+       "8K bytes",                                     //  1
+       "16K bytes",                            //  2
+       "32K bytes",                            //  3
+       _unknown,                                       //  4
+       "64K bytes",                            //  5
+       _unknown,                                       //  6
+       "128K bytes",                           //  7
+       _unknown,                                       //  8
+       "256K bytes",                           //  9
+       "512K bytes",                           // 10
+       _unknown,                                       // 11
+       "1024K bytes",                          // 12
+       _unknown,                                       // 13
+       "2048K bytes",                          // 14
+       _unknown,                                       // 15
+};
+
+
+static const char * const sramsize[] = {
+       "48K Bytes",                            //  0
+       "1K Bytes",                                     //  1
+       "2K Bytes",                                     //  2
+       "6K Bytes",                                     //  3
+       "112K Bytes",                           //  4
+       "4K Bytes",                                     //  5
+       "80K Bytes",                            //  6
+       "160K Bytes",                           //  7
+       "8K Bytes",                                     //  8
+       "16K Bytes",                            //  9
+       "32K Bytes",                            // 10
+       "64K Bytes",                            // 11
+       "128K Bytes",                           // 12
+       "256K Bytes",                           // 13
+       "96K Bytes",                            // 14
+       "512K Bytes",                           // 15
+
+};
+
+static const struct archnames { unsigned value; const char *name; } archnames[] = {
+       { 0x19,  "AT91SAM9xx Series"                                            },
+       { 0x29,  "AT91SAM9XExx Series"                                          },
+       { 0x34,  "AT91x34 Series"                                                       },
+       { 0x37,  "CAP7 Series"                                                          },
+       { 0x39,  "CAP9 Series"                                                          },
+       { 0x3B,  "CAP11 Series"                                                         },
+       { 0x40,  "AT91x40 Series"                                                       },
+       { 0x42,  "AT91x42 Series"                                                       },
+       { 0x55,  "AT91x55 Series"                                                       },
+       { 0x60,  "AT91SAM7Axx Series"                                           },
+       { 0x61,  "AT91SAM7AQxx Series"                                          },
+       { 0x63,  "AT91x63 Series"                                                       },
+       { 0x70,  "AT91SAM7Sxx Series"                                           },
+       { 0x71,  "AT91SAM7XCxx Series"                                          },
+       { 0x72,  "AT91SAM7SExx Series"                                          },
+       { 0x73,  "AT91SAM7Lxx Series"                                           },
+       { 0x75,  "AT91SAM7Xxx Series"                                           },
+       { 0x76,  "AT91SAM7SLxx Series"                                          },
+       { 0x80,  "ATSAM3UxC Series (100-pin version)"           },
+       { 0x81,  "ATSAM3UxE Series (144-pin version)"           },
+       { 0x83,  "ATSAM3AxC Series (100-pin version)"           },
+       { 0x84,  "ATSAM3XxC Series (100-pin version)"           },
+       { 0x85,  "ATSAM3XxE Series (144-pin version)"           },
+       { 0x86,  "ATSAM3XxG Series (208/217-pin version)"       },
+       { 0x88,  "ATSAM3SxA Series (48-pin version)"            },
+       { 0x89,  "ATSAM3SxB Series (64-pin version)"            },
+       { 0x8A,  "ATSAM3SxC Series (100-pin version)"           },
+       { 0x92,  "AT91x92 Series"                                                       },
+       { 0xF0,  "AT75Cxx Series"                                                       },
+       { -1, NULL },
+
+};
+
+static const char * const nvptype[] = {
+       "rom", // 0
+       "romless or onchip flash", // 1
+       "embedded flash memory", // 2
+       "rom(nvpsiz) + embedded flash (nvpsiz2)", //3
+       "sram emulating flash", // 4
+       _unknown, // 5
+       _unknown, // 6
+       _unknown, // 7
+
+};
+
+static const char *_yes_or_no(uint32_t v)
+{
+       if (v) {
+               return "YES";
+       } else {
+               return "NO";
+       }
+}
+
+static const char * const _rc_freq[] = {
+       "4 MHz", "8 MHz", "12 MHz", "reserved"
+};
+
+static void
+sam3_explain_ckgr_mor(struct sam3_chip *pChip)
+{
+       uint32_t v;
+       uint32_t rcen;
+
+       v = sam3_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1);
+       sam3_sprintf(pChip, "(main xtal enabled: %s)\n",
+                                 _yes_or_no(v));
+       v = sam3_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1);
+       sam3_sprintf(pChip, "(main osc bypass: %s)\n",
+                                 _yes_or_no(v));
+       rcen = sam3_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 2, 1);
+       sam3_sprintf(pChip, "(onchip RC-OSC enabled: %s)\n",
+                                 _yes_or_no(rcen));
+       v = sam3_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3);
+       sam3_sprintf(pChip, "(onchip RC-OSC freq: %s)\n",
+                                 _rc_freq[v]);
+
+       pChip->cfg.rc_freq = 0;
+       if (rcen) {
+               switch (v) {
+               default:
+                       pChip->cfg.rc_freq = 0;
+               case 0:
+                       pChip->cfg.rc_freq = 4 * 1000 * 1000;
+                       break;
+               case 1:
+                       pChip->cfg.rc_freq = 8 * 1000 * 1000;
+                       break;
+               case 2:
+                       pChip->cfg.rc_freq = 12* 1000 * 1000;
+                       break;
+               }
+       }
+
+       v = sam3_reg_fieldname(pChip,"MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8);
+       sam3_sprintf(pChip, "(startup clks, time= %f uSecs)\n",
+                                 ((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq)));
+       v = sam3_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1);
+       sam3_sprintf(pChip, "(mainosc source: %s)\n",
+                                 v ? "external xtal" : "internal RC");
+
+       v = sam3_reg_fieldname(pChip,"CFDEN", pChip->cfg.CKGR_MOR, 25, 1);
+       sam3_sprintf(pChip, "(clock failure enabled: %s)\n",
+                                _yes_or_no(v));
+}
+
+
+
+static void
+sam3_explain_chipid_cidr(struct sam3_chip *pChip)
+{
+       int x;
+       uint32_t v;
+       const char *cp;
+
+       sam3_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5);
+       sam3_sprintf(pChip,"\n");
+
+       v = sam3_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3);
+       sam3_sprintf(pChip, "%s\n", eproc_names[v]);
+
+       v = sam3_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4);
+       sam3_sprintf(pChip, "%s\n", nvpsize[v]);
+
+       v = sam3_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4);
+       sam3_sprintf(pChip, "%s\n", nvpsize2[v]);
+
+       v = sam3_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16,4);
+       sam3_sprintf(pChip, "%s\n", sramsize[ v ]);
+
+       v = sam3_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8);
+       cp = _unknown;
+       for (x = 0 ; archnames[x].name ; x++) {
+               if (v == archnames[x].value) {
+                       cp = archnames[x].name;
+                       break;
+               }
+       }
+
+       sam3_sprintf(pChip, "%s\n", cp);
+
+       v = sam3_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3);
+       sam3_sprintf(pChip, "%s\n", nvptype[ v ]);
+
+       v = sam3_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1);
+       sam3_sprintf(pChip, "(exists: %s)\n", _yes_or_no(v));
+}
+
+static void
+sam3_explain_ckgr_mcfr(struct sam3_chip *pChip)
+{
+       uint32_t v;
+
+
+       v = sam3_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1);
+       sam3_sprintf(pChip, "(main ready: %s)\n", _yes_or_no(v));
+
+       v = sam3_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16);
+
+       v = (v * pChip->cfg.slow_freq) / 16;
+       pChip->cfg.mainosc_freq = v;
+
+       sam3_sprintf(pChip, "(%3.03f Mhz (%d.%03dkhz slowclk)\n",
+                                _tomhz(v),
+                                pChip->cfg.slow_freq / 1000,
+                                pChip->cfg.slow_freq % 1000);
+
+}
+
+static void
+sam3_explain_ckgr_plla(struct sam3_chip *pChip)
+{
+       uint32_t mula,diva;
+
+       diva = sam3_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8);
+       sam3_sprintf(pChip,"\n");
+       mula = sam3_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11);
+       sam3_sprintf(pChip,"\n");
+       pChip->cfg.plla_freq = 0;
+       if (mula == 0) {
+               sam3_sprintf(pChip,"\tPLLA Freq: (Disabled,mula = 0)\n");
+       } else if (diva == 0) {
+               sam3_sprintf(pChip,"\tPLLA Freq: (Disabled,diva = 0)\n");
+       } else if (diva == 1) {
+               pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1));
+               sam3_sprintf(pChip,"\tPLLA Freq: %3.03f MHz\n",
+                                        _tomhz(pChip->cfg.plla_freq));
+       }
+}
+
+
+static void
+sam3_explain_mckr(struct sam3_chip *pChip)
+{
+       uint32_t css, pres, fin = 0;
+       int pdiv = 0;
+       const char *cp = NULL;
+
+       css = sam3_reg_fieldname(pChip, "CSS", pChip->cfg.PMC_MCKR, 0, 2);
+       switch (css & 3) {
+       case 0:
+               fin = pChip->cfg.slow_freq;
+               cp = "slowclk";
+               break;
+       case 1:
+               fin = pChip->cfg.mainosc_freq;
+               cp  = "mainosc";
+               break;
+       case 2:
+               fin = pChip->cfg.plla_freq;
+               cp  = "plla";
+               break;
+       case 3:
+               if (pChip->cfg.CKGR_UCKR & (1 << 16)) {
+                       fin = 480 * 1000 * 1000;
+                       cp = "upll";
+               } else {
+                       fin = 0;
+                       cp  = "upll (*ERROR* UPLL is disabled)";
+               }
+               break;
+       default:
+               assert(0);
+               break;
+       }
+
+       sam3_sprintf(pChip, "%s (%3.03f Mhz)\n",
+                                 cp,
+                                 _tomhz(fin));
+       pres = sam3_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3);
+       switch (pres & 0x07) {
+       case 0:
+               pdiv = 1;
+               cp = "selected clock";
+       case 1:
+               pdiv = 2;
+               cp = "clock/2";
+               break;
+       case 2:
+               pdiv = 4;
+               cp = "clock/4";
+               break;
+       case 3:
+               pdiv = 8;
+               cp = "clock/8";
+               break;
+       case 4:
+               pdiv = 16;
+               cp = "clock/16";
+               break;
+       case 5:
+               pdiv = 32;
+               cp = "clock/32";
+               break;
+       case 6:
+               pdiv = 64;
+               cp = "clock/64";
+               break;
+       case 7:
+               pdiv = 6;
+               cp = "clock/6";
+               break;
+       default:
+               assert(0);
+               break;
+       }
+       sam3_sprintf(pChip, "(%s)\n", cp);
+       fin = fin / pdiv;
+       // sam3 has a *SINGLE* clock -
+       // other at91 series parts have divisors for these.
+       pChip->cfg.cpu_freq = fin;
+       pChip->cfg.mclk_freq = fin;
+       pChip->cfg.fclk_freq = fin;
+       sam3_sprintf(pChip, "\t\tResult CPU Freq: %3.03f\n",
+                                 _tomhz(fin));
+}
+
+#if 0
+static struct sam3_chip *
+target2sam3(struct target *pTarget)
+{
+       struct sam3_chip *pChip;
+
+       if (pTarget == NULL) {
+               return NULL;
+       }
+
+       pChip = all_sam3_chips;
+       while (pChip) {
+               if (pChip->target == pTarget) {
+                       break; // return below
+               } else {
+                       pChip = pChip->next;
+               }
+       }
+       return pChip;
+}
+#endif
+
+static uint32_t *
+sam3_get_reg_ptr(struct sam3_cfg *pCfg, const struct sam3_reg_list *pList)
+{
+       // this function exists to help
+       // keep funky offsetof() errors
+       // and casting from causing bugs
+
+       // By using prototypes - we can detect what would
+       // be casting errors.
+
+       return ((uint32_t *)(((char *)(pCfg)) + pList->struct_offset));
+}
+
+
+#define SAM3_ENTRY(NAME, FUNC)  { .address = SAM3_ ## NAME, .struct_offset = offsetof(struct sam3_cfg, NAME), #NAME, FUNC }
+static const struct sam3_reg_list sam3_all_regs[] = {
+       SAM3_ENTRY(CKGR_MOR , sam3_explain_ckgr_mor),
+       SAM3_ENTRY(CKGR_MCFR , sam3_explain_ckgr_mcfr),
+       SAM3_ENTRY(CKGR_PLLAR , sam3_explain_ckgr_plla),
+       SAM3_ENTRY(CKGR_UCKR , NULL),
+       SAM3_ENTRY(PMC_FSMR , NULL),
+       SAM3_ENTRY(PMC_FSPR , NULL),
+       SAM3_ENTRY(PMC_IMR , NULL),
+       SAM3_ENTRY(PMC_MCKR , sam3_explain_mckr),
+       SAM3_ENTRY(PMC_PCK0 , NULL),
+       SAM3_ENTRY(PMC_PCK1 , NULL),
+       SAM3_ENTRY(PMC_PCK2 , NULL),
+       SAM3_ENTRY(PMC_PCSR , NULL),
+       SAM3_ENTRY(PMC_SCSR , NULL),
+       SAM3_ENTRY(PMC_SR , NULL),
+       SAM3_ENTRY(CHIPID_CIDR , sam3_explain_chipid_cidr),
+       SAM3_ENTRY(CHIPID_EXID , NULL),
+       SAM3_ENTRY(SUPC_CR, NULL),
+
+       // TERMINATE THE LIST
+       { .name = NULL }
+};
+#undef SAM3_ENTRY
+
+
+
+
+static struct sam3_bank_private *
+get_sam3_bank_private(struct flash_bank *bank)
+{
+       return (struct sam3_bank_private *)(bank->driver_priv);
+}
+
+/**
+ * Given a pointer to where it goes in the structure,
+ * determine the register name, address from the all registers table.
+ */
+static const struct sam3_reg_list *
+sam3_GetReg(struct sam3_chip *pChip, uint32_t *goes_here)
+{
+       const struct sam3_reg_list *pReg;
+
+       pReg = &(sam3_all_regs[0]);
+       while (pReg->name) {
+               uint32_t *pPossible;
+
+               // calculate where this one go..
+               // it is "possibly" this register.
+
+               pPossible = ((uint32_t *)(((char *)(&(pChip->cfg))) + pReg->struct_offset));
+
+               // well? Is it this register
+               if (pPossible == goes_here) {
+                       // Jump for joy!
+                       return pReg;
+               }
+
+               // next...
+               pReg++;
+       }
+       // This is *TOTAL*PANIC* - we are totally screwed.
+       LOG_ERROR("INVALID SAM3 REGISTER");
+       return NULL;
+}
+
+
+static int
+sam3_ReadThisReg(struct sam3_chip *pChip, uint32_t *goes_here)
+{
+       const struct sam3_reg_list *pReg;
+       int r;
+
+       pReg = sam3_GetReg(pChip, goes_here);
+       if (!pReg) {
+               return ERROR_FAIL;
+       }
+
+       r = target_read_u32(pChip->target, pReg->address, goes_here);
+       if (r != ERROR_OK) {
+               LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d\n",
+                                 pReg->name, (unsigned)(pReg->address), r);
+       }
+       return r;
+}
+
+
+
+static int
+sam3_ReadAllRegs(struct sam3_chip *pChip)
+{
+       int r;
+       const struct sam3_reg_list *pReg;
+
+       pReg = &(sam3_all_regs[0]);
+       while (pReg->name) {
+               r = sam3_ReadThisReg(pChip,
+                                                                 sam3_get_reg_ptr(&(pChip->cfg), pReg));
+               if (r != ERROR_OK) {
+                       LOG_ERROR("Cannot read SAM3 registere: %s @ 0x%08x, Error: %d\n",
+                                         pReg->name, ((unsigned)(pReg->address)), r);
+                       return r;
+               }
+
+               pReg++;
+       }
+
+       return ERROR_OK;
+}
+
+
+static int
+sam3_GetInfo(struct sam3_chip *pChip)
+{
+       const struct sam3_reg_list *pReg;
+       uint32_t regval;
+
+       membuf_reset(pChip->mbuf);
+
+
+       pReg = &(sam3_all_regs[0]);
+       while (pReg->name) {
+               // display all regs
+               LOG_DEBUG("Start: %s", pReg->name);
+               regval = *sam3_get_reg_ptr(&(pChip->cfg), pReg);
+               sam3_sprintf(pChip, "%*s: [0x%08x] -> 0x%08x\n",
+                                        REG_NAME_WIDTH,
+                                        pReg->name,
+                                        pReg->address,
+                                        regval);
+               if (pReg->explain_func) {
+                       (*(pReg->explain_func))(pChip);
+               }
+               LOG_DEBUG("End: %s", pReg->name);
+               pReg++;
+       }
+       sam3_sprintf(pChip,"   rc-osc: %3.03f MHz\n", _tomhz(pChip->cfg.rc_freq));
+       sam3_sprintf(pChip,"  mainosc: %3.03f MHz\n", _tomhz(pChip->cfg.mainosc_freq));
+       sam3_sprintf(pChip,"     plla: %3.03f MHz\n", _tomhz(pChip->cfg.plla_freq));
+       sam3_sprintf(pChip," cpu-freq: %3.03f MHz\n", _tomhz(pChip->cfg.cpu_freq));
+       sam3_sprintf(pChip,"mclk-freq: %3.03f MHz\n", _tomhz(pChip->cfg.mclk_freq));
+
+
+       sam3_sprintf(pChip, " UniqueId: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                 pChip->cfg.unique_id[0],
+                                 pChip->cfg.unique_id[1],
+                                 pChip->cfg.unique_id[2],
+                                 pChip->cfg.unique_id[3]);
+
+
+       return ERROR_OK;
+}
+
+
+static int
+sam3_erase_check(struct flash_bank *bank)
+{
+       int x;
+
+       LOG_DEBUG("Here");
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       if (0 == bank->num_sectors) {
+               LOG_ERROR("Target: not supported/not probed\n");
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("sam3 - supports auto-erase, erase_check ignored");
+       for (x = 0 ; x < bank->num_sectors ; x++) {
+               bank->sectors[x].is_erased = 1;
+       }
+
+       LOG_DEBUG("Done");
+       return ERROR_OK;
+}
+
+static int
+sam3_protect_check(struct flash_bank *bank)
+{
+       int r;
+       uint32_t v=0;
+       unsigned x;
+       struct sam3_bank_private *pPrivate;
+
+       LOG_DEBUG("Begin");
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       pPrivate = get_sam3_bank_private(bank);
+       if (!pPrivate) {
+               LOG_ERROR("no private for this bank?");
+               return ERROR_FAIL;
+       }
+       if (!(pPrivate->probed)) {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       r = FLASHD_GetLockBits(pPrivate , &v);
+       if (r != ERROR_OK) {
+               LOG_DEBUG("Failed: %d",r);
+               return r;
+       }
+
+       for (x = 0 ; x < pPrivate->nsectors ; x++) {
+               bank->sectors[x].is_protected = (!!(v & (1 << x)));
+       }
+       LOG_DEBUG("Done");
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
+{
+       struct sam3_chip *pChip;
+
+       pChip = all_sam3_chips;
+
+       // is this an existing chip?
+       while (pChip) {
+               if (pChip->target == bank->target) {
+                       break;
+               }
+               pChip = pChip->next;
+       }
+
+       if (!pChip) {
+               // this is a *NEW* chip
+               pChip = calloc(1, sizeof(struct sam3_chip));
+               if (!pChip) {
+                       LOG_ERROR("NO RAM!");
+                       return ERROR_FAIL;
+               }
+               pChip->target = bank->target;
+               // insert at head
+               pChip->next = all_sam3_chips;
+               all_sam3_chips = pChip;
+               pChip->target = bank->target;
+               // assumption is this runs at 32khz
+               pChip->cfg.slow_freq = 32768;
+               pChip->probed = 0;
+               pChip->mbuf = membuf_new();
+               if (!(pChip->mbuf)) {
+                       LOG_ERROR("no memory");
+                       return ERROR_FAIL;
+               }
+       }
+
+       switch (bank->base) {
+       default:
+               LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x)",
+                                 ((unsigned int)(bank->base)),
+                                 ((unsigned int)(FLASH_BANK0_BASE)),
+                                 ((unsigned int)(FLASH_BANK1_BASE)));
+               return ERROR_FAIL;
+               break;
+       case FLASH_BANK0_BASE:
+               bank->driver_priv = &(pChip->details.bank[0]);
+               bank->bank_number = 0;
+               pChip->details.bank[0].pChip = pChip;
+               pChip->details.bank[0].pBank = bank;
+               break;
+       case FLASH_BANK1_BASE:
+               bank->driver_priv = &(pChip->details.bank[1]);
+               bank->bank_number = 1;
+               pChip->details.bank[1].pChip = pChip;
+               pChip->details.bank[1].pBank = bank;
+               break;
+       }
+
+       // we initialize after probing.
+       return ERROR_OK;
+}
+
+static int
+sam3_GetDetails(struct sam3_bank_private *pPrivate)
+{
+       const struct sam3_chip_details *pDetails;
+       struct sam3_chip *pChip;
+       void *vp;
+       struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS];
+
+       unsigned x;
+       const char *cp;
+
+       LOG_DEBUG("Begin");
+       pDetails = all_sam3_details;
+       while (pDetails->name) {
+               if (pDetails->chipid_cidr == pPrivate->pChip->cfg.CHIPID_CIDR) {
+                       break;
+               } else {
+                       pDetails++;
+               }
+       }
+       if (pDetails->name == NULL) {
+               LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can this chip?)",
+                                 (unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR));
+               // Help the victim, print details about the chip
+               membuf_reset(pPrivate->pChip->mbuf);
+               membuf_sprintf(pPrivate->pChip->mbuf,
+                                               "SAM3 CHIPID_CIDR: 0x%08x decodes as follows\n",
+                                               pPrivate->pChip->cfg.CHIPID_CIDR);
+               sam3_explain_chipid_cidr(pPrivate->pChip);
+               cp = membuf_strtok(pPrivate->pChip->mbuf, "\n", &vp);
+               while (cp) {
+                       LOG_INFO("%s", cp);
+                       cp = membuf_strtok(NULL, "\n", &vp);
+               }
+               return ERROR_FAIL;
+       }
+
+       // DANGER: THERE ARE DRAGONS HERE
+
+       // get our pChip - it is going
+       // to be over-written shortly
+       pChip = pPrivate->pChip;
+
+       // Note that, in reality:
+       //
+       //     pPrivate = &(pChip->details.bank[0])
+       // or  pPrivate = &(pChip->details.bank[1])
+       //
+
+       // save the "bank" pointers
+       for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
+               saved_banks[ x ] = pChip->details.bank[x].pBank;
+       }
+
+       // Overwrite the "details" structure.
+       memcpy(&(pPrivate->pChip->details),
+                       pDetails,
+                       sizeof(pPrivate->pChip->details));
+
+       // now fix the ghosted pointers
+       for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
+               pChip->details.bank[x].pChip = pChip;
+               pChip->details.bank[x].pBank = saved_banks[x];
+       }
+
+       // update the *BANK*SIZE*
+
+       LOG_DEBUG("End");
+       return ERROR_OK;
+}
+
+
+
+static int
+_sam3_probe(struct flash_bank *bank, int noise)
+{
+       unsigned x;
+       int r;
+       struct sam3_bank_private *pPrivate;
+
+
+       LOG_DEBUG("Begin: Bank: %d, Noise: %d", bank->bank_number, noise);
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       pPrivate = get_sam3_bank_private(bank);
+       if (!pPrivate) {
+               LOG_ERROR("Invalid/unknown bank number\n");
+               return ERROR_FAIL;
+       }
+
+       r = sam3_ReadAllRegs(pPrivate->pChip);
+       if (r != ERROR_OK) {
+               return r;
+       }
+
+
+       LOG_DEBUG("Here");
+       r = sam3_GetInfo(pPrivate->pChip);
+       if (r != ERROR_OK) {
+               return r;
+       }
+       if (!(pPrivate->pChip->probed)) {
+               pPrivate->pChip->probed = 1;
+               LOG_DEBUG("Here");
+               r = sam3_GetDetails(pPrivate);
+               if (r != ERROR_OK) {
+                       return r;
+               }
+       }
+
+       // update the flash bank size
+       for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
+               if (bank->base == pPrivate->pChip->details.bank[0].base_address) {
+                       bank->size =  pPrivate->pChip->details.bank[0].size_bytes;
+                       break;
+               }
+       }
+
+       if (bank->sectors == NULL) {
+               bank->sectors     = calloc(pPrivate->nsectors, (sizeof((bank->sectors)[0])));
+               if (bank->sectors == NULL) {
+                       LOG_ERROR("No memory!");
+                       return ERROR_FAIL;
+               }
+               bank->num_sectors = pPrivate->nsectors;
+
+               for (x = 0 ; ((int)(x)) < bank->num_sectors ; x++) {
+                       bank->sectors[x].size         = pPrivate->sector_size;
+                       bank->sectors[x].offset       = x * (pPrivate->sector_size);
+                       // mark as unknown
+                       bank->sectors[x].is_erased    = -1;
+                       bank->sectors[x].is_protected = -1;
+               }
+       }
+
+       pPrivate->probed = 1;
+
+       r = sam3_protect_check(bank);
+       if (r != ERROR_OK) {
+               return r;
+       }
+
+       LOG_DEBUG("Bank = %d, nbanks = %d",
+                         pPrivate->bank_number , pPrivate->pChip->details.n_banks);
+       if ((pPrivate->bank_number + 1) == pPrivate->pChip->details.n_banks) {
+               // read unique id,
+               // it appears to be associated with the *last* flash bank.
+               FLASHD_ReadUniqueID(pPrivate);
+       }
+
+       return r;
+}
+
+static int
+sam3_probe(struct flash_bank *bank)
+{
+       return _sam3_probe(bank, 1);
+}
+
+static int
+sam3_auto_probe(struct flash_bank *bank)
+{
+       return _sam3_probe(bank, 0);
+}
+
+
+
+static int
+sam3_erase(struct flash_bank *bank, int first, int last)
+{
+       struct sam3_bank_private *pPrivate;
+       int r;
+
+       LOG_DEBUG("Here");
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       r = sam3_auto_probe(bank);
+       if (r != ERROR_OK) {
+               LOG_DEBUG("Here,r=%d",r);
+               return r;
+       }
+
+       pPrivate = get_sam3_bank_private(bank);
+       if (!(pPrivate->probed)) {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if ((first == 0) && ((last + 1)== ((int)(pPrivate->nsectors)))) {
+               // whole chip
+               LOG_DEBUG("Here");
+               return FLASHD_EraseEntireBank(pPrivate);
+       }
+       LOG_INFO("sam3 auto-erases while programing (request ignored)");
+       return ERROR_OK;
+}
+
+static int
+sam3_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       struct sam3_bank_private *pPrivate;
+       int r;
+
+       LOG_DEBUG("Here");
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       pPrivate = get_sam3_bank_private(bank);
+       if (!(pPrivate->probed)) {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if (set) {
+               r = FLASHD_Lock(pPrivate, (unsigned)(first), (unsigned)(last));
+       } else {
+               r = FLASHD_Unlock(pPrivate, (unsigned)(first), (unsigned)(last));
+       }
+       LOG_DEBUG("End: r=%d",r);
+
+       return r;
+
+}
+
+
+static int
+sam3_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       buf[ 0 ] = 0;
+       return ERROR_OK;
+}
+
+static int
+sam3_page_read(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf)
+{
+       uint32_t adr;
+       int r;
+
+       adr = pagenum * pPrivate->page_size;
+       adr += adr + pPrivate->base_address;
+
+       r = target_read_memory(pPrivate->pChip->target,
+                                                       adr,
+                                                       4, /* THIS*MUST*BE* in 32bit values */
+                                                       pPrivate->page_size / 4,
+                                                       buf);
+       if (r != ERROR_OK) {
+               LOG_ERROR("SAM3: Flash program failed to read page phys address: 0x%08x", (unsigned int)(adr));
+       }
+       return r;
+}
+
+// The code below is basically this:
+// compiled with
+// arm-none-eabi-gcc -mthumb -mcpu = cortex-m3 -O9 -S ./foobar.c -o foobar.s
+//
+// Only the *CPU* can write to the flash buffer.
+// the DAP cannot... so - we download this 28byte thing
+// Run the algorithm - (below)
+// to program the device
+//
+// ========================================
+// #include <stdint.h>
+//
+// struct foo {
+//   uint32_t *dst;
+//   const uint32_t *src;
+//   int   n;
+//   volatile uint32_t *base;
+//   uint32_t   cmd;
+// };
+//
+//
+// uint32_t sam3_function(struct foo *p)
+// {
+//   volatile uint32_t *v;
+//   uint32_t *d;
+//   const uint32_t *s;
+//   int   n;
+//   uint32_t r;
+//
+//   d = p->dst;
+//   s = p->src;
+//   n = p->n;
+//
+//   do {
+//     *d++ = *s++;
+//   } while (--n)
+//     ;
+//
+//   v = p->base;
+//
+//   v[ 1 ] = p->cmd;
+//   do {
+//     r = v[8/4];
+//   } while (!(r&1))
+//     ;
+//   return r;
+// }
+// ========================================
+
+
+
+static const uint8_t
+sam3_page_write_opcodes[] = {
+       //  24 0000 0446                mov     r4, r0
+       0x04,0x46,
+       //  25 0002 6168                ldr     r1, [r4, #4]
+       0x61,0x68,
+       //  26 0004 0068                ldr     r0, [r0, #0]
+       0x00,0x68,
+       //  27 0006 A268                ldr     r2, [r4, #8]
+       0xa2,0x68,
+       //  28                          @ lr needed for prologue
+       //  29                  .L2:
+       //  30 0008 51F8043B            ldr     r3, [r1], #4
+       0x51,0xf8,0x04,0x3b,
+       //  31 000c 12F1FF32            adds    r2, r2, #-1
+       0x12,0xf1,0xff,0x32,
+       //  32 0010 40F8043B            str     r3, [r0], #4
+       0x40,0xf8,0x04,0x3b,
+       //  33 0014 F8D1                bne     .L2
+       0xf8,0xd1,
+       //  34 0016 E268                ldr     r2, [r4, #12]
+       0xe2,0x68,
+       //  35 0018 2369                ldr     r3, [r4, #16]
+       0x23,0x69,
+       //  36 001a 5360                str     r3, [r2, #4]
+       0x53,0x60,
+       //  37 001c 0832                adds    r2, r2, #8
+       0x08,0x32,
+       //  38                  .L4:
+       //  39 001e 1068                ldr     r0, [r2, #0]
+       0x10,0x68,
+       //  40 0020 10F0010F            tst     r0, #1
+       0x10,0xf0,0x01,0x0f,
+       //  41 0024 FBD0                beq     .L4
+       0xfb,0xd0,
+       //  42                  .done:
+       //  43 0026 FEE7                b       .done
+       0xfe,0xe7
+};
+
+
+static int
+sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf)
+{
+       uint32_t adr;
+       uint32_t status;
+       int r;
+
+       adr = pagenum * pPrivate->page_size;
+       adr += (adr + pPrivate->base_address);
+
+       LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr));
+       r = target_write_memory(pPrivate->pChip->target,
+                                                        adr,
+                                                        4, /* THIS*MUST*BE* in 32bit values */
+                                                        pPrivate->page_size / 4,
+                                                        buf);
+       if (r != ERROR_OK) {
+               LOG_ERROR("SAM3: Failed to write (buffer) page at phys address 0x%08x", (unsigned int)(adr));
+               return r;
+       }
+
+       r = EFC_PerformCommand(pPrivate,
+                                                       // send Erase & Write Page
+                                                       AT91C_EFC_FCMD_EWP,
+                                                       pagenum,
+                                                       &status);
+
+       if (r != ERROR_OK) {
+               LOG_ERROR("SAM3: Error performing Erase & Write page @ phys address 0x%08x", (unsigned int)(adr));
+       }
+       if (status & (1 << 2)) {
+               LOG_ERROR("SAM3: Page @ Phys address 0x%08x is locked", (unsigned int)(adr));
+               return ERROR_FAIL;
+       }
+       if (status & (1 << 1)) {
+               LOG_ERROR("SAM3: Flash Command error @phys address 0x%08x", (unsigned int)(adr));
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+
+
+
+
+static int
+sam3_write(struct flash_bank *bank,
+                  uint8_t *buffer,
+                  uint32_t offset,
+                  uint32_t count)
+{
+       int n;
+       unsigned page_cur;
+       unsigned page_end;
+       int r;
+       unsigned page_offset;
+       struct sam3_bank_private *pPrivate;
+       uint8_t *pagebuffer;
+
+       // incase we bail further below, set this to null
+       pagebuffer = NULL;
+
+       // ignore dumb requests
+       if (count == 0) {
+               r = ERROR_OK;
+               goto done;
+       }
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               r = ERROR_TARGET_NOT_HALTED;
+               goto done;
+       }
+
+       pPrivate = get_sam3_bank_private(bank);
+       if (!(pPrivate->probed)) {
+               r = ERROR_FLASH_BANK_NOT_PROBED;
+               goto done;
+       }
+
+
+       if ((offset + count) > pPrivate->size_bytes) {
+               LOG_ERROR("Flash write error - past end of bank");
+               LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x",
+                                 (unsigned int)(offset),
+                                 (unsigned int)(count),
+                                 (unsigned int)(pPrivate->size_bytes));
+               r = ERROR_FAIL;
+               goto done;
+       }
+
+       pagebuffer = malloc(pPrivate->page_size);
+       if( !pagebuffer ){
+               LOG_ERROR("No memory for %d Byte page buffer", (int)(pPrivate->page_size));
+               r = ERROR_FAIL;
+               goto done;
+       }
+
+       // what page do we start & end in?
+       page_cur = offset / pPrivate->page_size;
+       page_end = (offset + count - 1) / pPrivate->page_size;
+
+       LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count));
+       LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end));
+
+       // Special case: all one page
+       //
+       // Otherwise:
+       //    (1) non-aligned start
+       //    (2) body pages
+       //    (3) non-aligned end.
+
+       // Handle special case - all one page.
+       if (page_cur == page_end) {
+               LOG_DEBUG("Special case, all in one page");
+               r = sam3_page_read(pPrivate, page_cur, pagebuffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+
+               page_offset = (offset & (pPrivate->page_size-1));
+               memcpy(pagebuffer + page_offset,
+                               buffer,
+                               count);
+
+               r = sam3_page_write(pPrivate, page_cur, pagebuffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+               r = ERROR_OK;
+               goto done;
+       }
+
+       // non-aligned start
+       page_offset = offset & (pPrivate->page_size - 1);
+       if (page_offset) {
+               LOG_DEBUG("Not-Aligned start");
+               // read the partial
+               r = sam3_page_read(pPrivate, page_cur, pagebuffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+
+               // over-write with new data
+               n = (pPrivate->page_size - page_offset);
+               memcpy(pagebuffer + page_offset,
+                               buffer,
+                               n);
+
+               r = sam3_page_write(pPrivate, page_cur, pagebuffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+
+               count  -= n;
+               offset += n;
+               buffer += n;
+               page_cur++;
+       }
+
+       // intermediate large pages
+       // also - the final *terminal*
+       // if that terminal page is a full page
+       LOG_DEBUG("Full Page Loop: cur=%d, end=%d, count = 0x%08x",
+                         (int)page_cur, (int)page_end, (unsigned int)(count));
+
+       while ((page_cur < page_end) &&
+                  (count >= pPrivate->page_size)) {
+               r = sam3_page_write(pPrivate, page_cur, buffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+               count    -= pPrivate->page_size;
+               buffer   += pPrivate->page_size;
+               page_cur += 1;
+       }
+
+       // terminal partial page?
+       if (count) {
+               LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count));
+               // we have a partial page
+               r = sam3_page_read(pPrivate, page_cur, pagebuffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+               // data goes at start
+               memcpy(pagebuffer, buffer, count);
+               r = sam3_page_write(pPrivate, page_cur, pagebuffer);
+               if (r != ERROR_OK) {
+                       goto done;
+               }
+               buffer += count;
+               count  -= count;
+       }
+       LOG_DEBUG("Done!");
+       r = ERROR_OK;
+ done:
+       if( pagebuffer ){
+               free(pagebuffer);
+       }
+       return r;
+}
+
+COMMAND_HANDLER(sam3_handle_info_command)
+{
+       struct sam3_chip *pChip;
+       void *vp;
+       const char *cp;
+       unsigned x;
+       int r;
+
+       pChip = get_current_sam3(CMD_CTX);
+       if (!pChip) {
+               return ERROR_OK;
+       }
+
+       r = 0;
+
+       // bank0 must exist before we can do anything
+       if (pChip->details.bank[0].pBank == NULL) {
+               x = 0;
+       need_define:
+               command_print(CMD_CTX,
+                                          "Please define bank %d via command: flash bank %s ... ",
+                                          x,
+                                          at91sam3_flash.name);
+               return ERROR_FAIL;
+       }
+
+       // if bank 0 is not probed, then probe it
+       if (!(pChip->details.bank[0].probed)) {
+               r = sam3_auto_probe(pChip->details.bank[0].pBank);
+               if (r != ERROR_OK) {
+                       return ERROR_FAIL;
+               }
+       }
+       // above garentees the "chip details" structure is valid
+       // and thus, bank private areas are valid
+       // and we have a SAM3 chip, what a concept!
+
+
+       // auto-probe other banks, 0 done above
+    for (x = 1 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
+               // skip banks not present
+               if (!(pChip->details.bank[x].present)) {
+                       continue;
+               }
+
+               if (pChip->details.bank[x].pBank == NULL) {
+                       goto need_define;
+               }
+
+               if (pChip->details.bank[x].probed) {
+                       continue;
+               }
+
+               r = sam3_auto_probe(pChip->details.bank[x].pBank);
+               if (r != ERROR_OK) {
+                       return r;
+               }
+       }
+
+
+       r = sam3_GetInfo(pChip);
+       if (r != ERROR_OK) {
+               LOG_DEBUG("Sam3Info, Failed %d\n",r);
+               return r;
+       }
+
+
+       // print results
+       cp = membuf_strtok(pChip->mbuf, "\n", &vp);
+       while (cp) {
+               command_print(CMD_CTX,"%s", cp);
+               cp = membuf_strtok(NULL, "\n", &vp);
+       }
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sam3_handle_gpnvm_command)
+{
+       unsigned x,v;
+       int r,who;
+       struct sam3_chip *pChip;
+
+       pChip = get_current_sam3(CMD_CTX);
+       if (!pChip) {
+               return ERROR_OK;
+       }
+
+       if (pChip->target->state != TARGET_HALTED) {
+               LOG_ERROR("sam3 - target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+
+       if (pChip->details.bank[0].pBank == NULL) {
+               command_print(CMD_CTX, "Bank0 must be defined first via: flash bank %s ...",
+                                          at91sam3_flash.name);
+               return ERROR_FAIL;
+       }
+       if (!pChip->details.bank[0].probed) {
+               r = sam3_auto_probe(pChip->details.bank[0].pBank);
+               if (r != ERROR_OK) {
+                       return r;
+               }
+       }
+
+
+       switch (CMD_ARGC) {
+       default:
+               command_print(CMD_CTX,"Too many parameters\n");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+               break;
+       case 0:
+               who = -1;
+               goto showall;
+               break;
+       case 1:
+               who = -1;
+               break;
+       case 2:
+               if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) {
+                       who = -1;
+               } else {
+                       uint32_t v32;
+                       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32);
+                       who = v32;
+               }
+               break;
+       }
+
+       if (0 == strcmp("show", CMD_ARGV[0])) {
+               if (who == -1) {
+               showall:
+                       r = ERROR_OK;
+                       for (x = 0 ; x < pChip->details.n_gpnvms ; x++) {
+                               r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v);
+                               if (r != ERROR_OK) {
+                                       break;
+                               }
+                               command_print(CMD_CTX, "sam3-gpnvm%u: %u", x, v);
+                       }
+                       return r;
+               }
+               if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
+                       r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
+                       command_print(CMD_CTX, "sam3-gpnvm%u: %u", who, v);
+                       return r;
+               } else {
+                       command_print(CMD_CTX, "sam3-gpnvm invalid GPNVM: %u", who);
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+       }
+
+       if (who == -1) {
+               command_print(CMD_CTX, "Missing GPNVM number");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (0 == strcmp("set", CMD_ARGV[0])) {
+               r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who);
+       } else if ((0 == strcmp("clr", CMD_ARGV[0])) ||
+                          (0 == strcmp("clear", CMD_ARGV[0]))) { // quietly accept both
+               r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who);
+       } else {
+               command_print(CMD_CTX, "Unkown command: %s", CMD_ARGV[0]);
+               r = ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       return r;
+}
+
+COMMAND_HANDLER(sam3_handle_slowclk_command)
+{
+       struct sam3_chip *pChip;
+
+       pChip = get_current_sam3(CMD_CTX);
+       if (!pChip) {
+               return ERROR_OK;
+       }
+
+
+       switch (CMD_ARGC) {
+       case 0:
+               // show
+               break;
+       case 1:
+       {
+               // set
+               uint32_t v;
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v);
+               if (v > 200000) {
+                       // absurd slow clock of 200Khz?
+                       command_print(CMD_CTX,"Absurd/illegal slow clock freq: %d\n", (int)(v));
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               pChip->cfg.slow_freq = v;
+               break;
+       }
+       default:
+               // error
+               command_print(CMD_CTX,"Too many parameters");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+               break;
+       }
+       command_print(CMD_CTX, "Slowclk freq: %d.%03dkhz",
+                                  (int)(pChip->cfg.slow_freq/ 1000),
+                                  (int)(pChip->cfg.slow_freq% 1000));
+       return ERROR_OK;
+}
+
+static const struct command_registration at91sam3_exec_command_handlers[] = {
+       {
+               .name = "gpnvm",
+               .handler = &sam3_handle_gpnvm_command,
+               .mode = COMMAND_EXEC,
+               .usage = "[(set|clear) [<bit_id>]]",
+               .help = "Without arguments, shows the gpnvm register; "
+                       "otherwise, sets or clear the specified bit.",
+       },
+       {
+               .name = "info",
+               .handler = &sam3_handle_info_command,
+               .mode = COMMAND_EXEC,
+               .help = "print information about the current sam3 chip",
+       },
+       {
+               .name = "slowclk",
+               .handler = &sam3_handle_slowclk_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<value>",
+               .help = "set the slowclock frequency (default 32768hz)",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration at91sam3_command_handlers[] = {
+       {
+               .name = "at91sam3",
+               .mode = COMMAND_ANY,
+               .help = "at91sam3 flash command group",
+               .chain = at91sam3_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver at91sam3_flash = {
+               .name = "at91sam3",
+               .commands = at91sam3_command_handlers,
+               .flash_bank_command = &sam3_flash_bank_command,
+               .erase = &sam3_erase,
+               .protect = &sam3_protect,
+               .write = &sam3_write,
+               .probe = &sam3_probe,
+               .auto_probe = &sam3_auto_probe,
+               .erase_check = &sam3_erase_check,
+               .protect_check = &sam3_protect_check,
+               .info = &sam3_info,
+       };
diff --git a/src/flash/nor/at91sam3.h b/src/flash/nor/at91sam3.h
new file mode 100644 (file)
index 0000000..4fa7f46
--- /dev/null
@@ -0,0 +1,23 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Duane Ellis                                     *
+ *   openocd@duaneellis.com                                                *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+
+// nothing to do here other then export this.
+extern struct flash_driver at91sam3_flash;
diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c
new file mode 100644 (file)
index 0000000..f9b87ba
--- /dev/null
@@ -0,0 +1,1213 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Magnus Lundin                                   *
+ *   lundin@mlu.mine.nu                                                    *
+ *                                                                         *
+ *   Copyright (C) 2008 by Gheorghe Guran (atlas)                          *
+ *                                                                         *
+ *   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.             *
+****************************************************************************/
+
+/***************************************************************************
+*
+* New flash setup command:
+*
+* flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_id>
+*      [<chip_type> <banks>
+*       <sectors_per_bank> <pages_per_sector>
+*       <page_size> <num_nvmbits>
+*       <ext_freq_khz>]
+*
+*   <ext_freq_khz> - MUST be used if clock is from external source,
+*                    CAN be used if main oscillator frequency is known (recommended)
+* Examples:
+* ==== RECOMMENDED (covers clock speed) ============
+*  flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 25000
+*                      (if auto-detect fails; provides clock spec)
+*  flash bank at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 25000
+*                      (auto-detect everything except the clock)
+* ==== NOT RECOMMENDED !!! (clock speed is not configured) ====
+*  flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 0
+*                      (if auto-detect fails)
+*  flash bank at91sam7 0 0 0 0 $_TARGETNAME
+*                      (old style, auto-detect everything)
+****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "at91sam7.h"
+#include "binarybuffer.h"
+
+static int at91sam7_protect_check(struct flash_bank *bank);
+static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
+
+static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
+static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
+static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
+static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen);
+
+static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
+static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
+static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
+
+static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
+
+#if 0
+static long SRAMSIZ[16] = {
+       -1,
+       0x0400,         /*  1K */
+       0x0800,         /*  2K */
+       -1,
+       0x1c000,        /* 112K */
+       0x1000,         /*   4K */
+       0x14000,        /*  80K */
+       0x28000,        /* 160K */
+       0x2000,         /*   8K */
+       0x4000,         /*  16K */
+       0x8000,         /*  32K */
+       0x10000,        /*  64K */
+       0x20000,        /* 128K */
+       0x40000,        /* 256K */
+       0x18000,        /*  96K */
+       0x80000,        /* 512K */
+};
+#endif
+
+
+static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
+{
+       uint32_t fsr;
+       target_read_u32(target, MC_FSR[bank_number], &fsr);
+
+       return fsr;
+}
+
+/* Read clock configuration and set at91sam7_info->mck_freq */
+static void at91sam7_read_clock_info(struct flash_bank *bank)
+{
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t mckr, mcfr, pllr, mor;
+       unsigned long tmp = 0, mainfreq;
+
+       /* Read Clock Generator Main Oscillator Register */
+       target_read_u32(target, CKGR_MOR, &mor);
+       /* Read Clock Generator Main Clock Frequency Register */
+       target_read_u32(target, CKGR_MCFR, &mcfr);
+       /* Read Master Clock Register*/
+       target_read_u32(target, PMC_MCKR, &mckr);
+       /* Read Clock Generator PLL Register  */
+       target_read_u32(target, CKGR_PLLR, &pllr);
+
+       at91sam7_info->mck_valid = 0;
+       at91sam7_info->mck_freq = 0;
+       switch (mckr & PMC_MCKR_CSS)
+       {
+               case 0:                 /* Slow Clock */
+                       at91sam7_info->mck_valid = 1;
+                       tmp = RC_FREQ;
+                       break;
+
+               case 1:                 /* Main Clock */
+                       if ((mcfr & CKGR_MCFR_MAINRDY) &&
+                               (at91sam7_info->ext_freq == 0))
+                       {
+                               at91sam7_info->mck_valid = 1;
+                               tmp = RC_FREQ / 16ul * (mcfr & 0xffff);
+                       }
+                       else if (at91sam7_info->ext_freq != 0)
+                       {
+                               at91sam7_info->mck_valid = 1;
+                               tmp = at91sam7_info->ext_freq;
+                       }
+                       break;
+
+               case 2:                 /* Reserved */
+                       break;
+
+               case 3:                 /* PLL Clock */
+                       if ((mcfr & CKGR_MCFR_MAINRDY) &&
+                               (at91sam7_info->ext_freq == 0))
+                       {
+                               target_read_u32(target, CKGR_PLLR, &pllr);
+                               if (!(pllr & CKGR_PLLR_DIV))
+                                       break; /* 0 Hz */
+                               at91sam7_info->mck_valid = 1;
+                               mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
+                               /* Integer arithmetic should have sufficient precision
+                                * as long as PLL is properly configured. */
+                               tmp = mainfreq / (pllr & CKGR_PLLR_DIV)*
+                                       (((pllr & CKGR_PLLR_MUL) >> 16) + 1);
+                       }
+                       else if ((at91sam7_info->ext_freq != 0) &&
+                               ((pllr&CKGR_PLLR_DIV) != 0))
+                       {
+                               at91sam7_info->mck_valid = 1;
+                               tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)*
+                                       (((pllr & CKGR_PLLR_MUL) >> 16) + 1);
+                       }
+                       break;
+       }
+
+       /* Prescaler adjust */
+       if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0))
+       {
+               at91sam7_info->mck_valid = 0;
+               at91sam7_info->mck_freq = 0;
+       }
+       else if (((mckr & PMC_MCKR_PRES) >> 2) != 0)
+               at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
+       else
+               at91sam7_info->mck_freq = tmp;
+}
+
+/* Setup the timimg registers for nvbits or normal flash */
+static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
+{
+       uint32_t fmr, fmcn = 0, fws = 0;
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       if (mode && (mode != at91sam7_info->flashmode))
+       {
+               /* Always round up (ceil) */
+               if (mode == FMR_TIMING_NVBITS)
+               {
+                       if (at91sam7_info->cidr_arch == 0x60)
+                       {
+                               /* AT91SAM7A3 uses master clocks in 100 ns */
+                               fmcn = (at91sam7_info->mck_freq/10000000ul) + 1;
+                       }
+                       else
+                       {
+                               /* master clocks in 1uS for ARCH 0x7 types */
+                               fmcn = (at91sam7_info->mck_freq/1000000ul) + 1;
+                       }
+               }
+               else if (mode == FMR_TIMING_FLASH)
+               {
+                       /* main clocks in 1.5uS */
+                       fmcn = (at91sam7_info->mck_freq/1000000ul)+
+                               (at91sam7_info->mck_freq/2000000ul) + 1;
+               }
+
+               /* hard overclocking */
+               if (fmcn > 0xFF)
+                       fmcn = 0xFF;
+
+               /* Only allow fmcn = 0 if clock period is > 30 us = 33kHz. */
+               if (at91sam7_info->mck_freq <= 33333ul)
+                       fmcn = 0;
+               /* Only allow fws = 0 if clock frequency is < 30 MHz. */
+               if (at91sam7_info->mck_freq > 30000000ul)
+                       fws = 1;
+
+               LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn));
+               fmr = fmcn << 16 | fws << 8;
+               target_write_u32(target, MC_FMR[bank->bank_number], fmr);
+       }
+
+       at91sam7_info->flashmode = mode;
+}
+
+static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
+{
+       uint32_t status;
+
+       while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0))
+       {
+               LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status);
+               alive_sleep(1);
+       }
+
+       LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status);
+
+       if (status & 0x0C)
+       {
+               LOG_ERROR("status register: 0x%" PRIx32 "", status);
+               if (status & 0x4)
+                       LOG_ERROR("Lock Error Bit Detected, Operation Abort");
+               if (status & 0x8)
+                       LOG_ERROR("Invalid command and/or bad keyword, Operation Abort");
+               if (status & 0x10)
+                       LOG_ERROR("Security Bit Set, Operation Abort");
+       }
+
+       return status;
+}
+
+/* Send one command to the AT91SAM flash controller */
+static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen)
+{
+       uint32_t fcr;
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
+       target_write_u32(target, MC_FCR[bank->bank_number], fcr);
+       LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen);
+
+       if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB)))
+       {
+               /* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
+               if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               return ERROR_OK;
+       }
+
+       if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C)
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+/* Read device id register, main clock frequency register and fill in driver info structure */
+static int at91sam7_read_part_info(struct flash_bank *bank)
+{
+       struct flash_bank *t_bank = bank;
+       struct at91sam7_flash_bank *at91sam7_info;
+       struct target *target = t_bank->target;
+
+       uint16_t bnk, sec;
+       uint16_t arch;
+       uint32_t cidr;
+       uint8_t banks_num = 0;
+       uint16_t num_nvmbits = 0;
+       uint16_t sectors_num = 0;
+       uint16_t pages_per_sector = 0;
+       uint16_t page_size = 0;
+       uint32_t ext_freq;
+       uint32_t bank_size;
+       uint32_t base_address = 0;
+       char *target_name = "Unknown";
+
+       at91sam7_info = t_bank->driver_priv;
+
+       if (at91sam7_info->cidr != 0)
+       {
+               /* flash already configured, update clock and check for protected sectors */
+               struct flash_bank *fb = bank;
+               t_bank = fb;
+
+               while (t_bank)
+               {
+                       /* re-calculate master clock frequency */
+                       at91sam7_read_clock_info(t_bank);
+
+                       /* no timming */
+                       at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);
+
+                       /* check protect state */
+                       at91sam7_protect_check(t_bank);
+
+                       t_bank = fb->next;
+                       fb = t_bank;
+               }
+
+               return ERROR_OK;
+       }
+
+       /* Read and parse chip identification register */
+       target_read_u32(target, DBGU_CIDR, &cidr);
+       if (cidr == 0)
+       {
+               LOG_WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (at91sam7_info->flash_autodetection == 0)
+       {
+               /* banks and sectors are already created, based on data from input file */
+               struct flash_bank *fb = bank;
+               t_bank = fb;
+               while (t_bank)
+               {
+                       at91sam7_info = t_bank->driver_priv;
+
+                       at91sam7_info->cidr = cidr;
+                       at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
+                       at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
+                       at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
+                       at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
+                       at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
+                       at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
+                       at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
+                       at91sam7_info->cidr_version = cidr&0x001F;
+
+                       /* calculate master clock frequency */
+                       at91sam7_read_clock_info(t_bank);
+
+                       /* no timming */
+                       at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);
+
+                       /* check protect state */
+                       at91sam7_protect_check(t_bank);
+
+                       t_bank = fb->next;
+                       fb = t_bank;
+               }
+
+               return ERROR_OK;
+       }
+
+       arch = (cidr >> 20)&0x00FF;
+
+       /* check flash size */
+       switch ((cidr >> 8)&0x000F)
+       {
+               case FLASH_SIZE_8KB:
+                       break;
+
+               case FLASH_SIZE_16KB:
+                       banks_num = 1;
+                       sectors_num = 8;
+                       pages_per_sector = 32;
+                       page_size  = 64;
+                       base_address = 0x00100000;
+                       if (arch == 0x70)
+                       {
+                               num_nvmbits = 2;
+                               target_name = "AT91SAM7S161/16";
+                       }
+                       break;
+
+               case FLASH_SIZE_32KB:
+                       banks_num = 1;
+                       sectors_num = 8;
+                       pages_per_sector = 32;
+                       page_size  = 128;
+                       base_address = 0x00100000;
+                       if (arch == 0x70)
+                       {
+                               num_nvmbits = 2;
+                               target_name = "AT91SAM7S321/32";
+                       }
+                       if (arch == 0x72)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7SE32";
+                       }
+                       break;
+
+               case FLASH_SIZE_64KB:
+                       banks_num = 1;
+                       sectors_num = 16;
+                       pages_per_sector = 32;
+                       page_size  = 128;
+                       base_address = 0x00100000;
+                       if (arch == 0x70)
+                       {
+                               num_nvmbits = 2;
+                               target_name = "AT91SAM7S64";
+                       }
+                       break;
+
+               case FLASH_SIZE_128KB:
+                       banks_num = 1;
+                       sectors_num = 8;
+                       pages_per_sector = 64;
+                       page_size  = 256;
+                       base_address = 0x00100000;
+                       if (arch == 0x70)
+                       {
+                               num_nvmbits = 2;
+                               target_name = "AT91SAM7S128";
+                       }
+                       if (arch == 0x71)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7XC128";
+                       }
+                       if (arch == 0x72)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7SE128";
+                       }
+                       if (arch == 0x75)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7X128";
+                       }
+                       break;
+
+               case FLASH_SIZE_256KB:
+                       banks_num = 1;
+                       sectors_num = 16;
+                       pages_per_sector = 64;
+                       page_size  = 256;
+                       base_address = 0x00100000;
+                       if (arch == 0x60)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7A3";
+                       }
+                       if (arch == 0x70)
+                       {
+                               num_nvmbits = 2;
+                               target_name = "AT91SAM7S256";
+                       }
+                       if (arch == 0x71)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7XC256";
+                       }
+                       if (arch == 0x72)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7SE256";
+                       }
+                       if (arch == 0x75)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7X256";
+                       }
+                       break;
+
+               case FLASH_SIZE_512KB:
+                       banks_num = 2;
+                       sectors_num = 16;
+                       pages_per_sector = 64;
+                       page_size  = 256;
+                       base_address = 0x00100000;
+                       if (arch == 0x70)
+                       {
+                               num_nvmbits = 2;
+                               target_name = "AT91SAM7S512";
+                       }
+                       if (arch == 0x71)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7XC512";
+                       }
+                       if (arch == 0x72)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7SE512";
+                       }
+                       if (arch == 0x75)
+                       {
+                               num_nvmbits = 3;
+                               target_name = "AT91SAM7X512";
+                       }
+                       break;
+
+               case FLASH_SIZE_1024KB:
+                       break;
+
+               case FLASH_SIZE_2048KB:
+                       break;
+       }
+
+       if (strcmp(target_name, "Unknown") == 0)
+       {
+               LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       ext_freq = at91sam7_info->ext_freq;
+
+       /* calculate bank size  */
+       bank_size = sectors_num * pages_per_sector * page_size;
+
+       for (bnk = 0; bnk < banks_num; bnk++)
+       {
+               if (bnk > 0)
+               {
+                       /* create a new flash bank element */
+                       struct flash_bank *fb = malloc(sizeof(struct flash_bank));
+                       fb->target = target;
+                       fb->driver = bank->driver;
+                       fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
+                       fb->next = NULL;
+
+                       /* link created bank in 'flash_banks' list and redirect t_bank */
+                       t_bank->next = fb;
+                       t_bank = fb;
+               }
+
+               t_bank->bank_number = bnk;
+               t_bank->base = base_address + bnk * bank_size;
+               t_bank->size = bank_size;
+               t_bank->chip_width = 0;
+               t_bank->bus_width = 4;
+               t_bank->num_sectors = sectors_num;
+
+               /* allocate sectors */
+               t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
+               for (sec = 0; sec < sectors_num; sec++)
+               {
+                       t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
+                       t_bank->sectors[sec].size = pages_per_sector * page_size;
+                       t_bank->sectors[sec].is_erased = -1;
+                       t_bank->sectors[sec].is_protected = -1;
+               }
+
+               at91sam7_info = t_bank->driver_priv;
+
+               at91sam7_info->cidr = cidr;
+               at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
+               at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
+               at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
+               at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
+               at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
+               at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
+               at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
+               at91sam7_info->cidr_version = cidr&0x001F;
+
+               at91sam7_info->target_name  = target_name;
+               at91sam7_info->flashmode = 0;
+               at91sam7_info->ext_freq = ext_freq;
+               at91sam7_info->num_nvmbits = num_nvmbits;
+               at91sam7_info->num_nvmbits_on = 0;
+               at91sam7_info->pagesize = page_size;
+               at91sam7_info->pages_per_sector = pages_per_sector;
+
+               /* calculate master clock frequency */
+               at91sam7_read_clock_info(t_bank);
+
+               /* no timming */
+               at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);
+
+               /* check protect state */
+               at91sam7_protect_check(t_bank);
+       }
+
+       LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch);
+
+       return ERROR_OK;
+}
+
+static int at91sam7_erase_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint16_t retval;
+       uint32_t blank;
+       uint16_t fast_check;
+       uint8_t *buffer;
+       uint16_t nSector;
+       uint16_t nByte;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank);
+       at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
+
+       fast_check = 1;
+       for (nSector = 0; nSector < bank->num_sectors; nSector++)
+       {
+               retval = target_blank_check_memory(target, bank->base + bank->sectors[nSector].offset,
+                       bank->sectors[nSector].size, &blank);
+               if (retval != ERROR_OK)
+               {
+                       fast_check = 0;
+                       break;
+               }
+               if (blank == 0xFF)
+                       bank->sectors[nSector].is_erased = 1;
+               else
+                       bank->sectors[nSector].is_erased = 0;
+       }
+
+       if (fast_check)
+       {
+               return ERROR_OK;
+       }
+
+       LOG_USER("Running slow fallback erase check - add working memory");
+
+       buffer = malloc(bank->sectors[0].size);
+       for (nSector = 0; nSector < bank->num_sectors; nSector++)
+       {
+               bank->sectors[nSector].is_erased = 1;
+               retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
+                       bank->sectors[nSector].size/4, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++)
+               {
+                       if (buffer[nByte] != 0xFF)
+                       {
+                               bank->sectors[nSector].is_erased = 0;
+                               break;
+                       }
+               }
+       }
+       free(buffer);
+
+       return ERROR_OK;
+}
+
+static int at91sam7_protect_check(struct flash_bank *bank)
+{
+       uint8_t lock_pos, gpnvm_pos;
+       uint32_t status;
+
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+
+       if (at91sam7_info->cidr == 0)
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       status = at91sam7_get_flash_status(bank->target, bank->bank_number);
+       at91sam7_info->lockbits = (status >> 16);
+
+       at91sam7_info->num_lockbits_on = 0;
+       for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++)
+       {
+               if (((status >> (16 + lock_pos))&(0x0001)) == 1)
+               {
+                       at91sam7_info->num_lockbits_on++;
+                       bank->sectors[lock_pos].is_protected = 1;
+               }
+               else
+                       bank->sectors[lock_pos].is_protected = 0;
+       }
+
+       /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
+       status = at91sam7_get_flash_status(bank->target, 0);
+
+       at91sam7_info->securitybit = (status >> 4)&0x01;
+       at91sam7_info->nvmbits = (status >> 8)&0xFF;
+
+       at91sam7_info->num_nvmbits_on = 0;
+       for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++)
+       {
+               if (((status >> (8 + gpnvm_pos))&(0x01)) == 1)
+               {
+                       at91sam7_info->num_nvmbits_on++;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
+{
+       struct flash_bank *t_bank = bank;
+       struct at91sam7_flash_bank *at91sam7_info;
+       struct target *target = t_bank->target;
+
+       uint32_t base_address;
+       uint32_t bank_size;
+       uint32_t ext_freq = 0;
+
+       int chip_width;
+       int bus_width;
+       int banks_num;
+       int num_sectors;
+
+       uint16_t pages_per_sector;
+       uint16_t page_size;
+       uint16_t num_nvmbits;
+
+       char *target_name;
+
+       int bnk, sec;
+
+       at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
+       t_bank->driver_priv = at91sam7_info;
+
+       /* part wasn't probed for info yet */
+       at91sam7_info->cidr = 0;
+       at91sam7_info->flashmode = 0;
+       at91sam7_info->ext_freq = 0;
+       at91sam7_info->flash_autodetection = 0;
+
+       if (CMD_ARGC < 13)
+       {
+               at91sam7_info->flash_autodetection = 1;
+               return ERROR_OK;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address);
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], chip_width);
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], bus_width);
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[8], banks_num);
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[9], num_sectors);
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector);
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size);
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits);
+
+       if (CMD_ARGC == 14) {
+               unsigned long freq;
+               COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq);
+               ext_freq = freq * 1000;
+               at91sam7_info->ext_freq = ext_freq;
+       }
+
+       if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
+               (pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0))
+       {
+               at91sam7_info->flash_autodetection = 1;
+               return ERROR_OK;
+       }
+
+       target_name = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
+       strcpy(target_name, CMD_ARGV[7]);
+
+       /* calculate bank size  */
+       bank_size = num_sectors * pages_per_sector * page_size;
+
+       for (bnk = 0; bnk < banks_num; bnk++)
+       {
+               if (bnk > 0)
+               {
+                       /* create a new bank element */
+                       struct flash_bank *fb = malloc(sizeof(struct flash_bank));
+                       fb->target = target;
+                       fb->driver = bank->driver;
+                       fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
+                       fb->next = NULL;
+
+                       /* link created bank in 'flash_banks' list and redirect t_bank */
+                       t_bank->next = fb;
+                       t_bank = fb;
+               }
+
+               t_bank->bank_number = bnk;
+               t_bank->base = base_address + bnk * bank_size;
+               t_bank->size = bank_size;
+               t_bank->chip_width = chip_width;
+               t_bank->bus_width = bus_width;
+               t_bank->num_sectors = num_sectors;
+
+               /* allocate sectors */
+               t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
+               for (sec = 0; sec < num_sectors; sec++)
+               {
+                       t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
+                       t_bank->sectors[sec].size = pages_per_sector * page_size;
+                       t_bank->sectors[sec].is_erased = -1;
+                       t_bank->sectors[sec].is_protected = -1;
+               }
+
+               at91sam7_info = t_bank->driver_priv;
+
+               at91sam7_info->target_name  = target_name;
+               at91sam7_info->flashmode = 0;
+               at91sam7_info->ext_freq  = ext_freq;
+               at91sam7_info->num_nvmbits = num_nvmbits;
+               at91sam7_info->num_nvmbits_on = 0;
+               at91sam7_info->pagesize = page_size;
+               at91sam7_info->pages_per_sector = pages_per_sector;
+       }
+
+       return ERROR_OK;
+}
+
+static int at91sam7_erase(struct flash_bank *bank, int first, int last)
+{
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+       int sec;
+       uint32_t nbytes, pos;
+       uint8_t *buffer;
+       uint8_t erase_all;
+
+       if (at91sam7_info->cidr == 0)
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       erase_all = 0;
+       if ((first == 0) && (last == (bank->num_sectors-1)))
+       {
+               erase_all = 1;
+       }
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank);
+       at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
+
+       if (erase_all)
+       {
+               if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+       else
+       {
+               /* allocate and clean buffer  */
+               nbytes = (last - first + 1) * bank->sectors[first].size;
+               buffer = malloc(nbytes * sizeof(uint8_t));
+               for (pos = 0; pos < nbytes; pos++)
+               {
+                       buffer[pos] = 0xFF;
+               }
+
+               if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               free(buffer);
+       }
+
+       /* mark erased sectors */
+       for (sec = first; sec <= last; sec++)
+       {
+               bank->sectors[sec].is_erased = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int at91sam7_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       uint32_t cmd;
+       int sector;
+       uint32_t pagen;
+
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+
+       if (at91sam7_info->cidr == 0)
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank);
+       at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
+
+       for (sector = first; sector <= last; sector++)
+       {
+               if (set)
+                       cmd = SLB;
+               else
+                       cmd = CLB;
+
+               /* if we lock a page from one sector then entire sector will be locked, also,
+                * if we unlock a page from a locked sector, entire sector will be unlocked   */
+               pagen = sector * at91sam7_info->pages_per_sector;
+
+               if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+
+       at91sam7_protect_check(bank);
+
+       return ERROR_OK;
+}
+
+static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       int retval;
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t dst_min_alignment, wcount, bytes_remaining = count;
+       uint32_t first_page, last_page, pagen, buffer_pos;
+
+       if (at91sam7_info->cidr == 0)
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > bank->size)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       dst_min_alignment = at91sam7_info->pagesize;
+
+       if (offset % dst_min_alignment)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, dst_min_alignment);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       if (at91sam7_info->cidr_arch == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       first_page = offset/dst_min_alignment;
+       last_page = DIV_ROUND_UP(offset + count, dst_min_alignment);
+
+       LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count);
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank);
+       at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
+
+       for (pagen = first_page; pagen < last_page; pagen++)
+       {
+               if (bytes_remaining < dst_min_alignment)
+                       count = bytes_remaining;
+               else
+                       count = dst_min_alignment;
+               bytes_remaining -= count;
+
+               /* Write one block to the PageWriteBuffer */
+               buffer_pos = (pagen-first_page)*dst_min_alignment;
+               wcount = DIV_ROUND_UP(count,4);
+               if ((retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               /* Send Write Page command to Flash Controller */
+               if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               LOG_DEBUG("Write flash bank:%i page number:%" PRIi32 "", bank->bank_number, pagen);
+       }
+
+       return ERROR_OK;
+}
+
+static int at91sam7_probe(struct flash_bank *bank)
+{
+       /* we can't probe on an at91sam7
+        * if this is an at91sam7, it has the configured flash */
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       retval = at91sam7_read_part_info(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int printed;
+       struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
+
+       if (at91sam7_info->cidr == 0)
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       printed = snprintf(buf, buf_size,
+               "\n at91sam7 driver information: Chip is %s\n",
+               at91sam7_info->target_name);
+
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf,
+                          buf_size,
+                          " Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | Flashsize: 0x%8.8" PRIx32 "\n",
+                          at91sam7_info->cidr,
+                          at91sam7_info->cidr_arch,
+                          EPROC[at91sam7_info->cidr_eproc],
+                          at91sam7_info->cidr_version,
+                          bank->size);
+
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size,
+               " Master clock (estimated): %u KHz | External clock: %u KHz\n",
+               (unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000));
+
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size,
+               " Pagesize: %i bytes | Lockbits(%i): %i 0x%4.4x | Pages in lock region: %i \n",
+               at91sam7_info->pagesize, bank->num_sectors, at91sam7_info->num_lockbits_on,
+               at91sam7_info->lockbits, at91sam7_info->pages_per_sector*at91sam7_info->num_lockbits_on);
+
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size,
+               " Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n",
+               at91sam7_info->securitybit, at91sam7_info->num_nvmbits,
+               at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits);
+
+       buf += printed;
+       buf_size -= printed;
+
+       return ERROR_OK;
+}
+
+/*
+* On AT91SAM7S: When the gpnvm bits are set with
+* > at91sam7 gpnvm bitnr set
+* the changes are not visible in the flash controller status register MC_FSR
+* until the processor has been reset.
+* On the Olimex board this requires a power cycle.
+* Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3):
+*   The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes
+*   Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
+*/
+COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
+{
+       struct flash_bank *bank;
+       int bit;
+       uint8_t  flashcmd;
+       uint32_t status;
+       struct at91sam7_flash_bank *at91sam7_info;
+       int retval;
+
+       if (CMD_ARGC != 2)
+       {
+               command_print(CMD_CTX, "at91sam7 gpnvm <bit> <set | clear>");
+               return ERROR_OK;
+       }
+
+       bank = get_flash_bank_by_num_noprobe(0);
+       if (bank ==  NULL)
+       {
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       if (strcmp(bank->driver->name, "at91sam7"))
+       {
+               command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]);
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("target has to be halted to perform flash operation");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (strcmp(CMD_ARGV[1], "set") == 0)
+       {
+               flashcmd = SGPB;
+       }
+       else if (strcmp(CMD_ARGV[1], "clear") == 0)
+       {
+               flashcmd = CGPB;
+       }
+       else
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       at91sam7_info = bank->driver_priv;
+       if (at91sam7_info->cidr == 0)
+       {
+               retval = at91sam7_read_part_info(bank);
+               if (retval != ERROR_OK)
+               {
+                       return retval;
+               }
+       }
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit);
+       if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits))
+       {
+               command_print(CMD_CTX, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name);
+               return ERROR_OK;
+       }
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank);
+       at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
+
+       if (at91sam7_flash_command(bank, flashcmd, bit) != ERROR_OK)
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
+       status = at91sam7_get_flash_status(bank->target, 0);
+       LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32 " \n", flashcmd, bit, status);
+
+       /* check protect state */
+       at91sam7_protect_check(bank);
+
+       return ERROR_OK;
+}
+
+static const struct command_registration at91sam7_exec_command_handlers[] = {
+       {
+               .name = "gpnvm",
+               .handler = &at91sam7_handle_gpnvm_command,
+               .mode = COMMAND_EXEC,
+               .usage = "gpnvm <bit> set | clear, "
+                       "set or clear one gpnvm bit",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration at91sam7_command_handlers[] = {
+       {
+               .name = "at91sam7",
+               .mode = COMMAND_ANY,
+               .help = "at91sam7 flash command group",
+               .chain = at91sam7_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver at91sam7_flash = {
+               .name = "at91sam7",
+               .commands = at91sam7_command_handlers,
+               .flash_bank_command = &at91sam7_flash_bank_command,
+               .erase = &at91sam7_erase,
+               .protect = &at91sam7_protect,
+               .write = &at91sam7_write,
+               .probe = &at91sam7_probe,
+               .auto_probe = &at91sam7_probe,
+               .erase_check = &at91sam7_erase_check,
+               .protect_check = &at91sam7_protect_check,
+               .info = &at91sam7_info,
+       };
diff --git a/src/flash/nor/at91sam7.h b/src/flash/nor/at91sam7.h
new file mode 100644 (file)
index 0000000..4510686
--- /dev/null
@@ -0,0 +1,118 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Magnus Lundin                                   *
+ *   lundin@mlu.mine.nu                                                    *
+ *                                                                         *
+ *   Copyright (C) 2006 by Gheorghe Guran (atlas)                          *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#ifndef AT91SAM7_H
+#define AT91SAM7_H
+
+#include "flash.h"
+
+struct at91sam7_flash_bank
+{
+       /* chip id register */
+       uint32_t cidr;
+       uint16_t cidr_ext;
+       uint16_t cidr_nvptyp;
+       uint16_t cidr_arch;
+       uint16_t cidr_sramsiz;
+       uint16_t cidr_nvpsiz;
+       uint16_t cidr_nvpsiz2;
+       uint16_t cidr_eproc;
+       uint16_t cidr_version;
+       char *target_name;
+
+       /* flash auto-detection */
+       uint8_t  flash_autodetection;
+
+       /* flash geometry */
+       uint16_t pages_per_sector;
+       uint16_t pagesize;
+       uint16_t pages_in_lockregion;
+
+       /* nv memory bits */
+       uint16_t num_lockbits_on;
+       uint16_t lockbits;
+       uint16_t num_nvmbits;
+       uint16_t num_nvmbits_on;
+       uint16_t nvmbits;
+       uint8_t  securitybit;
+
+       /* 0: not init
+        * 1: fmcn for nvbits (1uS)
+        * 2: fmcn for flash (1.5uS) */
+       uint8_t  flashmode;
+
+       /* main clock status */
+       uint8_t  mck_valid;
+       uint32_t mck_freq;
+
+       /* external clock frequency */
+       uint32_t ext_freq;
+
+};
+
+
+/* AT91SAM7 control registers */
+#define DBGU_CIDR                      0xFFFFF240
+#define CKGR_MCFR                      0xFFFFFC24
+#define CKGR_MOR                       0xFFFFFC20
+#define CKGR_MCFR_MAINRDY      0x10000
+#define CKGR_PLLR                      0xFFFFFC2c
+#define CKGR_PLLR_DIV          0xff
+#define CKGR_PLLR_MUL          0x07ff0000
+#define PMC_MCKR                       0xFFFFFC30
+#define PMC_MCKR_CSS           0x03
+#define PMC_MCKR_PRES          0x1c
+
+/* Flash Controller Commands */
+#define WP             0x01
+#define SLB            0x02
+#define WPL            0x03
+#define CLB            0x04
+#define EA             0x08
+#define SGPB   0x0B
+#define CGPB   0x0D
+#define SSB            0x0F
+
+/* MC_FSR bit definitions */
+#define MC_FSR_FRDY                    1
+#define MC_FSR_EOL                     2
+
+/* AT91SAM7 constants */
+#define RC_FREQ                                32000
+
+/* Flash timing modes */
+#define FMR_TIMING_NONE                0
+#define FMR_TIMING_NVBITS      1
+#define FMR_TIMING_FLASH       2
+
+/* Flash size constants */
+#define FLASH_SIZE_8KB         1
+#define FLASH_SIZE_16KB                2
+#define FLASH_SIZE_32KB                3
+#define FLASH_SIZE_64KB                5
+#define FLASH_SIZE_128KB       7
+#define FLASH_SIZE_256KB       9
+#define FLASH_SIZE_512KB       10
+#define FLASH_SIZE_1024KB      12
+#define FLASH_SIZE_2048KB      14
+
+#endif /* AT91SAM7_H */
diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c
new file mode 100644 (file)
index 0000000..687dd4b
--- /dev/null
@@ -0,0 +1,483 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Simon Qian                                      *
+ *   SimonQian@SimonQian.com                                               *
+ *                                                                         *
+ *   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 "avrf.h"
+#include "avrt.h"
+#include "flash.h"
+
+
+/* AVR_JTAG_Instructions */
+#define AVR_JTAG_INS_LEN                                                       4
+// Public Instructions:
+#define AVR_JTAG_INS_EXTEST                                                    0x00
+#define AVR_JTAG_INS_IDCODE                                                    0x01
+#define AVR_JTAG_INS_SAMPLE_PRELOAD                                    0x02
+#define AVR_JTAG_INS_BYPASS                                                    0x0F
+// AVR Specified Public Instructions:
+#define AVR_JTAG_INS_AVR_RESET                                         0x0C
+#define AVR_JTAG_INS_PROG_ENABLE                                       0x04
+#define AVR_JTAG_INS_PROG_COMMANDS                                     0x05
+#define AVR_JTAG_INS_PROG_PAGELOAD                                     0x06
+#define AVR_JTAG_INS_PROG_PAGEREAD                                     0x07
+
+// Data Registers:
+#define AVR_JTAG_REG_Bypass_Len                                                1
+#define AVR_JTAG_REG_DeviceID_Len                                      32
+
+#define AVR_JTAG_REG_Reset_Len                                         1
+#define AVR_JTAG_REG_JTAGID_Len                                                32
+#define AVR_JTAG_REG_ProgrammingEnable_Len                     16
+#define AVR_JTAG_REG_ProgrammingCommand_Len                    15
+#define AVR_JTAG_REG_FlashDataByte_Len                         16
+
+struct avrf_type avft_chips_info[] =
+{
+//      name,                  chip_id,        flash_page_size,        flash_page_num, eeprom_page_size,       eeprom_page_num
+       {"atmega128",   0x9702,         256,                            512,                    8,                                      512},
+};
+
+int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out);
+int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len);
+
+int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
+int mcu_write_dr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int dr_len, int rti);
+int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
+int mcu_write_dr_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
+int mcu_write_ir_u16(struct jtag_tap *tap, uint16_t *ir_in, uint16_t ir_out, int ir_len, int rti);
+int mcu_write_dr_u16(struct jtag_tap *tap, uint16_t *ir_in, uint16_t ir_out, int dr_len, int rti);
+int mcu_write_ir_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
+int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
+int mcu_execute_queue(void);
+
+/* avr program functions */
+static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
+{
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, reset ,AVR_JTAG_REG_Reset_Len);
+
+       return ERROR_OK;
+}
+
+static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id)
+{
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE);
+       avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len);
+
+       return ERROR_OK;
+}
+
+static int avr_jtagprg_enterprogmode(struct avr_common *avr)
+{
+       avr_jtag_reset(avr, 1);
+
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_ProgrammingEnable_Len);
+
+       return ERROR_OK;
+}
+
+static int avr_jtagprg_leaveprogmode(struct avr_common *avr)
+{
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len);
+
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_ProgrammingEnable_Len);
+
+       avr_jtag_reset(avr, 0);
+
+       return ERROR_OK;
+}
+
+static int avr_jtagprg_chiperase(struct avr_common *avr)
+{
+       uint32_t poll_value;
+
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
+
+       do {
+               poll_value = 0;
+               avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
+               if (ERROR_OK != mcu_execute_queue())
+               {
+                       return ERROR_FAIL;
+               }
+               LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
+       } while (!(poll_value & 0x0200));
+
+       return ERROR_OK;
+}
+
+static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size)
+{
+       uint32_t i, poll_value;
+
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
+
+       // load addr high byte
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
+
+       // load addr low byte
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
+
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
+
+       for (i = 0; i < page_size; i++)
+       {
+               if (i < buf_size)
+               {
+                       avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
+               }
+               else
+               {
+                       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8);
+               }
+       }
+
+       avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
+
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
+       avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
+
+       do {
+               poll_value = 0;
+               avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
+               if (ERROR_OK != mcu_execute_queue())
+               {
+                       return ERROR_FAIL;
+               }
+               LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
+       } while (!(poll_value & 0x0200));
+
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
+{
+       struct avrf_flash_bank *avrf_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank avr configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       avrf_info = malloc(sizeof(struct avrf_flash_bank));
+       bank->driver_priv = avrf_info;
+
+       avrf_info->probed = 0;
+
+       return ERROR_OK;
+}
+
+static int avrf_erase(struct flash_bank *bank, int first, int last)
+{
+       LOG_INFO("%s", __FUNCTION__);
+       return ERROR_OK;
+}
+
+static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       LOG_INFO("%s", __FUNCTION__);
+       return ERROR_OK;
+}
+
+static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct avr_common *avr = target->arch_info;
+       uint32_t cur_size, cur_buffer_size, page_size;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       page_size = bank->sectors[0].size;
+       if ((offset % page_size) != 0)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       LOG_DEBUG("offset is 0x%08" PRIx32 "", offset);
+       LOG_DEBUG("count is %" PRId32 "", count);
+
+       if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
+       {
+               return ERROR_FAIL;
+       }
+
+       cur_size = 0;
+       while (count > 0)
+       {
+               if (count > page_size)
+               {
+                       cur_buffer_size = page_size;
+               }
+               else
+               {
+                       cur_buffer_size = count;
+               }
+               avr_jtagprg_writeflashpage(avr, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size);
+               count -= cur_buffer_size;
+               cur_size += cur_buffer_size;
+
+               keep_alive();
+       }
+
+       return avr_jtagprg_leaveprogmode(avr);
+}
+
+#define EXTRACT_MFG(X)  (((X) & 0xffe) >> 1)
+#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
+#define EXTRACT_VER(X)  (((X) & 0xf0000000) >> 28)
+static int avrf_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct avrf_flash_bank *avrf_info = bank->driver_priv;
+       struct avr_common *avr = target->arch_info;
+       struct avrf_type *avr_info = NULL;
+       int i;
+       uint32_t device_id;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       avrf_info->probed = 0;
+
+       avr_jtag_read_jtagid(avr, &device_id);
+       if (ERROR_OK != mcu_execute_queue())
+       {
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
+       if (EXTRACT_MFG(device_id) != 0x1F)
+       {
+               LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
+       }
+
+       for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
+       {
+               if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
+               {
+                       avr_info = &avft_chips_info[i];
+                       LOG_INFO("target device is %s", avr_info->name);
+                       break;
+               }
+       }
+
+       if (avr_info != NULL)
+       {
+               // chip found
+               bank->base = 0x00000000;
+               bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
+               bank->num_sectors = avr_info->flash_page_num;
+               bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
+
+               for (i = 0; i < avr_info->flash_page_num; i++)
+               {
+                       bank->sectors[i].offset = i * avr_info->flash_page_size;
+                       bank->sectors[i].size = avr_info->flash_page_size;
+                       bank->sectors[i].is_erased = -1;
+                       bank->sectors[i].is_protected = 1;
+               }
+
+               avrf_info->probed = 1;
+               return ERROR_OK;
+       }
+       else
+       {
+               // chip not supported
+               LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
+
+               avrf_info->probed = 1;
+               return ERROR_FAIL;
+       }
+}
+
+static int avrf_auto_probe(struct flash_bank *bank)
+{
+       struct avrf_flash_bank *avrf_info = bank->driver_priv;
+       if (avrf_info->probed)
+               return ERROR_OK;
+       return avrf_probe(bank);
+}
+
+static int avrf_protect_check(struct flash_bank *bank)
+{
+       LOG_INFO("%s", __FUNCTION__);
+       return ERROR_OK;
+}
+
+static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct target *target = bank->target;
+       struct avr_common *avr = target->arch_info;
+       struct avrf_type *avr_info = NULL;
+       int i;
+       uint32_t device_id;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       avr_jtag_read_jtagid(avr, &device_id);
+       if (ERROR_OK != mcu_execute_queue())
+       {
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
+       if (EXTRACT_MFG(device_id) != 0x1F)
+       {
+               LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
+       }
+
+       for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
+       {
+               if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
+               {
+                       avr_info = &avft_chips_info[i];
+                       LOG_INFO("target device is %s", avr_info->name);
+
+                       break;
+               }
+       }
+
+       if (avr_info != NULL)
+       {
+               // chip found
+               snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id));
+               return ERROR_OK;
+       }
+       else
+       {
+               // chip not supported
+               snprintf(buf, buf_size, "Cannot identify target as a avr\n");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+}
+
+static int avrf_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct avr_common *avr = target->arch_info;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((ERROR_OK != avr_jtagprg_enterprogmode(avr))
+               || (ERROR_OK != avr_jtagprg_chiperase(avr))
+               || (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
+       {
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(avrf_handle_mass_erase_command)
+{
+       int i;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "avr mass_erase <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (avrf_mass_erase(bank) == ERROR_OK)
+       {
+               /* set all sectors as erased */
+               for (i = 0; i < bank->num_sectors; i++)
+               {
+                       bank->sectors[i].is_erased = 1;
+               }
+
+               command_print(CMD_CTX, "avr mass erase complete");
+       }
+       else
+       {
+               command_print(CMD_CTX, "avr mass erase failed");
+       }
+
+       LOG_DEBUG("%s", __FUNCTION__);
+       return ERROR_OK;
+}
+
+static const struct command_registration avrf_exec_command_handlers[] = {
+       {
+               .name = "mass_erase",
+               .handler = &avrf_handle_mass_erase_command,
+               .mode = COMMAND_EXEC,
+               .help = "erase entire device",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration avrf_command_handlers[] = {
+       {
+               .name = "avrf",
+               .mode = COMMAND_ANY,
+               .help = "AVR flash command group",
+               .chain = avrf_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver avr_flash = {
+               .name = "avr",
+               .commands = avrf_command_handlers,
+               .flash_bank_command = &avrf_flash_bank_command,
+               .erase = &avrf_erase,
+               .protect = &avrf_protect,
+               .write = &avrf_write,
+               .probe = &avrf_probe,
+               .auto_probe = &avrf_auto_probe,
+               .erase_check = &default_flash_mem_blank_check,
+               .protect_check = &avrf_protect_check,
+               .info = &avrf_info,
+       };
diff --git a/src/flash/nor/avrf.h b/src/flash/nor/avrf.h
new file mode 100644 (file)
index 0000000..e75d9d7
--- /dev/null
@@ -0,0 +1,41 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Simon Qian                                      *
+ *   SimonQian@SimonQian.com                                               *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef AVRF_H
+#define AVRF_H
+
+#include "types.h"
+
+struct avrf_type
+{
+       char name[15];
+       uint16_t chip_id;
+       int flash_page_size;
+       int flash_page_num;
+       int eeprom_page_size;
+       int eeprom_page_num;
+};
+
+struct avrf_flash_bank
+{
+       int ppage_size;
+       int probed;
+};
+
+#endif /* AVRF_H */
diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c
new file mode 100644 (file)
index 0000000..6dbffb9
--- /dev/null
@@ -0,0 +1,2630 @@
+/***************************************************************************
+ *   Copyright (C) 2005, 2007 by Dominic Rath                              *
+ *   Dominic.Rath@gmx.de                                                   *
+ *   Copyright (C) 2009 Michael Schwingen                                  *
+ *   michael@schwingen.org                                                 *
+ *                                                                         *
+ *   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 "cfi.h"
+#include "non_cfi.h"
+#include "armv4_5.h"
+#include "binarybuffer.h"
+#include "algorithm.h"
+
+
+#define CFI_MAX_BUS_WIDTH      4
+#define CFI_MAX_CHIP_WIDTH     4
+
+/* defines internal maximum size for code fragment in cfi_intel_write_block() */
+#define CFI_MAX_INTEL_CODESIZE 256
+
+static struct cfi_unlock_addresses cfi_unlock_addresses[] =
+{
+       [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
+       [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa },
+};
+
+/* CFI fixups foward declarations */
+static void cfi_fixup_0002_erase_regions(struct flash_bank *flash, void *param);
+static void cfi_fixup_0002_unlock_addresses(struct flash_bank *flash, void *param);
+static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *flash, void *param);
+
+/* fixup after reading cmdset 0002 primary query table */
+static const struct cfi_fixup cfi_0002_fixups[] = {
+       {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
+       {CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
+       {CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
+       {CFI_MFR_AMD, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
+       {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
+       {0, 0, NULL, NULL}
+};
+
+/* fixup after reading cmdset 0001 primary query table */
+static const struct cfi_fixup cfi_0001_fixups[] = {
+       {0, 0, NULL, NULL}
+};
+
+static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       const struct cfi_fixup *f;
+
+       for (f = fixups; f->fixup; f++)
+       {
+               if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) &&
+                       ((f->id  == CFI_ID_ANY)  || (f->id  == cfi_info->device_id)))
+               {
+                       f->fixup(bank, f->param);
+               }
+       }
+}
+
+/* inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset) */
+static __inline__ uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       if (cfi_info->x16_as_x8) offset *= 2;
+
+       /* while the sector list isn't built, only accesses to sector 0 work */
+       if (sector == 0)
+               return bank->base + offset * bank->bus_width;
+       else
+       {
+               if (!bank->sectors)
+               {
+                       LOG_ERROR("BUG: sector list not yet built");
+                       exit(-1);
+               }
+               return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
+       }
+
+}
+
+static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
+{
+       int i;
+
+       /* clear whole buffer, to ensure bits that exceed the bus_width
+        * are set to zero
+        */
+       for (i = 0; i < CFI_MAX_BUS_WIDTH; i++)
+               cmd_buf[i] = 0;
+
+       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = bank->bus_width; i > 0; i--)
+               {
+                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
+               }
+       }
+       else
+       {
+               for (i = 1; i <= bank->bus_width; i++)
+               {
+                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
+               }
+       }
+}
+
+/* read unsigned 8-bit value from the bank
+ * flash banks are expected to be made of similar chips
+ * the query result should be the same for all
+ */
+static uint8_t cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset)
+{
+       struct target *target = bank->target;
+       uint8_t data[CFI_MAX_BUS_WIDTH];
+
+       target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
+
+       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
+               return data[0];
+       else
+               return data[bank->bus_width - 1];
+}
+
+/* read unsigned 8-bit value from the bank
+ * in case of a bank made of multiple chips,
+ * the individual values are ORed
+ */
+static uint8_t cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset)
+{
+       struct target *target = bank->target;
+       uint8_t data[CFI_MAX_BUS_WIDTH];
+       int i;
+
+       target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
+
+       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+                       data[0] |= data[i];
+
+               return data[0];
+       }
+       else
+       {
+               uint8_t value = 0;
+               for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+                       value |= data[bank->bus_width - 1 - i];
+
+               return value;
+       }
+}
+
+static uint16_t cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset)
+{
+       struct target *target = bank->target;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       uint8_t data[CFI_MAX_BUS_WIDTH * 2];
+
+       if (cfi_info->x16_as_x8)
+       {
+               uint8_t i;
+               for (i = 0;i < 2;i++)
+                       target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1,
+                               &data[i*bank->bus_width]);
+       }
+       else
+               target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
+
+       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
+               return data[0] | data[bank->bus_width] << 8;
+       else
+               return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
+}
+
+static uint32_t cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset)
+{
+       struct target *target = bank->target;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       uint8_t data[CFI_MAX_BUS_WIDTH * 4];
+
+       if (cfi_info->x16_as_x8)
+       {
+               uint8_t i;
+               for (i = 0;i < 4;i++)
+                       target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1,
+                               &data[i*bank->bus_width]);
+       }
+       else
+               target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
+
+       if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
+               return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24;
+       else
+               return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 |
+                               data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
+}
+
+static void cfi_intel_clear_status_register(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("BUG: attempted to clear status register while target wasn't halted");
+               exit(-1);
+       }
+
+       cfi_command(bank, 0x50, command);
+       target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+}
+
+uint8_t cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+       uint8_t status;
+
+       while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0))
+       {
+               LOG_DEBUG("status: 0x%x", status);
+               alive_sleep(1);
+       }
+
+       /* mask out bit 0 (reserved) */
+       status = status & 0xfe;
+
+       LOG_DEBUG("status: 0x%x", status);
+
+       if ((status & 0x80) != 0x80)
+       {
+               LOG_ERROR("timeout while waiting for WSM to become ready");
+       }
+       else if (status != 0x80)
+       {
+               LOG_ERROR("status register: 0x%x", status);
+               if (status & 0x2)
+                       LOG_ERROR("Block Lock-Bit Detected, Operation Abort");
+               if (status & 0x4)
+                       LOG_ERROR("Program suspended");
+               if (status & 0x8)
+                       LOG_ERROR("Low Programming Voltage Detected, Operation Aborted");
+               if (status & 0x10)
+                       LOG_ERROR("Program Error / Error in Setting Lock-Bit");
+               if (status & 0x20)
+                       LOG_ERROR("Error in Block Erasure or Clear Lock-Bits");
+               if (status & 0x40)
+                       LOG_ERROR("Block Erase Suspended");
+
+               cfi_intel_clear_status_register(bank);
+       }
+
+       return status;
+}
+
+int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+       uint8_t status, oldstatus;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       oldstatus = cfi_get_u8(bank, 0, 0x0);
+
+       do {
+               status = cfi_get_u8(bank, 0, 0x0);
+               if ((status ^ oldstatus) & 0x40) {
+                       if (status & cfi_info->status_poll_mask & 0x20) {
+                               oldstatus = cfi_get_u8(bank, 0, 0x0);
+                               status = cfi_get_u8(bank, 0, 0x0);
+                               if ((status ^ oldstatus) & 0x40) {
+                                       LOG_ERROR("dq5 timeout, status: 0x%x", status);
+                                       return(ERROR_FLASH_OPERATION_FAILED);
+                               } else {
+                                       LOG_DEBUG("status: 0x%x", status);
+                                       return(ERROR_OK);
+                               }
+                       }
+               } else { /* no toggle: finished, OK */
+                       LOG_DEBUG("status: 0x%x", status);
+                       return(ERROR_OK);
+               }
+
+               oldstatus = status;
+               alive_sleep(1);
+       } while (timeout-- > 0);
+
+       LOG_ERROR("timeout, status: 0x%x", status);
+
+       return(ERROR_FLASH_BUSY);
+}
+
+static int cfi_read_intel_pri_ext(struct flash_bank *bank)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_intel_pri_ext *pri_ext = malloc(sizeof(struct cfi_intel_pri_ext));
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       cfi_info->pri_ext = pri_ext;
+
+       pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
+       pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
+       pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
+
+       if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               LOG_ERROR("Could not read bank flash bank information");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
+       pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
+
+       LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
+
+       pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5);
+       pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
+       pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa);
+
+       LOG_DEBUG("feature_support: 0x%" PRIx32 ", suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x",
+                 pri_ext->feature_support,
+                 pri_ext->suspend_cmd_support,
+                 pri_ext->blk_status_reg_mask);
+
+       pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc);
+       pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd);
+
+       LOG_DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
+                 (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
+                 (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
+
+       pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe);
+       if (pri_ext->num_protection_fields != 1)
+       {
+               LOG_WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields);
+       }
+
+       pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf);
+       pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11);
+       pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12);
+
+       LOG_DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
+
+       return ERROR_OK;
+}
+
+static int cfi_read_spansion_pri_ext(struct flash_bank *bank)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       cfi_info->pri_ext = pri_ext;
+
+       pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
+       pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
+       pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
+
+       if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               LOG_ERROR("Could not read spansion bank information");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
+       pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
+
+       LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
+
+       pri_ext->SiliconRevision = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5);
+       pri_ext->EraseSuspend    = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6);
+       pri_ext->BlkProt         = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7);
+       pri_ext->TmpBlkUnprotect = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8);
+       pri_ext->BlkProtUnprot   = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
+       pri_ext->SimultaneousOps = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10);
+       pri_ext->BurstMode       = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11);
+       pri_ext->PageMode        = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12);
+       pri_ext->VppMin          = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13);
+       pri_ext->VppMax          = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14);
+       pri_ext->TopBottom       = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15);
+
+       LOG_DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", pri_ext->SiliconRevision,
+             pri_ext->EraseSuspend, pri_ext->BlkProt);
+
+       LOG_DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, Simultaneous Ops: 0x%x", pri_ext->TmpBlkUnprotect,
+             pri_ext->BlkProtUnprot, pri_ext->SimultaneousOps);
+
+       LOG_DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode);
+
+
+       LOG_DEBUG("Vpp min: %2.2d.%1.1d, Vpp max: %2.2d.%1.1x",
+                 (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f,
+                 (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f);
+
+       LOG_DEBUG("WP# protection 0x%x", pri_ext->TopBottom);
+
+       /* default values for implementation specific workarounds */
+       pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
+       pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
+       pri_ext->_reversed_geometry = 0;
+
+       return ERROR_OK;
+}
+
+static int cfi_read_atmel_pri_ext(struct flash_bank *bank)
+{
+       int retval;
+       struct cfi_atmel_pri_ext atmel_pri_ext;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion,
+        * but a different primary extended query table.
+        * We read the atmel table, and prepare a valid AMD/Spansion query table.
+        */
+
+       memset(pri_ext, 0, sizeof(struct cfi_spansion_pri_ext));
+
+       cfi_info->pri_ext = pri_ext;
+
+       atmel_pri_ext.pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
+       atmel_pri_ext.pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
+       atmel_pri_ext.pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
+
+       if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I'))
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               LOG_ERROR("Could not read atmel bank information");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       pri_ext->pri[0] = atmel_pri_ext.pri[0];
+       pri_ext->pri[1] = atmel_pri_ext.pri[1];
+       pri_ext->pri[2] = atmel_pri_ext.pri[2];
+
+       atmel_pri_ext.major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
+       atmel_pri_ext.minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
+
+       LOG_DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version);
+
+       pri_ext->major_version = atmel_pri_ext.major_version;
+       pri_ext->minor_version = atmel_pri_ext.minor_version;
+
+       atmel_pri_ext.features = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5);
+       atmel_pri_ext.bottom_boot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6);
+       atmel_pri_ext.burst_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7);
+       atmel_pri_ext.page_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8);
+
+       LOG_DEBUG("features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x",
+               atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode);
+
+       if (atmel_pri_ext.features & 0x02)
+               pri_ext->EraseSuspend = 2;
+
+       if (atmel_pri_ext.bottom_boot)
+               pri_ext->TopBottom = 2;
+       else
+               pri_ext->TopBottom = 3;
+
+       pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
+       pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
+
+       return ERROR_OK;
+}
+
+static int cfi_read_0002_pri_ext(struct flash_bank *bank)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       if (cfi_info->manufacturer == CFI_MFR_ATMEL)
+       {
+               return cfi_read_atmel_pri_ext(bank);
+       }
+       else
+       {
+               return cfi_read_spansion_pri_ext(bank);
+       }
+}
+
+static int cfi_spansion_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int printed;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+       printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n");
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0],
+                          pri_ext->pri[1], pri_ext->pri[2],
+                          pri_ext->major_version, pri_ext->minor_version);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n",
+                          (pri_ext->SiliconRevision) >> 2,
+                          (pri_ext->SiliconRevision) & 0x03);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n",
+                          pri_ext->EraseSuspend,
+                          pri_ext->BlkProt);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "VppMin: %2.2d.%1.1x, VppMax: %2.2d.%1.1x\n",
+               (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f,
+               (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f);
+
+       return ERROR_OK;
+}
+
+static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int printed;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
+
+       printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "feature_support: 0x%" PRIx32 ", suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
+               (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
+               (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
+
+       return ERROR_OK;
+}
+
+/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options]
+ */
+FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
+{
+       struct cfi_flash_bank *cfi_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank cfi configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       uint16_t chip_width, bus_width;
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], bus_width);
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[4], chip_width);
+
+       if ((chip_width > CFI_MAX_CHIP_WIDTH)
+                       || (bus_width > CFI_MAX_BUS_WIDTH))
+       {
+               LOG_ERROR("chip and bus width have to specified in bytes");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       cfi_info = malloc(sizeof(struct cfi_flash_bank));
+       cfi_info->probed = 0;
+       bank->driver_priv = cfi_info;
+
+       cfi_info->write_algorithm = NULL;
+
+       cfi_info->x16_as_x8 = 0;
+       cfi_info->jedec_probe = 0;
+       cfi_info->not_cfi = 0;
+
+       for (unsigned i = 6; i < CMD_ARGC; i++)
+       {
+               if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0)
+               {
+                       cfi_info->x16_as_x8 = 1;
+               }
+               else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0)
+               {
+                       cfi_info->jedec_probe = 1;
+               }
+       }
+
+       cfi_info->write_algorithm = NULL;
+
+       /* bank wasn't probed yet */
+       cfi_info->qry[0] = -1;
+
+       return ERROR_OK;
+}
+
+static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint8_t command[8];
+       int i;
+
+       cfi_intel_clear_status_register(bank);
+
+       for (i = first; i <= last; i++)
+       {
+               cfi_command(bank, 0x20, command);
+               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               cfi_command(bank, 0xd0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80)
+                       bank->sectors[i].is_erased = 1;
+               else
+               {
+                       cfi_command(bank, 0xff, command);
+                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+
+                       LOG_ERROR("couldn't erase block %i of flash bank at base 0x%" PRIx32 , i, bank->base);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+
+       cfi_command(bank, 0xff, command);
+       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+}
+
+static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct target *target = bank->target;
+       uint8_t command[8];
+       int i;
+
+       for (i = first; i <= last; i++)
+       {
+               cfi_command(bank, 0xaa, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               cfi_command(bank, 0x55, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               cfi_command(bank, 0x80, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               cfi_command(bank, 0xaa, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               cfi_command(bank, 0x55, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               cfi_command(bank, 0x30, command);
+               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == ERROR_OK)
+                       bank->sectors[i].is_erased = 1;
+               else
+               {
+                       cfi_command(bank, 0xf0, command);
+                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+
+                       LOG_ERROR("couldn't erase block %i of flash bank at base 0x%" PRIx32, i, bank->base);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+
+       cfi_command(bank, 0xf0, command);
+       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+}
+
+static int cfi_erase(struct flash_bank *bank, int first, int last)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       if (cfi_info->qry[0] != 'Q')
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       return cfi_intel_erase(bank, first, last);
+                       break;
+               case 2:
+                       return cfi_spansion_erase(bank, first, last);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct target *target = bank->target;
+       uint8_t command[8];
+       int retry = 0;
+       int i;
+
+       /* if the device supports neither legacy lock/unlock (bit 3) nor
+        * instant individual block locking (bit 5).
+        */
+       if (!(pri_ext->feature_support & 0x28))
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       cfi_intel_clear_status_register(bank);
+
+       for (i = first; i <= last; i++)
+       {
+               cfi_command(bank, 0x60, command);
+               LOG_DEBUG("address: 0x%4.4" PRIx32 ", command: 0x%4.4" PRIx32, flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
+               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               if (set)
+               {
+                       cfi_command(bank, 0x01, command);
+                       LOG_DEBUG("address: 0x%4.4" PRIx32 ", command: 0x%4.4" PRIx32 , flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
+                       if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       bank->sectors[i].is_protected = 1;
+               }
+               else
+               {
+                       cfi_command(bank, 0xd0, command);
+                       LOG_DEBUG("address: 0x%4.4" PRIx32 ", command: 0x%4.4" PRIx32, flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
+                       if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       bank->sectors[i].is_protected = 0;
+               }
+
+               /* instant individual block locking doesn't require reading of the status register */
+               if (!(pri_ext->feature_support & 0x20))
+               {
+                       /* Clear lock bits operation may take up to 1.4s */
+                       cfi_intel_wait_status_busy(bank, 1400);
+               }
+               else
+               {
+                       uint8_t block_status;
+                       /* read block lock bit, to verify status */
+                       cfi_command(bank, 0x90, command);
+                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       block_status = cfi_get_u8(bank, i, 0x2);
+
+                       if ((block_status & 0x1) != set)
+                       {
+                               LOG_ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status);
+                               cfi_command(bank, 0x70, command);
+                               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
+                               {
+                                       return retval;
+                               }
+                               cfi_intel_wait_status_busy(bank, 10);
+
+                               if (retry > 10)
+                                       return ERROR_FLASH_OPERATION_FAILED;
+                               else
+                               {
+                                       i--;
+                                       retry++;
+                               }
+                       }
+               }
+       }
+
+       /* if the device doesn't support individual block lock bits set/clear,
+        * all blocks have been unlocked in parallel, so we set those that should be protected
+        */
+       if ((!set) && (!(pri_ext->feature_support & 0x20)))
+       {
+               for (i = 0; i < bank->num_sectors; i++)
+               {
+                       if (bank->sectors[i].is_protected == 1)
+                       {
+                               cfi_intel_clear_status_register(bank);
+
+                               cfi_command(bank, 0x60, command);
+                               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+                               {
+                                       return retval;
+                               }
+
+                               cfi_command(bank, 0x01, command);
+                               if ((retval = target_write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+                               {
+                                       return retval;
+                               }
+
+                               cfi_intel_wait_status_busy(bank, 100);
+                       }
+               }
+       }
+
+       cfi_command(bank, 0xff, command);
+       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+}
+
+static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       if (cfi_info->qry[0] != 'Q')
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       cfi_intel_protect(bank, set, first, last);
+                       break;
+               default:
+                       LOG_ERROR("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+/* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */
+static void cfi_add_byte(struct flash_bank *bank, uint8_t *word, uint8_t byte)
+{
+       /* struct target *target = bank->target; */
+
+       int i;
+
+       /* NOTE:
+        * The data to flash must not be changed in endian! We write a bytestrem in
+        * target byte order already. Only the control and status byte lane of the flash
+        * WSM is interpreted by the CPU in different ways, when read a uint16_t or uint32_t
+        * word (data seems to be in the upper or lower byte lane for uint16_t accesses).
+        */
+
+#if 0
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+#endif
+               /* shift bytes */
+               for (i = 0; i < bank->bus_width - 1; i++)
+                       word[i] = word[i + 1];
+               word[bank->bus_width - 1] = byte;
+#if 0
+       }
+       else
+       {
+               /* shift bytes */
+               for (i = bank->bus_width - 1; i > 0; i--)
+                       word[i] = word[i - 1];
+               word[0] = byte;
+       }
+#endif
+}
+
+/* Convert code image to target endian */
+/* FIXME create general block conversion fcts in target.c?) */
+static void cfi_fix_code_endian(struct target *target, uint8_t *dest, const uint32_t *src, uint32_t count)
+{
+       uint32_t i;
+       for (i = 0; i< count; i++)
+       {
+               target_buffer_set_u32(target, dest, *src);
+               dest += 4;
+               src++;
+       }
+}
+
+static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd)
+{
+       struct target *target = bank->target;
+
+       uint8_t buf[CFI_MAX_BUS_WIDTH];
+       cfi_command(bank, cmd, buf);
+       switch (bank->bus_width)
+       {
+       case 1 :
+               return buf[0];
+               break;
+       case 2 :
+               return target_buffer_get_u16(target, buf);
+               break;
+       case 4 :
+               return target_buffer_get_u32(target, buf);
+               break;
+       default :
+               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
+               return 0;
+       }
+}
+
+static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       struct reg_param reg_params[7];
+       struct armv4_5_algorithm armv4_5_info;
+       struct working_area *source;
+       uint32_t buffer_size = 32768;
+       uint32_t write_command_val, busy_pattern_val, error_pattern_val;
+
+       /* algorithm register usage:
+        * r0: source address (in RAM)
+        * r1: target address (in Flash)
+        * r2: count
+        * r3: flash write command
+        * r4: status byte (returned to host)
+        * r5: busy test pattern
+        * r6: error test pattern
+        */
+
+       static const uint32_t word_32_code[] = {
+               0xe4904004,   /* loop:  ldr r4, [r0], #4 */
+               0xe5813000,   /*                str r3, [r1] */
+               0xe5814000,   /*                str r4, [r1] */
+               0xe5914000,   /* busy:  ldr r4, [r1] */
+               0xe0047005,   /*                and r7, r4, r5 */
+               0xe1570005,   /*                cmp r7, r5 */
+               0x1afffffb,   /*                bne busy */
+               0xe1140006,   /*                tst r4, r6 */
+               0x1a000003,   /*                bne done */
+               0xe2522001,   /*                subs r2, r2, #1 */
+               0x0a000001,   /*                beq done */
+               0xe2811004,   /*                add r1, r1 #4 */
+               0xeafffff2,   /*                b loop */
+               0xeafffffe    /* done:  b -2 */
+       };
+
+       static const uint32_t word_16_code[] = {
+               0xe0d040b2,   /* loop:  ldrh r4, [r0], #2 */
+               0xe1c130b0,   /*                strh r3, [r1] */
+               0xe1c140b0,   /*                strh r4, [r1] */
+               0xe1d140b0,   /* busy   ldrh r4, [r1] */
+               0xe0047005,   /*                and r7, r4, r5 */
+               0xe1570005,   /*                cmp r7, r5 */
+               0x1afffffb,   /*                bne busy */
+               0xe1140006,   /*                tst r4, r6 */
+               0x1a000003,   /*                bne done */
+               0xe2522001,   /*                subs r2, r2, #1 */
+               0x0a000001,   /*                beq done */
+               0xe2811002,   /*                add r1, r1 #2 */
+               0xeafffff2,   /*                b loop */
+               0xeafffffe    /* done:  b -2 */
+       };
+
+       static const uint32_t word_8_code[] = {
+               0xe4d04001,   /* loop:  ldrb r4, [r0], #1 */
+               0xe5c13000,   /*                strb r3, [r1] */
+               0xe5c14000,   /*                strb r4, [r1] */
+               0xe5d14000,   /* busy   ldrb r4, [r1] */
+               0xe0047005,   /*                and r7, r4, r5 */
+               0xe1570005,   /*                cmp r7, r5 */
+               0x1afffffb,   /*                bne busy */
+               0xe1140006,   /*                tst r4, r6 */
+               0x1a000003,   /*                bne done */
+               0xe2522001,   /*                subs r2, r2, #1 */
+               0x0a000001,   /*                beq done */
+               0xe2811001,   /*                add r1, r1 #1 */
+               0xeafffff2,   /*                b loop */
+               0xeafffffe    /* done:  b -2 */
+       };
+       uint8_t target_code[4*CFI_MAX_INTEL_CODESIZE];
+       const uint32_t *target_code_src;
+       uint32_t target_code_size;
+       int retval = ERROR_OK;
+
+
+       cfi_intel_clear_status_register(bank);
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       /* If we are setting up the write_algorith, we need target_code_src */
+       /* if not we only need target_code_size. */
+
+       /* However, we don't want to create multiple code paths, so we */
+       /* do the unecessary evaluation of target_code_src, which the */
+       /* compiler will probably nicely optimize away if not needed */
+
+       /* prepare algorithm code for target endian */
+       switch (bank->bus_width)
+       {
+       case 1 :
+               target_code_src = word_8_code;
+               target_code_size = sizeof(word_8_code);
+               break;
+       case 2 :
+               target_code_src = word_16_code;
+               target_code_size = sizeof(word_16_code);
+               break;
+       case 4 :
+               target_code_src = word_32_code;
+               target_code_size = sizeof(word_32_code);
+               break;
+       default:
+               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* flash write code */
+       if (!cfi_info->write_algorithm)
+       {
+               if (target_code_size > sizeof(target_code))
+               {
+                       LOG_WARNING("Internal error - target code buffer to small. Increase CFI_MAX_INTEL_CODESIZE and recompile.");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+               cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
+
+               /* Get memory for block write handler */
+               retval = target_alloc_working_area(target, target_code_size, &cfi_info->write_algorithm);
+               if (retval != ERROR_OK)
+               {
+                       LOG_WARNING("No working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               };
+
+               /* write algorithm code to working area */
+               retval = target_write_buffer(target, cfi_info->write_algorithm->address, target_code_size, target_code);
+               if (retval != ERROR_OK)
+               {
+                       LOG_ERROR("Unable to write block write code to target");
+                       goto cleanup;
+               }
+       }
+
+       /* Get a workspace buffer for the data to flash starting with 32k size.
+          Half size until buffer would be smaller 256 Bytem then fail back */
+       /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */
+       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       {
+               buffer_size /= 2;
+               if (buffer_size <= 256)
+               {
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+                       goto cleanup;
+               }
+       };
+
+       /* setup algo registers */
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
+       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT);
+
+       /* prepare command and status register patterns */
+       write_command_val = cfi_command_val(bank, 0x40);
+       busy_pattern_val  = cfi_command_val(bank, 0x80);
+       error_pattern_val = cfi_command_val(bank, 0x7e);
+
+       LOG_INFO("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
+
+       /* Programming main loop */
+       while (count > 0)
+       {
+               uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
+               uint32_t wsm_error;
+
+               if ((retval = target_write_buffer(target, source->address, thisrun_count, buffer)) != ERROR_OK)
+               {
+                       goto cleanup;
+               }
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
+
+               buf_set_u32(reg_params[3].value, 0, 32, write_command_val);
+               buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val);
+               buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val);
+
+               LOG_INFO("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32 , thisrun_count, address);
+
+               /* Execute algorithm, assume breakpoint for last instruction */
+               retval = target_run_algorithm(target, 0, NULL, 7, reg_params,
+                       cfi_info->write_algorithm->address,
+                       cfi_info->write_algorithm->address + target_code_size - sizeof(uint32_t),
+                       10000, /* 10s should be enough for max. 32k of data */
+                       &armv4_5_info);
+
+               /* On failure try a fall back to direct word writes */
+               if (retval != ERROR_OK)
+               {
+                       cfi_intel_clear_status_register(bank);
+                       LOG_ERROR("Execution of flash algorythm failed. Can't fall back. Please report.");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       /* retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; */
+                       /* FIXME To allow fall back or recovery, we must save the actual status
+                          somewhere, so that a higher level code can start recovery. */
+                       goto cleanup;
+               }
+
+               /* Check return value from algo code */
+               wsm_error = buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val;
+               if (wsm_error)
+               {
+                       /* read status register (outputs debug inforation) */
+                       cfi_intel_wait_status_busy(bank, 100);
+                       cfi_intel_clear_status_register(bank);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       goto cleanup;
+               }
+
+               buffer += thisrun_count;
+               address += thisrun_count;
+               count -= thisrun_count;
+       }
+
+       /* free up resources */
+cleanup:
+       if (source)
+               target_free_working_area(target, source);
+
+       if (cfi_info->write_algorithm)
+       {
+               target_free_working_area(target, cfi_info->write_algorithm);
+               cfi_info->write_algorithm = NULL;
+       }
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+       destroy_reg_param(&reg_params[6]);
+
+       return retval;
+}
+
+static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct target *target = bank->target;
+       struct reg_param reg_params[10];
+       struct armv4_5_algorithm armv4_5_info;
+       struct working_area *source;
+       uint32_t buffer_size = 32768;
+       uint32_t status;
+       int retval, retvaltemp;
+       int exit_code = ERROR_OK;
+
+       /* input parameters - */
+       /*      R0 = source address */
+       /*      R1 = destination address */
+       /*      R2 = number of writes */
+       /*      R3 = flash write command */
+       /*      R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
+       /* output parameters - */
+       /*      R5 = 0x80 ok 0x00 bad */
+       /* temp registers - */
+       /*      R6 = value read from flash to test status */
+       /*      R7 = holding register */
+       /* unlock registers - */
+       /*  R8 = unlock1_addr */
+       /*  R9 = unlock1_cmd */
+       /*  R10 = unlock2_addr */
+       /*  R11 = unlock2_cmd */
+
+       static const uint32_t word_32_code[] = {
+                                               /* 00008100 <sp_32_code>:               */
+               0xe4905004,             /* ldr  r5, [r0], #4                    */
+               0xe5889000,     /* str  r9, [r8]                                */
+               0xe58ab000,     /* str  r11, [r10]                              */
+               0xe5883000,     /* str  r3, [r8]                                */
+               0xe5815000,     /* str  r5, [r1]                                */
+               0xe1a00000,     /* nop                                                  */
+                                               /*                                                              */
+                                               /* 00008110 <sp_32_busy>:               */
+               0xe5916000,     /* ldr  r6, [r1]                                */
+               0xe0257006,     /* eor  r7, r5, r6                              */
+               0xe0147007,     /* ands r7, r4, r7                              */
+               0x0a000007,     /* beq  8140 <sp_32_cont> ; b if DQ7 == Data7 */
+               0xe0166124,     /* ands r6, r6, r4, lsr #2              */
+               0x0afffff9,     /* beq  8110 <sp_32_busy> ;     b if DQ5 low */
+               0xe5916000,     /* ldr  r6, [r1]                                */
+               0xe0257006,     /* eor  r7, r5, r6                              */
+               0xe0147007,     /* ands r7, r4, r7                              */
+               0x0a000001,     /* beq  8140 <sp_32_cont> ; b if DQ7 == Data7 */
+               0xe3a05000,     /* mov  r5, #0  ; 0x0 - return 0x00, error */
+               0x1a000004,     /* bne  8154 <sp_32_done>               */
+                                               /*                                                              */
+                               /* 00008140 <sp_32_cont>:                               */
+               0xe2522001,     /* subs r2, r2, #1      ; 0x1           */
+               0x03a05080,     /* moveq        r5, #128        ; 0x80  */
+               0x0a000001,     /* beq  8154 <sp_32_done>               */
+               0xe2811004,     /* add  r1, r1, #4      ; 0x4           */
+               0xeaffffe8,     /* b    8100 <sp_32_code>               */
+                                               /*                                                              */
+                                               /* 00008154 <sp_32_done>:               */
+               0xeafffffe              /* b    8154 <sp_32_done>               */
+               };
+
+               static const uint32_t word_16_code[] = {
+                               /* 00008158 <sp_16_code>:              */
+               0xe0d050b2,     /* ldrh r5, [r0], #2               */
+               0xe1c890b0,     /* strh r9, [r8]                                */
+               0xe1cab0b0,     /* strh r11, [r10]                              */
+               0xe1c830b0,     /* strh r3, [r8]                                */
+               0xe1c150b0,     /* strh r5, [r1]                       */
+               0xe1a00000,     /* nop                  (mov r0,r0)    */
+                               /*                                     */
+                               /* 00008168 <sp_16_busy>:              */
+               0xe1d160b0,     /* ldrh r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe0147007,     /* ands r7, r4, r7                     */
+               0x0a000007,     /* beq  8198 <sp_16_cont>              */
+               0xe0166124,     /* ands r6, r6, r4, lsr #2             */
+               0x0afffff9,     /* beq  8168 <sp_16_busy>              */
+               0xe1d160b0,     /* ldrh r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe0147007,     /* ands r7, r4, r7                     */
+               0x0a000001,     /* beq  8198 <sp_16_cont>              */
+               0xe3a05000,     /* mov  r5, #0  ; 0x0                  */
+               0x1a000004,     /* bne  81ac <sp_16_done>              */
+                               /*                                     */
+                               /* 00008198 <sp_16_cont>:              */
+               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
+               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
+               0x0a000001,     /* beq  81ac <sp_16_done>              */
+               0xe2811002,     /* add  r1, r1, #2      ; 0x2          */
+               0xeaffffe8,     /* b    8158 <sp_16_code>              */
+                               /*                                     */
+                               /* 000081ac <sp_16_done>:              */
+               0xeafffffe      /* b    81ac <sp_16_done>              */
+               };
+
+               static const uint32_t word_16_code_dq7only[] = {
+                               /* <sp_16_code>:                       */
+               0xe0d050b2,     /* ldrh r5, [r0], #2                   */
+               0xe1c890b0,     /* strh r9, [r8]                       */
+               0xe1cab0b0,     /* strh r11, [r10]                              */
+               0xe1c830b0,     /* strh r3, [r8]                                */
+               0xe1c150b0,     /* strh r5, [r1]                       */
+               0xe1a00000,     /* nop                  (mov r0,r0)    */
+                               /*                                     */
+                               /* <sp_16_busy>:                       */
+               0xe1d160b0,     /* ldrh r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe2177080,     /* ands r7, #0x80                      */
+               0x1afffffb,     /* bne  8168 <sp_16_busy>              */
+                               /*                                     */
+               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
+               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
+               0x0a000001,     /* beq  81ac <sp_16_done>              */
+               0xe2811002,     /* add  r1, r1, #2      ; 0x2          */
+               0xeafffff0,     /* b    8158 <sp_16_code>              */
+                               /*                                     */
+                               /* 000081ac <sp_16_done>:              */
+               0xeafffffe      /* b    81ac <sp_16_done>              */
+               };
+
+               static const uint32_t word_8_code[] = {
+                               /* 000081b0 <sp_16_code_end>:          */
+               0xe4d05001,     /* ldrb r5, [r0], #1                   */
+               0xe5c89000,     /* strb r9, [r8]                                */
+               0xe5cab000,     /* strb r11, [r10]                              */
+               0xe5c83000,     /* strb r3, [r8]                                */
+               0xe5c15000,     /* strb r5, [r1]                       */
+               0xe1a00000,     /* nop                  (mov r0,r0)    */
+                               /*                                     */
+                               /* 000081c0 <sp_8_busy>:               */
+               0xe5d16000,     /* ldrb r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe0147007,     /* ands r7, r4, r7                     */
+               0x0a000007,     /* beq  81f0 <sp_8_cont>               */
+               0xe0166124,     /* ands r6, r6, r4, lsr #2             */
+               0x0afffff9,     /* beq  81c0 <sp_8_busy>               */
+               0xe5d16000,     /* ldrb r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe0147007,     /* ands r7, r4, r7                     */
+               0x0a000001,     /* beq  81f0 <sp_8_cont>               */
+               0xe3a05000,     /* mov  r5, #0  ; 0x0                  */
+               0x1a000004,     /* bne  8204 <sp_8_done>               */
+                               /*                                     */
+                               /* 000081f0 <sp_8_cont>:               */
+               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
+               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
+               0x0a000001,     /* beq  8204 <sp_8_done>               */
+               0xe2811001,     /* add  r1, r1, #1      ; 0x1          */
+               0xeaffffe8,     /* b    81b0 <sp_16_code_end>          */
+                               /*                                     */
+                               /* 00008204 <sp_8_done>:               */
+               0xeafffffe      /* b    8204 <sp_8_done>               */
+       };
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       int target_code_size;
+       const uint32_t *target_code_src;
+
+       switch (bank->bus_width)
+       {
+       case 1 :
+               target_code_src = word_8_code;
+               target_code_size = sizeof(word_8_code);
+               break;
+       case 2 :
+               /* Check for DQ5 support */
+               if( cfi_info->status_poll_mask & (1 << 5) )
+               {
+                       target_code_src = word_16_code;
+                       target_code_size = sizeof(word_16_code);
+               }
+               else
+               {
+                       /* No DQ5 support. Use DQ7 DATA# polling only. */
+                       target_code_src = word_16_code_dq7only;
+                       target_code_size = sizeof(word_16_code_dq7only);
+               }
+               break;
+       case 4 :
+               target_code_src = word_32_code;
+               target_code_size = sizeof(word_32_code);
+               break;
+       default:
+               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* flash write code */
+       if (!cfi_info->write_algorithm)
+       {
+               uint8_t *target_code;
+
+               /* convert bus-width dependent algorithm code to correct endiannes */
+               target_code = malloc(target_code_size);
+               cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
+
+               /* allocate working area */
+               retval = target_alloc_working_area(target, target_code_size,
+                               &cfi_info->write_algorithm);
+               if (retval != ERROR_OK)
+               {
+                       free(target_code);
+                       return retval;
+               }
+
+               /* write algorithm code to working area */
+               if ((retval = target_write_buffer(target, cfi_info->write_algorithm->address,
+                                   target_code_size, target_code)) != ERROR_OK)
+               {
+                       free(target_code);
+                       return retval;
+               }
+
+               free(target_code);
+       }
+       /* the following code still assumes target code is fixed 24*4 bytes */
+
+       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 (cfi_info->write_algorithm)
+                               target_free_working_area(target, cfi_info->write_algorithm);
+
+                       LOG_WARNING("not enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       };
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);
+       init_reg_param(&reg_params[6], "r8", 32, PARAM_OUT);
+       init_reg_param(&reg_params[7], "r9", 32, PARAM_OUT);
+       init_reg_param(&reg_params[8], "r10", 32, PARAM_OUT);
+       init_reg_param(&reg_params[9], "r11", 32, PARAM_OUT);
+
+       while (count > 0)
+       {
+               uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
+
+               retvaltemp = target_write_buffer(target, source->address, thisrun_count, buffer);
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
+               buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0));
+               buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80));
+               buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
+               buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa);
+               buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
+               buf_set_u32(reg_params[9].value, 0, 32, 0x55555555);
+
+               retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
+                                                    cfi_info->write_algorithm->address,
+                                                    cfi_info->write_algorithm->address + ((target_code_size) - 4),
+                                                    10000, &armv4_5_info);
+
+               status = buf_get_u32(reg_params[5].value, 0, 32);
+
+               if ((retval != ERROR_OK) || (retvaltemp != ERROR_OK) || status != 0x80)
+               {
+                       LOG_DEBUG("status: 0x%" PRIx32 , status);
+                       exit_code = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer += thisrun_count;
+               address += thisrun_count;
+               count -= thisrun_count;
+       }
+
+       target_free_all_working_areas(target);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+       destroy_reg_param(&reg_params[6]);
+       destroy_reg_param(&reg_params[7]);
+       destroy_reg_param(&reg_params[8]);
+       destroy_reg_param(&reg_params[9]);
+
+       return exit_code;
+}
+
+static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       cfi_intel_clear_status_register(bank);
+       cfi_command(bank, 0x40, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, word)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
+       {
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address %" PRIx32 , bank->base, address);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       /* Calculate buffer size and boundary mask */
+       uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
+       uint32_t buffermask = buffersize-1;
+       uint32_t bufferwsize;
+
+       /* Check for valid range */
+       if (address & buffermask)
+       {
+               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary",
+                         bank->base, address, cfi_info->max_buf_write_size);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       switch (bank->chip_width)
+       {
+       case 4 : bufferwsize = buffersize / 4; break;
+       case 2 : bufferwsize = buffersize / 2; break;
+       case 1 : bufferwsize = buffersize; break;
+       default:
+               LOG_ERROR("Unsupported chip width %d", bank->chip_width);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       bufferwsize/=(bank->bus_width / bank->chip_width);
+
+
+       /* Check for valid size */
+       if (wordcount > bufferwsize)
+       {
+               LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" PRId32 , wordcount, buffersize);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Write to flash buffer */
+       cfi_intel_clear_status_register(bank);
+
+       /* Initiate buffer operation _*/
+       cfi_command(bank, 0xE8, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+       if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80)
+       {
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               LOG_ERROR("couldn't start buffer write operation at base 0x%" PRIx32 ", address %" PRIx32 , bank->base, address);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Write buffer wordcount-1 and data words */
+       cfi_command(bank, bufferwsize-1, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if ((retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       /* Commit write operation */
+       cfi_command(bank, 0xd0, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+       if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80)
+       {
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               LOG_ERROR("Buffer write at base 0x%" PRIx32 ", address %" PRIx32 " failed.", bank->base, address);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct target *target = bank->target;
+       uint8_t command[8];
+
+       cfi_command(bank, 0xaa, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_command(bank, 0x55, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_command(bank, 0xa0, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, word)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address %" PRIx32 , bank->base, address);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint8_t command[8];
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+       /* Calculate buffer size and boundary mask */
+       uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
+       uint32_t buffermask = buffersize-1;
+       uint32_t bufferwsize;
+
+       /* Check for valid range */
+       if (address & buffermask)
+       {
+               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       switch (bank->chip_width)
+       {
+       case 4 : bufferwsize = buffersize / 4; break;
+       case 2 : bufferwsize = buffersize / 2; break;
+       case 1 : bufferwsize = buffersize; break;
+       default:
+               LOG_ERROR("Unsupported chip width %d", bank->chip_width);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       bufferwsize/=(bank->bus_width / bank->chip_width);
+
+       /* Check for valid size */
+       if (wordcount > bufferwsize)
+       {
+               LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" PRId32, wordcount, buffersize);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       // Unlock
+       cfi_command(bank, 0xaa, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_command(bank, 0x55, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       // Buffer load command
+       cfi_command(bank, 0x25, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       /* Write buffer wordcount-1 and data words */
+       cfi_command(bank, bufferwsize-1, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if ((retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       /* Commit write operation */
+       cfi_command(bank, 0x29, command);
+       if ((retval = target_write_memory(target, address, bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               LOG_ERROR("couldn't write block at base 0x%" PRIx32 ", address %" PRIx32 ", size %" PRIx32 , bank->base, address, bufferwsize);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       return cfi_intel_write_word(bank, word, address);
+                       break;
+               case 2:
+                       return cfi_spansion_write_word(bank, word, address);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+
+       return ERROR_FLASH_OPERATION_FAILED;
+}
+
+static int cfi_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       return cfi_intel_write_words(bank, word, wordcount, address);
+                       break;
+               case 2:
+                       return cfi_spansion_write_words(bank, word, wordcount, address);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+
+       return ERROR_FLASH_OPERATION_FAILED;
+}
+
+int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t address = bank->base + offset; /* address of first byte to be programmed */
+       uint32_t write_p, copy_p;
+       int align;      /* number of unaligned bytes */
+       int blk_count; /* number of bus_width bytes for block copy */
+       uint8_t current_word[CFI_MAX_BUS_WIDTH * 4];    /* word (bus_width size) currently being programmed */
+       int i;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > bank->size)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       if (cfi_info->qry[0] != 'Q')
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /* start at the first byte of the first word (bus_width size) */
+       write_p = address & ~(bank->bus_width - 1);
+       if ((align = address - write_p) != 0)
+       {
+               LOG_INFO("Fixup %d unaligned head bytes", align);
+
+               for (i = 0; i < bank->bus_width; i++)
+                       current_word[i] = 0;
+               copy_p = write_p;
+
+               /* copy bytes before the first write address */
+               for (i = 0; i < align; ++i, ++copy_p)
+               {
+                       uint8_t byte;
+                       if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       cfi_add_byte(bank, current_word, byte);
+               }
+
+               /* add bytes from the buffer */
+               for (; (i < bank->bus_width) && (count > 0); i++)
+               {
+                       cfi_add_byte(bank, current_word, *buffer++);
+                       count--;
+                       copy_p++;
+               }
+
+               /* if the buffer is already finished, copy bytes after the last write address */
+               for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
+               {
+                       uint8_t byte;
+                       if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       cfi_add_byte(bank, current_word, byte);
+               }
+
+               retval = cfi_write_word(bank, current_word, write_p);
+               if (retval != ERROR_OK)
+                       return retval;
+               write_p = copy_p;
+       }
+
+       /* handle blocks of bus_size aligned bytes */
+       blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */
+       switch (cfi_info->pri_id)
+       {
+               /* try block writes (fails without working area) */
+               case 1:
+               case 3:
+                       retval = cfi_intel_write_block(bank, buffer, write_p, blk_count);
+                       break;
+               case 2:
+                       retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+       }
+       if (retval == ERROR_OK)
+       {
+               /* Increment pointers and decrease count on succesful block write */
+               buffer += blk_count;
+               write_p += blk_count;
+               count -= blk_count;
+       }
+       else
+       {
+               if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+               {
+                       //adjust buffersize for chip width
+                       uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
+                       uint32_t buffermask = buffersize-1;
+                       uint32_t bufferwsize;
+
+                       switch (bank->chip_width)
+                       {
+                       case 4 : bufferwsize = buffersize / 4; break;
+                       case 2 : bufferwsize = buffersize / 2; break;
+                       case 1 : bufferwsize = buffersize; break;
+                       default:
+                               LOG_ERROR("Unsupported chip width %d", bank->chip_width);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+
+                       bufferwsize/=(bank->bus_width / bank->chip_width);
+
+                       /* fall back to memory writes */
+                       while (count >= (uint32_t)bank->bus_width)
+                       {
+                               int fallback;
+                               if ((write_p & 0xff) == 0)
+                               {
+                                       LOG_INFO("Programming at %08" PRIx32 ", count %08" PRIx32 " bytes remaining", write_p, count);
+                               }
+                               fallback = 1;
+                               if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask))
+                               {
+                                       retval = cfi_write_words(bank, buffer, bufferwsize, write_p);
+                                       if (retval == ERROR_OK)
+                                       {
+                                               buffer += buffersize;
+                                               write_p += buffersize;
+                                               count -= buffersize;
+                                               fallback = 0;
+                                       }
+                               }
+                               /* try the slow way? */
+                               if (fallback)
+                               {
+                                       for (i = 0; i < bank->bus_width; i++)
+                                               current_word[i] = 0;
+
+                                       for (i = 0; i < bank->bus_width; i++)
+                                       {
+                                               cfi_add_byte(bank, current_word, *buffer++);
+                                       }
+
+                                       retval = cfi_write_word(bank, current_word, write_p);
+                                       if (retval != ERROR_OK)
+                                               return retval;
+
+                                       write_p += bank->bus_width;
+                                       count -= bank->bus_width;
+                               }
+                       }
+               }
+               else
+                       return retval;
+       }
+
+       /* return to read array mode, so we can read from flash again for padding */
+       cfi_command(bank, 0xf0, current_word);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word)) != ERROR_OK)
+       {
+               return retval;
+       }
+       cfi_command(bank, 0xff, current_word);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       /* handle unaligned tail bytes */
+       if (count > 0)
+       {
+               LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
+
+               copy_p = write_p;
+               for (i = 0; i < bank->bus_width; i++)
+                       current_word[i] = 0;
+
+               for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
+               {
+                       cfi_add_byte(bank, current_word, *buffer++);
+                       count--;
+               }
+               for (; i < bank->bus_width; ++i, ++copy_p)
+               {
+                       uint8_t byte;
+                       if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       cfi_add_byte(bank, current_word, byte);
+               }
+               retval = cfi_write_word(bank, current_word, write_p);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       /* return to read array mode */
+       cfi_command(bank, 0xf0, current_word);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word)) != ERROR_OK)
+       {
+               return retval;
+       }
+       cfi_command(bank, 0xff, current_word);
+       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
+}
+
+static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *bank, void *param)
+{
+       (void) param;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+
+       pri_ext->_reversed_geometry = 1;
+}
+
+static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param)
+{
+       int i;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+       (void) param;
+
+       if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3))
+       {
+               LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device");
+
+               for (i = 0; i < cfi_info->num_erase_regions / 2; i++)
+               {
+                       int j = (cfi_info->num_erase_regions - 1) - i;
+                       uint32_t swap;
+
+                       swap = cfi_info->erase_region_info[i];
+                       cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j];
+                       cfi_info->erase_region_info[j] = swap;
+               }
+       }
+}
+
+static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct cfi_unlock_addresses *unlock_addresses = param;
+
+       pri_ext->_unlock1 = unlock_addresses->unlock1;
+       pri_ext->_unlock2 = unlock_addresses->unlock2;
+}
+
+
+static int cfi_query_string(struct flash_bank *bank, int address)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       int retval;
+       uint8_t command[8];
+
+       cfi_command(bank, 0x98, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, address), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
+       cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
+       cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
+
+       LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
+
+       if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               LOG_ERROR("Could not probe bank: no QRY");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_probe(struct flash_bank *bank)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint8_t command[8];
+       int num_sectors = 0;
+       int i;
+       int sector = 0;
+       uint32_t unlock1 = 0x555;
+       uint32_t unlock2 = 0x2aa;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       cfi_info->probed = 0;
+
+       /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses,
+        * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa
+        */
+       if (cfi_info->jedec_probe)
+       {
+               unlock1 = 0x5555;
+               unlock2 = 0x2aaa;
+       }
+
+       /* switch to read identifier codes mode ("AUTOSELECT") */
+       cfi_command(bank, 0xaa, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+       cfi_command(bank, 0x55, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+       cfi_command(bank, 0x90, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if (bank->chip_width == 1)
+       {
+               uint8_t manufacturer, device_id;
+               if ((retval = target_read_u8(target, flash_address(bank, 0, 0x00), &manufacturer)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               if ((retval = target_read_u8(target, flash_address(bank, 0, 0x01), &device_id)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               cfi_info->manufacturer = manufacturer;
+               cfi_info->device_id = device_id;
+       }
+       else if (bank->chip_width == 2)
+       {
+               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x00), &cfi_info->manufacturer)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x01), &cfi_info->device_id)) != ERROR_OK)
+               {
+                       return retval;
+               }
+       }
+
+       LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id);
+       /* switch back to read array mode */
+       cfi_command(bank, 0xf0, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+       cfi_command(bank, 0xff, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       /* check device/manufacturer ID for known non-CFI flashes. */
+       cfi_fixup_non_cfi(bank);
+
+       /* query only if this is a CFI compatible flash,
+        * otherwise the relevant info has already been filled in
+        */
+       if (cfi_info->not_cfi == 0)
+       {
+               int retval;
+
+               /* enter CFI query mode
+                * according to JEDEC Standard No. 68.01,
+                * a single bus sequence with address = 0x55, data = 0x98 should put
+                * the device into CFI query mode.
+                *
+                * SST flashes clearly violate this, and we will consider them incompatbile for now
+                */
+
+               retval = cfi_query_string(bank, 0x55);
+               if (retval != ERROR_OK)
+               {
+                       /*
+                        * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should
+                        * be harmless enough:
+                        *
+                        * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html
+                        */
+                       LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY.");
+                       retval = cfi_query_string(bank, 0x555);
+               }
+               if (retval != ERROR_OK)
+                       return retval;
+
+               cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
+               cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
+               cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
+               cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
+
+               LOG_DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
+
+               cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
+               cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
+               cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
+               cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
+               cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
+               cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
+               cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
+               cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
+               cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
+               cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
+               cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
+               cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
+
+               LOG_DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
+                       (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+                       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+                       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+                       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+               LOG_DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
+                       1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
+               LOG_DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+                       (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+                       (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+                       (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+
+               cfi_info->dev_size = 1 << cfi_query_u8(bank, 0, 0x27);
+               cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
+               cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
+               cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
+
+               LOG_DEBUG("size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: %x", cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
+
+               if (cfi_info->num_erase_regions)
+               {
+                       cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
+                       for (i = 0; i < cfi_info->num_erase_regions; i++)
+                       {
+                               cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
+                               LOG_DEBUG("erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "",
+                                         i,
+                                         (cfi_info->erase_region_info[i] & 0xffff) + 1,
+                                         (cfi_info->erase_region_info[i] >> 16) * 256);
+                       }
+               }
+               else
+               {
+                       cfi_info->erase_region_info = NULL;
+               }
+
+               /* We need to read the primary algorithm extended query table before calculating
+                * the sector layout to be able to apply fixups
+                */
+               switch (cfi_info->pri_id)
+               {
+                       /* Intel command set (standard and extended) */
+                       case 0x0001:
+                       case 0x0003:
+                               cfi_read_intel_pri_ext(bank);
+                               break;
+                       /* AMD/Spansion, Atmel, ... command set */
+                       case 0x0002:
+                               cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* default for all CFI flashs */
+                               cfi_read_0002_pri_ext(bank);
+                               break;
+                       default:
+                               LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                               break;
+               }
+
+               /* return to read array mode
+                * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
+                */
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+       } /* end CFI case */
+
+       /* apply fixups depending on the primary command set */
+       switch (cfi_info->pri_id)
+       {
+               /* Intel command set (standard and extended) */
+               case 0x0001:
+               case 0x0003:
+                       cfi_fixup(bank, cfi_0001_fixups);
+                       break;
+               /* AMD/Spansion, Atmel, ... command set */
+               case 0x0002:
+                       cfi_fixup(bank, cfi_0002_fixups);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+
+       if ((cfi_info->dev_size * bank->bus_width / bank->chip_width) != bank->size)
+       {
+               LOG_WARNING("configuration specifies 0x%" PRIx32 " size, but a 0x%" PRIx32 " size flash was found", bank->size, cfi_info->dev_size);
+       }
+
+       if (cfi_info->num_erase_regions == 0)
+       {
+               /* a device might have only one erase block, spanning the whole device */
+               bank->num_sectors = 1;
+               bank->sectors = malloc(sizeof(struct flash_sector));
+
+               bank->sectors[sector].offset = 0x0;
+               bank->sectors[sector].size = bank->size;
+               bank->sectors[sector].is_erased = -1;
+               bank->sectors[sector].is_protected = -1;
+       }
+       else
+       {
+               uint32_t offset = 0;
+
+               for (i = 0; i < cfi_info->num_erase_regions; i++)
+               {
+                       num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
+               }
+
+               bank->num_sectors = num_sectors;
+               bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+
+               for (i = 0; i < cfi_info->num_erase_regions; i++)
+               {
+                       uint32_t j;
+                       for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
+                       {
+                               bank->sectors[sector].offset = offset;
+                               bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width;
+                               offset += bank->sectors[sector].size;
+                               bank->sectors[sector].is_erased = -1;
+                               bank->sectors[sector].is_protected = -1;
+                               sector++;
+                       }
+               }
+               if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width))
+               {
+                       LOG_WARNING("CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \
+                               (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset);
+               }
+       }
+
+       cfi_info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int cfi_auto_probe(struct flash_bank *bank)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       if (cfi_info->probed)
+               return ERROR_OK;
+       return cfi_probe(bank);
+}
+
+
+static int cfi_intel_protect_check(struct flash_bank *bank)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct target *target = bank->target;
+       uint8_t command[CFI_MAX_BUS_WIDTH];
+       int i;
+
+       /* check if block lock bits are supported on this device */
+       if (!(pri_ext->blk_status_reg_mask & 0x1))
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       cfi_command(bank, 0x90, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint8_t block_status = cfi_get_u8(bank, i, 0x2);
+
+               if (block_status & 1)
+                       bank->sectors[i].is_protected = 1;
+               else
+                       bank->sectors[i].is_protected = 0;
+       }
+
+       cfi_command(bank, 0xff, command);
+       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+}
+
+static int cfi_spansion_protect_check(struct flash_bank *bank)
+{
+       int retval;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+       struct target *target = bank->target;
+       uint8_t command[8];
+       int i;
+
+       cfi_command(bank, 0xaa, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_command(bank, 0x55, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_command(bank, 0x90, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint8_t block_status = cfi_get_u8(bank, i, 0x2);
+
+               if (block_status & 1)
+                       bank->sectors[i].is_protected = 1;
+               else
+                       bank->sectors[i].is_protected = 0;
+       }
+
+       cfi_command(bank, 0xf0, command);
+       return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+}
+
+static int cfi_protect_check(struct flash_bank *bank)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (cfi_info->qry[0] != 'Q')
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       return cfi_intel_protect_check(bank);
+                       break;
+               case 2:
+                       return cfi_spansion_protect_check(bank);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+static int cfi_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int printed;
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       if (cfi_info->qry[0] == (char)-1)
+       {
+               printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
+               return ERROR_OK;
+       }
+
+       if (cfi_info->not_cfi == 0)
+               printed = snprintf(buf, buf_size, "\ncfi information:\n");
+       else
+               printed = snprintf(buf, buf_size, "\nnon-cfi flash:\n");
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "\nmfr: 0x%4.4x, id:0x%4.4x\n",
+               cfi_info->manufacturer, cfi_info->device_id);
+       buf += printed;
+       buf_size -= printed;
+
+       if (cfi_info->not_cfi == 0)
+       {
+       printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
+       buf += printed;
+       buf_size -= printed;
+
+               printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n",
+                                  (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+       buf += printed;
+       buf_size -= printed;
+
+               printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n",
+                                  1 << cfi_info->word_write_timeout_typ,
+                                  1 << cfi_info->buf_write_timeout_typ,
+                                  1 << cfi_info->block_erase_timeout_typ,
+                                  1 << cfi_info->chip_erase_timeout_typ);
+       buf += printed;
+       buf_size -= printed;
+
+               printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n",
+                                  (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+                 (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+                 (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+                 (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+       buf += printed;
+       buf_size -= printed;
+
+               printed = snprintf(buf, buf_size, "size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: %x\n",
+                                  cfi_info->dev_size,
+                                  cfi_info->interface_desc,
+                                  1 << cfi_info->max_buf_write_size);
+       buf += printed;
+       buf_size -= printed;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       cfi_intel_info(bank, buf, buf_size);
+                       break;
+               case 2:
+                       cfi_spansion_info(bank, buf, buf_size);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
+       }
+       }
+
+       return ERROR_OK;
+}
+
+struct flash_driver cfi_flash = {
+               .name = "cfi",
+               .flash_bank_command = &cfi_flash_bank_command,
+               .erase = &cfi_erase,
+               .protect = &cfi_protect,
+               .write = &cfi_write,
+               .probe = &cfi_probe,
+               .auto_probe = &cfi_auto_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &cfi_protect_check,
+               .info = &cfi_info,
+       };
diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h
new file mode 100644 (file)
index 0000000..d55fd34
--- /dev/null
@@ -0,0 +1,164 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef CFI_H
+#define CFI_H
+
+#include "flash.h"
+
+#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
+#define CFI_STATUS_POLL_MASK_DQ6_DQ7     0xC0 /* DQ6..DQ7 */
+
+struct cfi_flash_bank
+{
+       struct working_area *write_algorithm;
+
+       int x16_as_x8;
+       int jedec_probe;
+       int not_cfi;
+       int probed;
+
+       uint16_t manufacturer;
+       uint16_t device_id;
+
+       char qry[3];
+
+       /* identification string */
+       uint16_t pri_id;
+       uint16_t pri_addr;
+       uint16_t alt_id;
+       uint16_t alt_addr;
+
+       /* device-system interface */
+       uint8_t vcc_min;
+       uint8_t vcc_max;
+       uint8_t vpp_min;
+       uint8_t vpp_max;
+       uint8_t word_write_timeout_typ;
+       uint8_t buf_write_timeout_typ;
+       uint8_t block_erase_timeout_typ;
+       uint8_t chip_erase_timeout_typ;
+       uint8_t word_write_timeout_max;
+       uint8_t buf_write_timeout_max;
+       uint8_t block_erase_timeout_max;
+       uint8_t chip_erase_timeout_max;
+
+       uint8_t status_poll_mask;
+
+       /* flash geometry */
+       uint32_t dev_size;
+       uint16_t interface_desc;
+       uint16_t max_buf_write_size;
+       uint8_t num_erase_regions;
+       uint32_t *erase_region_info;
+
+       void *pri_ext;
+       void *alt_ext;
+};
+
+/* Intel primary extended query table
+ * as defined for the Advanced+ Boot Block Flash Memory (C3)
+ * and used by the linux kernel cfi driver (as of 2.6.14)
+ */
+struct cfi_intel_pri_ext
+{
+       char pri[3];
+       uint8_t major_version;
+       uint8_t minor_version;
+       uint32_t feature_support;
+       uint8_t suspend_cmd_support;
+       uint16_t blk_status_reg_mask;
+       uint8_t vcc_optimal;
+       uint8_t vpp_optimal;
+       uint8_t num_protection_fields;
+       uint16_t prot_reg_addr;
+       uint8_t fact_prot_reg_size;
+       uint8_t user_prot_reg_size;
+       uint8_t extra[0];
+};
+
+/* Spansion primary extended query table as defined for and used by
+ * the linux kernel cfi driver (as of 2.6.15)
+ */
+struct cfi_spansion_pri_ext
+{
+       uint8_t  pri[3];
+       uint8_t  major_version;
+       uint8_t  minor_version;
+       uint8_t  SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
+       uint8_t  EraseSuspend;
+       uint8_t  BlkProt;
+       uint8_t  TmpBlkUnprotect;
+       uint8_t  BlkProtUnprot;
+       uint8_t  SimultaneousOps;
+       uint8_t  BurstMode;
+       uint8_t  PageMode;
+       uint8_t  VppMin;
+       uint8_t  VppMax;
+       uint8_t  TopBottom;
+       int _reversed_geometry;
+       uint32_t _unlock1;
+       uint32_t _unlock2;
+};
+
+/* Atmel primary extended query table as defined for and used by
+ * the linux kernel cfi driver (as of 2.6.20+)
+ */
+struct cfi_atmel_pri_ext
+{
+       uint8_t pri[3];
+       uint8_t major_version;
+       uint8_t minor_version;
+       uint8_t features;
+       uint8_t bottom_boot;
+       uint8_t burst_mode;
+       uint8_t page_mode;
+};
+
+enum {
+       CFI_UNLOCK_555_2AA,
+       CFI_UNLOCK_5555_2AAA,
+};
+
+struct cfi_unlock_addresses
+{
+       uint32_t unlock1;
+       uint32_t unlock2;
+};
+
+struct cfi_fixup
+{
+       uint16_t mfr;
+       uint16_t id;
+       void (*fixup)(struct flash_bank *flash, void *param);
+       void *param;
+};
+
+#define CFI_MFR_AMD            0x0001
+#define CFI_MFR_FUJITSU        0x0004
+#define CFI_MFR_ATMEL  0x001F
+#define CFI_MFR_ST             0x0020  /* STMicroelectronics */
+#define CFI_MFR_AMIC   0x0037
+#define CFI_MFR_SST            0x00BF
+#define CFI_MFR_MX             0x00C2
+
+#define CFI_MFR_ANY            0xffff
+#define CFI_ID_ANY             0xffff
+
+#endif /* CFI_H */
diff --git a/src/flash/nor/ecos.c b/src/flash/nor/ecos.c
new file mode 100644 (file)
index 0000000..7a0b26f
--- /dev/null
@@ -0,0 +1,444 @@
+/***************************************************************************
+ *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
+ *   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 "flash.h"
+#include "embeddedice.h"
+#include "image.h"
+#include "algorithm.h"
+
+
+#if 0
+static uint32_t ecosflash_get_flash_status(struct flash_bank *bank);
+static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode);
+static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
+static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc);
+#endif
+
+struct ecosflash_flash_bank
+{
+       struct target *target;
+       struct working_area *write_algorithm;
+       struct working_area *erase_check_algorithm;
+       char *driverPath;
+       uint32_t start_address;
+};
+
+static const int sectorSize = 0x10000;
+
+char *
+flash_errmsg(int err);
+
+#ifndef __ECOS
+#define FLASH_ERR_OK              0x00  /* No error - operation complete */
+#define FLASH_ERR_INVALID         0x01  /* Invalid FLASH address */
+#define FLASH_ERR_ERASE           0x02  /* Error trying to erase */
+#define FLASH_ERR_LOCK            0x03  /* Error trying to lock/unlock */
+#define FLASH_ERR_PROGRAM         0x04  /* Error trying to program */
+#define FLASH_ERR_PROTOCOL        0x05  /* Generic error */
+#define FLASH_ERR_PROTECT         0x06  /* Device/region is write-protected */
+#define FLASH_ERR_NOT_INIT        0x07  /* FLASH info not yet initialized */
+#define FLASH_ERR_HWR             0x08  /* Hardware (configuration?) problem */
+#define FLASH_ERR_ERASE_SUSPEND   0x09  /* Device is in erase suspend mode */
+#define FLASH_ERR_PROGRAM_SUSPEND 0x0a  /* Device is in in program suspend mode */
+#define FLASH_ERR_DRV_VERIFY      0x0b  /* Driver failed to verify data */
+#define FLASH_ERR_DRV_TIMEOUT     0x0c  /* Driver timed out waiting for device */
+#define FLASH_ERR_DRV_WRONG_PART  0x0d  /* Driver does not support device */
+#define FLASH_ERR_LOW_VOLTAGE     0x0e  /* Not enough juice to complete job */
+
+char *
+flash_errmsg(int err)
+{
+       switch (err) {
+       case FLASH_ERR_OK:
+               return "No error - operation complete";
+       case FLASH_ERR_ERASE_SUSPEND:
+               return "Device is in erase suspend state";
+       case FLASH_ERR_PROGRAM_SUSPEND:
+               return "Device is in program suspend state";
+       case FLASH_ERR_INVALID:
+               return "Invalid FLASH address";
+       case FLASH_ERR_ERASE:
+               return "Error trying to erase";
+       case FLASH_ERR_LOCK:
+               return "Error trying to lock/unlock";
+       case FLASH_ERR_PROGRAM:
+               return "Error trying to program";
+       case FLASH_ERR_PROTOCOL:
+               return "Generic error";
+       case FLASH_ERR_PROTECT:
+               return "Device/region is write-protected";
+       case FLASH_ERR_NOT_INIT:
+               return "FLASH sub-system not initialized";
+       case FLASH_ERR_DRV_VERIFY:
+               return "Data verify failed after operation";
+       case FLASH_ERR_DRV_TIMEOUT:
+               return "Driver timed out waiting for device";
+       case FLASH_ERR_DRV_WRONG_PART:
+               return "Driver does not support device";
+       case FLASH_ERR_LOW_VOLTAGE:
+               return "Device reports low voltage";
+       default:
+               return "Unknown error";
+       }
+}
+#endif
+
+/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>
+ */
+FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
+{
+       struct ecosflash_flash_bank *info;
+
+       if (CMD_ARGC < 7)
+       {
+               LOG_WARNING("incomplete flash_bank ecosflash configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       info = malloc(sizeof(struct ecosflash_flash_bank));
+       if (info == NULL)
+       {
+               LOG_ERROR("no memory for flash bank info");
+               exit(-1);
+       }
+       bank->driver_priv = info;
+       info->driverPath = strdup(CMD_ARGV[6]);
+
+       /* eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as
+        * a way to improve impedance match between OpenOCD and eCos flash
+        * driver.
+        */
+       int i = 0;
+       uint32_t offset = 0;
+       bank->num_sectors = bank->size/sectorSize;
+       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 = sectorSize;
+               offset += bank->sectors[i].size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 0;
+       }
+
+       info->target = get_target(CMD_ARGV[5]);
+       if (info->target == NULL)
+       {
+               LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+static int loadDriver(struct ecosflash_flash_bank *info)
+{
+       size_t buf_cnt;
+       size_t image_size;
+       struct image image;
+
+       image.base_address_set = 0;
+       image.start_address_set = 0;
+       struct target *target = info->target;
+       int retval;
+
+       if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       info->start_address = image.start_address;
+
+       image_size = 0x0;
+       int i;
+       for (i = 0; i < image.num_sections; i++)
+       {
+               void *buffer = malloc(image.sections[i].size);
+               int retval;
+               if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
+               {
+                       free(buffer);
+                       image_close(&image);
+                       return retval;
+               }
+               target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
+               image_size += buf_cnt;
+               LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "",
+                               buf_cnt, image.sections[i].base_address);
+
+               free(buffer);
+       }
+
+       image_close(&image);
+
+       return ERROR_OK;
+}
+
+static int const OFFSET_ERASE = 0x0;
+static int const OFFSET_ERASE_SIZE = 0x8;
+static int const OFFSET_FLASH = 0xc;
+static int const OFFSET_FLASH_SIZE = 0x8;
+static int const OFFSET_GET_WORKAREA = 0x18;
+static int const OFFSET_GET_WORKAREA_SIZE = 0x4;
+
+static int runCode(struct ecosflash_flash_bank *info,
+               uint32_t codeStart, uint32_t codeStop, uint32_t r0, uint32_t r1, uint32_t r2,
+               uint32_t *result,
+               /* timeout in ms */
+               int timeout)
+{
+       struct target *target = info->target;
+
+       struct reg_param reg_params[3];
+       struct armv4_5_algorithm armv4_5_info;
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+
+       buf_set_u32(reg_params[0].value, 0, 32, r0);
+       buf_set_u32(reg_params[1].value, 0, 32, r1);
+       buf_set_u32(reg_params[2].value, 0, 32, r2);
+
+       int retval;
+       if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+                       codeStart,
+                       codeStop, timeout,
+                       &armv4_5_info)) != ERROR_OK)
+       {
+               LOG_ERROR("error executing eCos flash algorithm");
+               return retval;
+       }
+
+       *result = buf_get_u32(reg_params[0].value, 0, 32);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+
+       return ERROR_OK;
+}
+
+static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address, uint32_t len)
+{
+       int retval;
+       int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/
+
+       retval = loadDriver(info);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t flashErr;
+       retval = runCode(info,
+                       info->start_address + OFFSET_ERASE,
+                       info->start_address + OFFSET_ERASE + OFFSET_ERASE_SIZE,
+                       address,
+                       len,
+                       0,
+                       &flashErr,
+                       timeout
+);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (flashErr != 0x0)
+       {
+               LOG_ERROR("Flash erase failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32_t address, uint32_t len)
+{
+       struct target *target = info->target;
+       const int chunk = 8192;
+       int retval = ERROR_OK;
+       int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/
+
+       retval = loadDriver(info);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t buffer;
+       retval = runCode(info,
+                       info->start_address + OFFSET_GET_WORKAREA,
+                       info->start_address + OFFSET_GET_WORKAREA + OFFSET_GET_WORKAREA_SIZE,
+                       0,
+                       0,
+                       0,
+                       &buffer,
+                       1000);
+       if (retval != ERROR_OK)
+               return retval;
+
+
+       uint32_t i;
+       for (i = 0; i < len; i += chunk)
+       {
+               int t = len-i;
+               if (t > chunk)
+               {
+                       t = chunk;
+               }
+
+               int retval;
+               retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               uint32_t flashErr;
+               retval = runCode(info,
+                               info->start_address + OFFSET_FLASH,
+                               info->start_address + OFFSET_FLASH + OFFSET_FLASH_SIZE,
+                               buffer,
+                               address + i,
+                               t,
+                               &flashErr,
+                               timeout);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (flashErr != 0x0)
+               {
+                       LOG_ERROR("Flash prog failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
+                       return ERROR_FAIL;
+               }
+       }
+       return ERROR_OK;
+}
+
+static int ecosflash_probe(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+#if 0
+static void command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
+{
+       struct ecosflash_flash_bank *info = bank->driver_priv;
+       int i;
+
+       if (info->target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = bank->bus_width; i > 0; i--)
+               {
+                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
+               }
+       }
+       else
+       {
+               for (i = 1; i <= bank->bus_width; i++)
+               {
+                       *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
+               }
+       }
+}
+#endif
+
+#if 0
+static uint32_t ecosflash_address(struct flash_bank *bank, uint32_t address)
+{
+       uint32_t retval = 0;
+       switch (bank->bus_width)
+       {
+               case 4:
+                       retval = address & 0xfffffffc;
+               case 2:
+                       retval = address & 0xfffffffe;
+               case 1:
+                       retval = address;
+       }
+
+       return retval + bank->base;
+}
+#endif
+
+static int ecosflash_erase(struct flash_bank *bank, int first, int last)
+{
+       struct flash_bank *c = bank;
+       struct ecosflash_flash_bank *info = bank->driver_priv;
+       return eCosBoard_erase(info, c->base + first*sectorSize, sectorSize*(last-first + 1));
+}
+
+static int ecosflash_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       return ERROR_OK;
+}
+
+static int ecosflash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct ecosflash_flash_bank *info = bank->driver_priv;
+       struct flash_bank *c = bank;
+       return eCosBoard_flash(info, buffer, c->base + offset, count);
+}
+
+static int ecosflash_protect_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static int ecosflash_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct ecosflash_flash_bank *info = bank->driver_priv;
+       snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);
+       return ERROR_OK;
+}
+
+#if 0
+static uint32_t ecosflash_get_flash_status(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode)
+{
+
+}
+
+static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
+{
+       return ERROR_OK;
+}
+
+static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc)
+{
+       return ERROR_OK;
+}
+#endif
+
+struct flash_driver ecosflash_flash = {
+               .name = "ecosflash",
+               .flash_bank_command = &ecosflash_flash_bank_command,
+               .erase = &ecosflash_erase,
+               .protect = &ecosflash_protect,
+               .write = &ecosflash_write,
+               .probe = &ecosflash_probe,
+               .auto_probe = &ecosflash_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &ecosflash_protect_check,
+               .info = &ecosflash_info
+       };
diff --git a/src/flash/nor/faux.c b/src/flash/nor/faux.c
new file mode 100644 (file)
index 0000000..caec2c7
--- /dev/null
@@ -0,0 +1,149 @@
+/***************************************************************************
+ *   Copyright (C) 2009 Ã˜yvind Harboe                                      *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
+ *   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 "flash.h"
+#include "image.h"
+#include "../hello.h"
+
+
+struct faux_flash_bank
+{
+       struct target *target;
+       uint8_t *memory;
+       uint32_t start_address;
+};
+
+static const int sectorSize = 0x10000;
+
+
+/* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath>
+ */
+FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
+{
+       struct faux_flash_bank *info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank faux configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       info = malloc(sizeof(struct faux_flash_bank));
+       if (info == NULL)
+       {
+               LOG_ERROR("no memory for flash bank info");
+               return ERROR_FAIL;
+       }
+       info->memory = malloc(bank->size);
+       if (info == NULL)
+       {
+               free(info);
+               LOG_ERROR("no memory for flash bank info");
+               return ERROR_FAIL;
+       }
+       bank->driver_priv = info;
+
+       /* Use 0x10000 as a fixed sector size. */
+       int i = 0;
+       uint32_t offset = 0;
+       bank->num_sectors = bank->size/sectorSize;
+       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 = sectorSize;
+               offset += bank->sectors[i].size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 0;
+       }
+
+       info->target = get_target(CMD_ARGV[5]);
+       if (info->target == NULL)
+       {
+               LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
+               free(info->memory);
+               free(info);
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+static int faux_erase(struct flash_bank *bank, int first, int last)
+{
+       struct faux_flash_bank *info = bank->driver_priv;
+       memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1));
+       return ERROR_OK;
+}
+
+static int faux_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       LOG_USER("set protection sector %d to %d to %s", first, last, set?"on":"off");
+       return ERROR_OK;
+}
+
+static int faux_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct faux_flash_bank *info = bank->driver_priv;
+       memcpy(info->memory + offset, buffer, count);
+       return ERROR_OK;
+}
+
+static int faux_protect_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static int faux_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "faux flash driver");
+       return ERROR_OK;
+}
+
+static int faux_probe(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static const struct command_registration faux_command_handlers[] = {
+       {
+               .name = "faux",
+               .mode = COMMAND_ANY,
+               .help = "faux flash command group",
+               .chain = hello_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver faux_flash = {
+               .name = "faux",
+               .commands = faux_command_handlers,
+               .flash_bank_command = &faux_flash_bank_command,
+               .erase = &faux_erase,
+               .protect = &faux_protect,
+               .write = &faux_write,
+               .probe = &faux_probe,
+               .auto_probe = &faux_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &faux_protect_check,
+               .info = &faux_info
+       };
diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c
new file mode 100644 (file)
index 0000000..418b5b0
--- /dev/null
@@ -0,0 +1,812 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius            *
+ *   didele.deze@gmail.com                                                 *
+ *                                                                         *
+ *   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 "lpc2000.h"
+#include "armv7m.h"
+#include "binarybuffer.h"
+#include "algorithm.h"
+
+
+/* flash programming support for NXP LPC17xx and LPC2xxx devices
+ * currently supported devices:
+ * variant 1 (lpc2000_v1):
+ * - 2104 | 5 | 6
+ * - 2114 | 9
+ * - 2124 | 9
+ * - 2194
+ * - 2212 | 4
+ * - 2292 | 4
+ *
+ * variant 2 (lpc2000_v2):
+ * - 213x
+ * - 214x
+ * - 2101 | 2 | 3
+ * - 2364 | 6 | 8
+ * - 2378
+ *
+ * lpc1700:
+ * - 175x
+ * - 176x (tested with LPC1768)
+ */
+
+static int lpc2000_build_sector_list(struct flash_bank *bank)
+{
+       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
+       int i;
+       uint32_t offset = 0;
+
+       /* default to a 4096 write buffer */
+       lpc2000_info->cmd51_max_buffer = 4096;
+
+       if (lpc2000_info->variant == lpc2000_v1)
+       {
+               /* variant 1 has different layout for 128kb and 256kb flashes */
+               if (bank->size == 128 * 1024)
+               {
+                       bank->num_sectors = 16;
+                       bank->sectors = malloc(sizeof(struct flash_sector) * 16);
+                       for (i = 0; i < 16; i++)
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 8 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+               }
+               else if (bank->size == 256 * 1024)
+               {
+                       bank->num_sectors = 18;
+                       bank->sectors = malloc(sizeof(struct flash_sector) * 18);
+
+                       for (i = 0; i < 8; i++)
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 8 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+                       for (i = 8; i < 10; i++)
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 64 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+                       for (i = 10; i < 18; i++)
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 8 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+               }
+               else
+               {
+                       LOG_ERROR("BUG: unknown bank->size encountered");
+                       exit(-1);
+               }
+       }
+       else if (lpc2000_info->variant == lpc2000_v2)
+       {
+               /* variant 2 has a uniform layout, only number of sectors differs */
+               switch (bank->size)
+               {
+                       case 4 * 1024:
+                               lpc2000_info->cmd51_max_buffer = 1024;
+                               bank->num_sectors = 1;
+                               break;
+                       case 8 * 1024:
+                               lpc2000_info->cmd51_max_buffer = 1024;
+                               bank->num_sectors = 2;
+                               break;
+                       case 16 * 1024:
+                               bank->num_sectors = 4;
+                               break;
+                       case 32 * 1024:
+                               bank->num_sectors = 8;
+                               break;
+                       case 64 * 1024:
+                               bank->num_sectors = 9;
+                               break;
+                       case 128 * 1024:
+                               bank->num_sectors = 11;
+                               break;
+                       case 256 * 1024:
+                               bank->num_sectors = 15;
+                               break;
+                       case 512 * 1024:
+                       case 500 * 1024:
+                               bank->num_sectors = 27;
+                               break;
+                       default:
+                               LOG_ERROR("BUG: unknown bank->size encountered");
+                               exit(-1);
+                               break;
+               }
+
+               bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+
+               for (i = 0; i < bank->num_sectors; i++)
+               {
+                       if ((i >= 0) && (i < 8))
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 4 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+                       if ((i >= 8) && (i < 22))
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 32 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+                       if ((i >= 22) && (i < 27))
+                       {
+                               bank->sectors[i].offset = offset;
+                               bank->sectors[i].size = 4 * 1024;
+                               offset += bank->sectors[i].size;
+                               bank->sectors[i].is_erased = -1;
+                               bank->sectors[i].is_protected = 1;
+                       }
+               }
+       }
+       else if (lpc2000_info->variant == lpc1700)
+       {
+               switch(bank->size)
+               {
+                       case 32 * 1024:
+                               bank->num_sectors = 8;
+                               break;
+                       case 64 * 1024:
+                               bank->num_sectors = 16;
+                               break;
+                       case 128 * 1024:
+                               bank->num_sectors = 18;
+                               break;
+                       case 256 * 1024:
+                               bank->num_sectors = 22;
+                               break;
+                       case 512 * 1024:
+                               bank->num_sectors = 30;
+                               break;
+                       default:
+                               LOG_ERROR("BUG: unknown bank->size encountered");
+                               exit(-1);
+               }
+
+               bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+
+               for(i = 0; i < bank->num_sectors; i++)
+               {
+                       bank->sectors[i].offset = offset;
+                       /* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
+                       bank->sectors[i].size = (i < 16)? 4 * 1024 : 32 * 1024;
+                       offset += bank->sectors[i].size;
+                       bank->sectors[i].is_erased = -1;
+                       bank->sectors[i].is_protected = 1;
+               }
+       }
+       else
+       {
+               LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
+               exit(-1);
+       }
+
+       return ERROR_OK;
+}
+
+/* call LPC1700/LPC2000 IAP function
+ * uses 180 bytes working area
+ * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
+ * 0x8 to 0x1f: command parameter table (1+5 words)
+ * 0x20 to 0x33: command result table (1+4 words)
+ * 0x34 to 0xb3: stack (only 128b needed)
+ */
+static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
+{
+       int retval;
+       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
+       struct target *target = bank->target;
+       struct mem_param mem_params[2];
+       struct reg_param reg_params[5];
+       struct armv4_5_algorithm armv4_5_info; /* for LPC2000 */
+       struct armv7m_algorithm armv7m_info;   /* for LPC1700 */
+       uint32_t status_code;
+       uint32_t iap_entry_point = 0; /* to make compiler happier */
+
+       /* regrab previously allocated working_area, or allocate a new one */
+       if (!lpc2000_info->iap_working_area)
+       {
+               uint8_t jump_gate[8];
+
+               /* make sure we have a working area */
+               if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK)
+               {
+                       LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               /* write IAP code to working area */
+               switch(lpc2000_info->variant)
+               {
+                       case lpc1700:
+                               target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
+                               target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
+                               break;
+                       case lpc2000_v1:
+                       case lpc2000_v2:
+                               target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
+                               target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
+                               break;
+                       default:
+                               LOG_ERROR("BUG: unknown bank->size encountered");
+                               exit(-1);
+               }
+
+               if ((retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
+               {
+                       LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address);
+                       return retval;
+               }
+       }
+
+       switch(lpc2000_info->variant)
+       {
+               case lpc1700:
+                       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+                       armv7m_info.core_mode = ARMV7M_MODE_ANY;
+                       iap_entry_point = 0x1fff1ff1;
+                       break;
+               case lpc2000_v1:
+               case lpc2000_v2:
+                       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+                       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+                       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+                       iap_entry_point = 0x7ffffff1;
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown lpc2000->variant encountered");
+                       exit(-1);
+       }
+
+       /* command parameter table */
+       init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT);
+       target_buffer_set_u32(target, mem_params[0].value, code);
+       target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
+       target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
+       target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]);
+       target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);
+       target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);
+
+       /* command result table */
+       init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN);
+
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
+
+       /* IAP entry point */
+       init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);
+       buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
+
+       switch(lpc2000_info->variant)
+       {
+               case lpc1700:
+                       /* IAP stack */
+                       init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
+                       buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
+
+                       /* return address */
+                       init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
+                       buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
+
+                       target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
+                       break;
+               case lpc2000_v1:
+               case lpc2000_v2:
+                       /* IAP stack */
+                       init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);
+                       buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
+
+                       /* return address */
+                       init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
+                       buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04);
+
+                       target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown lpc2000->variant encountered");
+                       exit(-1);
+       }
+
+
+       status_code     = target_buffer_get_u32(target, mem_params[1].value);
+       result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
+       result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
+       result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
+       result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);
+
+       LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32") completed with result = %8.8" PRIx32,
+                         code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);
+
+       destroy_mem_param(&mem_params[0]);
+       destroy_mem_param(&mem_params[1]);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+
+       return status_code;
+}
+
+static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
+{
+       uint32_t param_table[5];
+       uint32_t result_table[4];
+       int status_code;
+       int i;
+
+       if ((first < 0) || (last >= bank->num_sectors))
+               return ERROR_FLASH_SECTOR_INVALID;
+
+       for (i = first; i <= last; i++)
+       {
+               /* check single sector */
+               param_table[0] = param_table[1] = i;
+               status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
+
+               switch (status_code)
+               {
+                       case ERROR_FLASH_OPERATION_FAILED:
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       case LPC2000_CMD_SUCCESS:
+                               bank->sectors[i].is_erased = 1;
+                               break;
+                       case LPC2000_SECTOR_NOT_BLANK:
+                               bank->sectors[i].is_erased = 0;
+                               break;
+                       case LPC2000_INVALID_SECTOR:
+                               bank->sectors[i].is_erased = 0;
+                               break;
+                       case LPC2000_BUSY:
+                               return ERROR_FLASH_BUSY;
+                               break;
+                       default:
+                               LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code);
+                               exit(-1);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/*
+ * flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
+ */
+FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
+{
+       struct lpc2000_flash_bank *lpc2000_info;
+
+       if (CMD_ARGC < 8)
+       {
+               LOG_WARNING("incomplete flash_bank lpc2000 configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
+       bank->driver_priv = lpc2000_info;
+
+       if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0)
+       {
+               lpc2000_info->variant = lpc2000_v1;
+               lpc2000_info->cmd51_dst_boundary = 512;
+               lpc2000_info->cmd51_can_256b = 0;
+               lpc2000_info->cmd51_can_8192b = 1;
+               lpc2000_info->checksum_vector = 5;
+       }
+       else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0)
+       {
+               lpc2000_info->variant = lpc2000_v2;
+               lpc2000_info->cmd51_dst_boundary = 256;
+               lpc2000_info->cmd51_can_256b = 1;
+               lpc2000_info->cmd51_can_8192b = 0;
+               lpc2000_info->checksum_vector = 5;
+       }
+       else if (strcmp(CMD_ARGV[6], "lpc1700") == 0)
+       {
+               lpc2000_info->variant = lpc1700;
+               lpc2000_info->cmd51_dst_boundary = 256;
+               lpc2000_info->cmd51_can_256b = 1;
+               lpc2000_info->cmd51_can_8192b = 0;
+               lpc2000_info->checksum_vector = 7;
+       }
+       else
+       {
+               LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
+               free(lpc2000_info);
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       lpc2000_info->iap_working_area = NULL;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk);
+       lpc2000_info->calc_checksum = 0;
+       lpc2000_build_sector_list(bank);
+
+       if (CMD_ARGC >= 9)
+       {
+               if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
+                       lpc2000_info->calc_checksum = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int lpc2000_erase(struct flash_bank *bank, int first, int last)
+{
+       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
+       uint32_t param_table[5];
+       uint32_t result_table[4];
+       int status_code;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       param_table[0] = first;
+       param_table[1] = last;
+       param_table[2] = lpc2000_info->cclk;
+
+       /* Prepare sectors */
+       status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
+       switch (status_code)
+       {
+               case ERROR_FLASH_OPERATION_FAILED:
+                       return ERROR_FLASH_OPERATION_FAILED;
+               case LPC2000_CMD_SUCCESS:
+                       break;
+               case LPC2000_INVALID_SECTOR:
+                       return ERROR_FLASH_SECTOR_INVALID;
+                       break;
+               default:
+                       LOG_WARNING("lpc2000 prepare sectors returned %i", status_code);
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Erase sectors */
+       status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
+       switch (status_code)
+       {
+               case ERROR_FLASH_OPERATION_FAILED:
+                       return ERROR_FLASH_OPERATION_FAILED;
+               case LPC2000_CMD_SUCCESS:
+                       break;
+               case LPC2000_INVALID_SECTOR:
+                       return ERROR_FLASH_SECTOR_INVALID;
+                       break;
+               default:
+                       LOG_WARNING("lpc2000 erase sectors returned %i", status_code);
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       /* can't protect/unprotect on the lpc2000 */
+       return ERROR_OK;
+}
+
+static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t dst_min_alignment;
+       uint32_t bytes_remaining = count;
+       uint32_t bytes_written = 0;
+       int first_sector = 0;
+       int last_sector = 0;
+       uint32_t param_table[5];
+       uint32_t result_table[4];
+       int status_code;
+       int i;
+       struct working_area *download_area;
+       int retval = ERROR_OK;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > bank->size)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       dst_min_alignment = lpc2000_info->cmd51_dst_boundary;
+
+       if (offset % dst_min_alignment)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               if (offset >= bank->sectors[i].offset)
+                       first_sector = i;
+               if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
+                       last_sector = i;
+       }
+
+       LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
+
+       /* check if exception vectors should be flashed */
+       if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
+       {
+               uint32_t checksum = 0;
+               int i;
+               for (i = 0; i < 8; i++)
+               {
+                       LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
+                       if (i != lpc2000_info->checksum_vector)
+                               checksum += buf_get_u32(buffer + (i * 4), 0, 32);
+               }
+               checksum = 0 - checksum;
+               LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
+
+               uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32);
+               if (original_value != checksum)
+               {
+                       LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is different from calculated vector checksum (0x%8.8" PRIx32 ").",
+                                       original_value, checksum);
+                       LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
+               }
+
+               buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum);
+       }
+
+       /* allocate a working area */
+       if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK)
+       {
+               LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       while (bytes_remaining > 0)
+       {
+               uint32_t thisrun_bytes;
+               if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
+                       thisrun_bytes = lpc2000_info->cmd51_max_buffer;
+               else if (bytes_remaining >= 1024)
+                       thisrun_bytes = 1024;
+               else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
+                       thisrun_bytes = 512;
+               else
+                       thisrun_bytes = 256;
+
+               /* Prepare sectors */
+               param_table[0] = first_sector;
+               param_table[1] = last_sector;
+               status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
+               switch (status_code)
+               {
+                       case ERROR_FLASH_OPERATION_FAILED:
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+                       case LPC2000_CMD_SUCCESS:
+                               break;
+                       case LPC2000_INVALID_SECTOR:
+                               retval = ERROR_FLASH_SECTOR_INVALID;
+                               break;
+                       default:
+                               LOG_WARNING("lpc2000 prepare sectors returned %i", status_code);
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+               }
+
+               /* Exit if error occured */
+               if (retval != ERROR_OK)
+                       break;
+
+               if (bytes_remaining >= thisrun_bytes)
+               {
+                       if ((retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written)) != ERROR_OK)
+                       {
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+                       }
+               }
+               else
+               {
+                       uint8_t *last_buffer = malloc(thisrun_bytes);
+                       memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
+                       memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining);
+                       target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
+                       free(last_buffer);
+               }
+
+               LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32 , thisrun_bytes, bank->base + offset + bytes_written);
+
+               /* Write data */
+               param_table[0] = bank->base + offset + bytes_written;
+               param_table[1] = download_area->address;
+               param_table[2] = thisrun_bytes;
+               param_table[3] = lpc2000_info->cclk;
+               status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
+               switch (status_code)
+               {
+                       case ERROR_FLASH_OPERATION_FAILED:
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+                       case LPC2000_CMD_SUCCESS:
+                               break;
+                       case LPC2000_INVALID_SECTOR:
+                               retval = ERROR_FLASH_SECTOR_INVALID;
+                               break;
+                       default:
+                               LOG_WARNING("lpc2000 returned %i", status_code);
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+               }
+
+               /* Exit if error occured */
+               if (retval != ERROR_OK)
+                       break;
+
+               if (bytes_remaining > thisrun_bytes)
+                       bytes_remaining -= thisrun_bytes;
+               else
+                       bytes_remaining = 0;
+               bytes_written += thisrun_bytes;
+       }
+
+       target_free_working_area(target, download_area);
+
+       return retval;
+}
+
+static int lpc2000_probe(struct flash_bank *bank)
+{
+       /* we can't probe on an lpc2000
+        * if this is an lpc2xxx, it has the configured flash
+        */
+       return ERROR_OK;
+}
+
+static int lpc2000_erase_check(struct flash_bank *bank)
+{
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+static int lpc2000_protect_check(struct flash_bank *bank)
+{
+       /* sectors are always protected */
+       return ERROR_OK;
+}
+
+static int lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
+
+       snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(lpc2000_handle_part_id_command)
+{
+       uint32_t param_table[5];
+       uint32_t result_table[4];
+       int status_code;
+
+       if (CMD_ARGC < 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
+       {
+               if (status_code == ERROR_FLASH_OPERATION_FAILED)
+               {
+                       command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface");
+                       return ERROR_OK;
+               }
+               command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code);
+       }
+       else
+       {
+               command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration lpc2000_exec_command_handlers[] = {
+       {
+               .name = "part_id",
+               .handler = &lpc2000_handle_part_id_command,
+               .mode = COMMAND_EXEC,
+               .help = "print part id of lpc2000 flash bank <num>",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration lpc2000_command_handlers[] = {
+       {
+               .name = "lpc2000",
+               .mode = COMMAND_ANY,
+               .help = "lpc2000 flash command group",
+               .chain = lpc2000_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver lpc2000_flash = {
+               .name = "lpc2000",
+               .commands = lpc2000_command_handlers,
+               .flash_bank_command = &lpc2000_flash_bank_command,
+               .erase = &lpc2000_erase,
+               .protect = &lpc2000_protect,
+               .write = &lpc2000_write,
+               .probe = &lpc2000_probe,
+               .auto_probe = &lpc2000_probe,
+               .erase_check = &lpc2000_erase_check,
+               .protect_check = &lpc2000_protect_check,
+               .info = &lpc2000_info,
+       };
+
+
diff --git a/src/flash/nor/lpc2000.h b/src/flash/nor/lpc2000.h
new file mode 100644 (file)
index 0000000..08e278a
--- /dev/null
@@ -0,0 +1,73 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius            *
+ *   didele.deze@gmail.com                                                 *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef LPC2000_H
+#define LPC2000_H
+
+#include "flash.h"
+
+typedef enum
+{
+       lpc2000_v1,
+       lpc2000_v2,
+       lpc1700
+} lpc2000_variant;
+
+struct lpc2000_flash_bank
+{
+       lpc2000_variant variant;
+       struct working_area *iap_working_area;
+       uint32_t cclk;
+       int cmd51_dst_boundary;
+       int cmd51_can_256b;
+       int cmd51_can_8192b;
+       int calc_checksum;
+       uint32_t cmd51_max_buffer;
+       int checksum_vector;
+};
+
+enum lpc2000_status_codes
+{
+       LPC2000_CMD_SUCCESS = 0,
+       LPC2000_INVALID_COMMAND = 1,
+       LPC2000_SRC_ADDR_ERROR = 2,
+       LPC2000_DST_ADDR_ERROR = 3,
+       LPC2000_SRC_ADDR_NOT_MAPPED = 4,
+       LPC2000_DST_ADDR_NOT_MAPPED = 5,
+       LPC2000_COUNT_ERROR = 6,
+       LPC2000_INVALID_SECTOR = 7,
+       LPC2000_SECTOR_NOT_BLANK = 8,
+       LPC2000_SECTOR_NOT_PREPARED = 9,
+       LPC2000_COMPARE_ERROR = 10,
+       LPC2000_BUSY = 11,
+       LPC2000_PARAM_ERROR = 12,
+       LPC2000_ADDR_ERROR = 13,
+       LPC2000_ADDR_NOT_MAPPED = 14,
+       LPC2000_CMD_NOT_LOCKED = 15,
+       LPC2000_INVALID_CODE = 16,
+       LPC2000_INVALID_BAUD_RATE = 17,
+       LPC2000_INVALID_STOP_BIT = 18,
+       LPC2000_CRP_ENABLED = 19
+
+};
+
+#endif /* LPC2000_H */
diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c
new file mode 100644 (file)
index 0000000..446fc9d
--- /dev/null
@@ -0,0 +1,485 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by                                                            *
+ *   Karl RobinSod <karl.robinsod@gmail.com>                               *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/***************************************************************************
+* There are some things to notice
+*
+* You need to unprotect flash sectors each time you connect the OpenOCD
+* Dumping 1MB takes about 60 Seconds
+* Full erase (sectors 0-22 inclusive) takes 2-4 seconds
+* Writing 1MB takes 88 seconds
+*
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lpc288x.h"
+#include "binarybuffer.h"
+
+
+#define LOAD_TIMER_ERASE       0
+#define LOAD_TIMER_WRITE       1
+
+#define FLASH_PAGE_SIZE                512
+
+/* LPC288X control registers */
+#define DBGU_CIDR              0x8000507C
+/* LPC288X flash registers */
+#define F_CTRL                 0x80102000      /* Flash control register R/W 0x5 */
+#define F_STAT                 0x80102004      /* Flash status register RO 0x45 */
+#define F_PROG_TIME            0x80102008      /* Flash program time register R/W 0 */
+#define F_WAIT                 0x80102010      /* Flash read wait state register R/W 0xC004 */
+#define F_CLK_TIME             0x8010201C      /* Flash clock divider for 66 kHz generation R/W 0 */
+#define F_INTEN_CLR            0x80102FD8      /* Clear interrupt enable bits WO - */
+#define F_INTEN_SET            0x80102FDC      /* Set interrupt enable bits WO - */
+#define F_INT_STAT             0x80102FE0      /* Interrupt status bits RO 0 */
+#define F_INTEN                        0x80102FE4      /* Interrupt enable bits RO 0 */
+#define F_INT_CLR              0x80102FE8      /* Clear interrupt status bits WO */
+#define F_INT_SET              0x80102FEC      /* Set interrupt status bits WO - */
+#define FLASH_PD               0x80005030      /* Allows turning off the Flash memory for power savings. R/W 1*/
+#define FLASH_INIT             0x80005034      /* Monitors Flash readiness, such as recovery from Power Down mode. R/W -*/
+
+/* F_CTRL bits */
+#define FC_CS                  0x0001
+#define FC_FUNC                        0x0002
+#define FC_WEN                 0x0004
+#define FC_RD_LATCH            0x0020
+#define FC_PROTECT             0x0080
+#define FC_SET_DATA            0x0400
+#define FC_RSSL                        0x0800
+#define FC_PROG_REQ            0x1000
+#define FC_CLR_BUF             0x4000
+#define FC_LOAD_REQ            0x8000
+/* F_STAT bits */
+#define FS_DONE                        0x0001
+#define FS_PROGGNT             0x0002
+#define FS_RDY                 0x0004
+#define FS_ERR                 0x0020
+/* F_PROG_TIME */
+#define FPT_TIME_MASK  0x7FFF
+
+#define FPT_ENABLE             0x8000
+/* F_WAIT */
+#define FW_WAIT_STATES_MASK            0x00FF
+#define FW_SET_MASK                            0xC000
+
+/* F_CLK_TIME */
+#define FCT_CLK_DIV_MASK    0x0FFF
+
+static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout);
+static void lpc288x_load_timer(int erase, struct target *target);
+static void lpc288x_set_flash_clk(struct flash_bank *bank);
+static uint32_t lpc288x_system_ready(struct flash_bank *bank);
+
+static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+       uint32_t status;
+       struct target *target = bank->target;
+       do
+       {
+               alive_sleep(1);
+               timeout--;
+               target_read_u32(target, F_STAT, &status);
+       } while (((status & FS_DONE) == 0) && timeout);
+
+       if (timeout == 0)
+       {
+               LOG_DEBUG("Timedout!");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       return ERROR_OK;
+}
+
+/* Read device id register and fill in driver info structure */
+static int lpc288x_read_part_info(struct flash_bank *bank)
+{
+       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t cidr;
+
+       int i = 0;
+       uint32_t offset;
+
+       if (lpc288x_info->cidr == 0x0102100A)
+               return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */
+
+       /* Read and parse chip identification register */
+       target_read_u32(target, DBGU_CIDR, &cidr);
+
+       if (cidr != 0x0102100A)
+       {
+               LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")",cidr);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       lpc288x_info->cidr = cidr;
+       lpc288x_info->sector_size_break = 0x000F0000;
+       lpc288x_info->target_name = "LPC288x";
+
+       /* setup the sector info... */
+       offset = bank->base;
+       bank->num_sectors = 23;
+       bank->sectors = malloc(sizeof(struct flash_sector) * 23);
+
+       for (i = 0; i < 15; i++)
+       {
+               bank->sectors[i].offset = offset;
+               bank->sectors[i].size = 64 * 1024;
+               offset += bank->sectors[i].size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 1;
+       }
+       for (i = 15; i < 23; i++)
+       {
+               bank->sectors[i].offset = offset;
+               bank->sectors[i].size = 8 * 1024;
+               offset += bank->sectors[i].size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int lpc288x_protect_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+/* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
+FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
+{
+       struct lpc288x_flash_bank *lpc288x_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank LPC288x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
+       bank->driver_priv = lpc288x_info;
+
+       /* part wasn't probed for info yet */
+       lpc288x_info->cidr = 0;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk);
+
+       return ERROR_OK;
+}
+
+/* The frequency is the AHB clock frequency divided by (CLK_DIV Ã—3) + 1.
+ * This must be programmed such that the Flash Programming clock frequency is 66 kHz Â± 20%.
+ * AHB = 12 MHz ?
+ * 12000000/66000 = 182
+ * CLK_DIV = 60 ? */
+static void lpc288x_set_flash_clk(struct flash_bank *bank)
+{
+       uint32_t clk_time;
+       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
+       clk_time = (lpc288x_info->cclk / 66000) / 3;
+       target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN);
+       target_write_u32(bank->target, F_CLK_TIME, clk_time);
+}
+
+/* AHB tcyc (in ns) 83 ns
+ * LOAD_TIMER_ERASE            FPT_TIME        = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512
+ *                                                                     = 9412 (9500) (AN10548 9375)
+ * LOAD_TIMER_WRITE            FPT_TIME        = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512
+ *                                                                     = 23 (75) (AN10548 72 - is this wrong?)
+ * TODO: Sort out timing calcs ;) */
+static void lpc288x_load_timer(int erase, struct target *target)
+{
+       if (erase == LOAD_TIMER_ERASE)
+       {
+               target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500);
+       }
+       else
+       {
+               target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75);
+       }
+}
+
+static uint32_t lpc288x_system_ready(struct flash_bank *bank)
+{
+       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
+       if (lpc288x_info->cidr == 0)
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       return ERROR_OK;
+}
+
+static int lpc288x_erase_check(struct flash_bank *bank)
+{
+       uint32_t status = lpc288x_system_ready(bank);   /* probed? halted? */
+       if (status != ERROR_OK)
+       {
+               LOG_INFO("Processor not halted/not probed");
+               return status;
+       }
+
+       return ERROR_OK;
+}
+
+static int lpc288x_erase(struct flash_bank *bank, int first, int last)
+{
+       uint32_t status;
+       int sector;
+       struct target *target = bank->target;
+
+       status = lpc288x_system_ready(bank);    /* probed? halted? */
+       if (status != ERROR_OK)
+       {
+               return status;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               LOG_INFO("Bad sector range");
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* Configure the flash controller timing */
+       lpc288x_set_flash_clk(bank);
+
+       for (sector = first; sector <= last; sector++)
+       {
+               if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               lpc288x_load_timer(LOAD_TIMER_ERASE,target);
+
+               target_write_u32(target, bank->sectors[sector].offset, 0x00);
+
+               target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS);
+       }
+       if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       return ERROR_OK;
+}
+
+static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       uint8_t page_buffer[FLASH_PAGE_SIZE];
+       uint32_t status, source_offset,dest_offset;
+       struct target *target = bank->target;
+       uint32_t bytes_remaining = count;
+       uint32_t first_sector, last_sector, sector, page;
+       int i;
+
+       /* probed? halted? */
+       status = lpc288x_system_ready(bank);
+       if (status != ERROR_OK)
+       {
+               return status;
+       }
+
+       /* Initialise search indices */
+       first_sector = last_sector = 0xffffffff;
+
+       /* validate the write range... */
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               if ((offset >= bank->sectors[i].offset) &&
+                       (offset < (bank->sectors[i].offset + bank->sectors[i].size)) &&
+                       (first_sector == 0xffffffff))
+               {
+                       first_sector = i;
+                       /* all writes must start on a sector boundary... */
+                       if (offset % bank->sectors[i].size)
+                       {
+                               LOG_INFO("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size);
+                               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+                       }
+               }
+               if (((offset + count) > bank->sectors[i].offset) &&
+                       ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) &&
+                       (last_sector == 0xffffffff))
+               {
+                       last_sector = i;
+               }
+       }
+
+       /* Range check... */
+       if (first_sector == 0xffffffff || last_sector == 0xffffffff)
+       {
+               LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count);
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+       }
+
+       /* Configure the flash controller timing */
+       lpc288x_set_flash_clk(bank);
+
+       /* initialise the offsets */
+       source_offset = 0;
+       dest_offset = 0;
+
+       for (sector = first_sector; sector <= last_sector; sector++)
+       {
+               for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++)
+               {
+                       if (bytes_remaining == 0)
+                       {
+                               count = 0;
+                               memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
+                       }
+                       else if (bytes_remaining < FLASH_PAGE_SIZE)
+                       {
+                               count = bytes_remaining;
+                               memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
+                               memcpy(page_buffer, &buffer[source_offset], count);
+                       }
+                       else
+                       {
+                               count = FLASH_PAGE_SIZE;
+                               memcpy(page_buffer, &buffer[source_offset], count);
+                       }
+
+                       /* Wait for flash to become ready */
+                       if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
+                       {
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+
+                       /* fill flash data latches with 1's */
+                       target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC);
+
+                       target_write_u32(target, F_CTRL, FC_CS | FC_WEN | FC_FUNC);
+                       /*would be better to use the clean target_write_buffer() interface but
+                        * it seems not to be a LOT slower....
+                        * bulk_write_memory() is no quicker :(*/
+#if 1
+                       if (target_write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK)
+                       {
+                               LOG_ERROR("Write failed s %" PRIx32 " p %" PRIx32 "", sector, page);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+#else
+                       if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK)
+                       {
+                               LOG_INFO("Write to flash buffer failed");
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+#endif
+                       dest_offset += FLASH_PAGE_SIZE;
+                       source_offset += count;
+                       bytes_remaining -= count;
+
+                       lpc288x_load_timer(LOAD_TIMER_WRITE, target);
+
+                       target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC | FC_CS);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int lpc288x_probe(struct flash_bank *bank)
+{
+       /* we only deal with LPC2888 so flash config is fixed */
+       struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
+       int retval;
+
+       if (lpc288x_info->cidr != 0)
+       {
+               return ERROR_OK; /* already probed */
+       }
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       retval = lpc288x_read_part_info(bank);
+       if (retval != ERROR_OK)
+               return retval;
+       return ERROR_OK;
+}
+
+static int lpc288x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "lpc288x flash driver");
+       return ERROR_OK;
+}
+
+static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       int lockregion, status;
+       uint32_t value;
+       struct target *target = bank->target;
+
+       /* probed? halted? */
+       status = lpc288x_system_ready(bank);
+       if (status != ERROR_OK)
+       {
+               return status;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* Configure the flash controller timing */
+       lpc288x_set_flash_clk(bank);
+
+       for (lockregion = first; lockregion <= last; lockregion++)
+       {
+               if (set)
+               {
+                       /* write an odd value to base addy to protect... */
+                       value = 0x01;
+               }
+               else
+               {
+                       /* write an even value to base addy to unprotect... */
+                       value = 0x00;
+               }
+               target_write_u32(target, bank->sectors[lockregion].offset, value);
+               target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC | FC_CS);
+       }
+
+       return ERROR_OK;
+}
+
+struct flash_driver lpc288x_flash = {
+               .name = "lpc288x",
+               .flash_bank_command = &lpc288x_flash_bank_command,
+               .erase = &lpc288x_erase,
+               .protect = &lpc288x_protect,
+               .write = &lpc288x_write,
+               .probe = &lpc288x_probe,
+               .auto_probe = &lpc288x_probe,
+               .erase_check = &lpc288x_erase_check,
+               .protect_check = &lpc288x_protect_check,
+               .info = &lpc288x_info,
+       };
diff --git a/src/flash/nor/lpc288x.h b/src/flash/nor/lpc288x.h
new file mode 100644 (file)
index 0000000..5a71ee0
--- /dev/null
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by                                                            *
+ *   Karl RobinSod <karl.robinsod@gmail.com>                               *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#ifndef lpc288x_H
+#define lpc288x_H
+
+#include "flash.h"
+
+struct lpc288x_flash_bank
+{
+       uint32_t working_area;
+       uint32_t working_area_size;
+
+       /* chip id register */
+       uint32_t cidr;
+       char * target_name;
+       uint32_t cclk;
+
+       uint32_t sector_size_break;
+};
+
+#endif /* lpc288x_H */
diff --git a/src/flash/nor/lpc2900.c b/src/flash/nor/lpc2900.c
new file mode 100644 (file)
index 0000000..81e2def
--- /dev/null
@@ -0,0 +1,1834 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by                                                 *
+ *   Rolf Meeser <rolfm_9dq@yahoo.de>                                      *
+ *                                                                         *
+ *   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 "image.h"
+#include "flash.h"
+#include "binarybuffer.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+
+
+/* 1024 bytes */
+#define KiB                 1024
+
+/* Some flash constants */
+#define FLASH_PAGE_SIZE     512     /* bytes */
+#define FLASH_ERASE_TIME    100000  /* microseconds */
+#define FLASH_PROGRAM_TIME  1000    /* microseconds */
+
+/* Chip ID / Feature Registers */
+#define CHIPID          0xE0000000  /* Chip ID */
+#define FEAT0           0xE0000100  /* Chip feature 0 */
+#define FEAT1           0xE0000104  /* Chip feature 1 */
+#define FEAT2           0xE0000108  /* Chip feature 2 (contains flash size indicator) */
+#define FEAT3           0xE000010C  /* Chip feature 3 */
+
+#define EXPECTED_CHIPID 0x209CE02B  /* Chip ID of all LPC2900 devices */
+
+/* Flash/EEPROM Control Registers */
+#define FCTR            0x20200000  /* Flash control */
+#define FPTR            0x20200008  /* Flash program-time */
+#define FTCTR           0x2020000C  /* Flash test control */
+#define FBWST           0x20200010  /* Flash bridge wait-state */
+#define FCRA            0x2020001C  /* Flash clock divider */
+#define FMSSTART        0x20200020  /* Flash Built-In Selft Test start address */
+#define FMSSTOP         0x20200024  /* Flash Built-In Selft Test stop address */
+#define FMS16           0x20200028  /* Flash 16-bit signature */
+#define FMSW0           0x2020002C  /* Flash 128-bit signature Word 0 */
+#define FMSW1           0x20200030  /* Flash 128-bit signature Word 1 */
+#define FMSW2           0x20200034  /* Flash 128-bit signature Word 2 */
+#define FMSW3           0x20200038  /* Flash 128-bit signature Word 3 */
+
+#define EECMD           0x20200080  /* EEPROM command */
+#define EEADDR          0x20200084  /* EEPROM address */
+#define EEWDATA         0x20200088  /* EEPROM write data */
+#define EERDATA         0x2020008C  /* EEPROM read data */
+#define EEWSTATE        0x20200090  /* EEPROM wait state */
+#define EECLKDIV        0x20200094  /* EEPROM clock divider */
+#define EEPWRDWN        0x20200098  /* EEPROM power-down/start */
+#define EEMSSTART       0x2020009C  /* EEPROM BIST start address */
+#define EEMSSTOP        0x202000A0  /* EEPROM BIST stop address */
+#define EEMSSIG         0x202000A4  /* EEPROM 24-bit BIST signature */
+
+#define INT_CLR_ENABLE  0x20200FD8  /* Flash/EEPROM interrupt clear enable */
+#define INT_SET_ENABLE  0x20200FDC  /* Flash/EEPROM interrupt set enable */
+#define INT_STATUS      0x20200FE0  /* Flash/EEPROM interrupt status */
+#define INT_ENABLE      0x20200FE4  /* Flash/EEPROM interrupt enable */
+#define INT_CLR_STATUS  0x20200FE8  /* Flash/EEPROM interrupt clear status */
+#define INT_SET_STATUS  0x20200FEC  /* Flash/EEPROM interrupt set status */
+
+/* Interrupt sources */
+#define INTSRC_END_OF_PROG    (1 << 28)
+#define INTSRC_END_OF_BIST    (1 << 27)
+#define INTSRC_END_OF_RDWR    (1 << 26)
+#define INTSRC_END_OF_MISR    (1 << 2)
+#define INTSRC_END_OF_BURN    (1 << 1)
+#define INTSRC_END_OF_ERASE   (1 << 0)
+
+
+/* FCTR bits */
+#define FCTR_FS_LOADREQ       (1 << 15)
+#define FCTR_FS_CACHECLR      (1 << 14)
+#define FCTR_FS_CACHEBYP      (1 << 13)
+#define FCTR_FS_PROGREQ       (1 << 12)
+#define FCTR_FS_RLS           (1 << 11)
+#define FCTR_FS_PDL           (1 << 10)
+#define FCTR_FS_PD            (1 << 9)
+#define FCTR_FS_WPB           (1 << 7)
+#define FCTR_FS_ISS           (1 << 6)
+#define FCTR_FS_RLD           (1 << 5)
+#define FCTR_FS_DCR           (1 << 4)
+#define FCTR_FS_WEB           (1 << 2)
+#define FCTR_FS_WRE           (1 << 1)
+#define FCTR_FS_CS            (1 << 0)
+/* FPTR bits */
+#define FPTR_EN_T             (1 << 15)
+/* FTCTR bits */
+#define FTCTR_FS_BYPASS_R     (1 << 29)
+#define FTCTR_FS_BYPASS_W     (1 << 28)
+/* FMSSTOP bits */
+#define FMSSTOP_MISR_START    (1 << 17)
+/* EEMSSTOP bits */
+#define EEMSSTOP_STRTBIST     (1 << 31)
+
+/* Index sector */
+#define ISS_CUSTOMER_START1   (0x830)
+#define ISS_CUSTOMER_END1     (0xA00)
+#define ISS_CUSTOMER_SIZE1    (ISS_CUSTOMER_END1 - ISS_CUSTOMER_START1)
+#define ISS_CUSTOMER_NWORDS1  (ISS_CUSTOMER_SIZE1 / 4)
+#define ISS_CUSTOMER_START2   (0xA40)
+#define ISS_CUSTOMER_END2     (0xC00)
+#define ISS_CUSTOMER_SIZE2    (ISS_CUSTOMER_END2 - ISS_CUSTOMER_START2)
+#define ISS_CUSTOMER_NWORDS2  (ISS_CUSTOMER_SIZE2 / 4)
+#define ISS_CUSTOMER_SIZE     (ISS_CUSTOMER_SIZE1 + ISS_CUSTOMER_SIZE2)
+
+
+
+/**
+ * Private data for \c lpc2900 flash driver.
+ */
+struct lpc2900_flash_bank
+{
+       /**
+        * Holds the value read from CHIPID register.
+        * The driver will not load if the chipid doesn't match the expected
+        * value of 0x209CE02B of the LPC2900 family. A probe will only be done
+        * if the chipid does not yet contain the expected value.
+        */
+       uint32_t chipid;
+
+       /**
+        * String holding device name.
+        * This string is set by the probe function to the type number of the
+        * device. It takes the form "LPC29xx".
+        */
+       char * target_name;
+
+       /**
+        * System clock frequency.
+        * Holds the clock frequency in Hz, as passed by the configuration file
+        * to the <tt>flash bank</tt> command.
+        */
+       uint32_t clk_sys_fmc;
+
+       /**
+        * Flag to indicate that dangerous operations are possible.
+        * This flag can be set by passing the correct password to the
+        * <tt>lpc2900 password</tt> command. If set, other dangerous commands,
+        * which operate on the index sector, can be executed.
+        */
+       uint32_t risky;
+
+       /**
+        * Maximum contiguous block of internal SRAM (bytes).
+        * Autodetected by the driver. Not the total amount of SRAM, only the
+        * the largest \em contiguous block!
+        */
+       uint32_t max_ram_block;
+
+};
+
+
+static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout);
+static void lpc2900_setup(struct flash_bank *bank);
+static uint32_t lpc2900_is_ready(struct flash_bank *bank);
+static uint32_t lpc2900_read_security_status(struct flash_bank *bank);
+static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
+                                    uint32_t addr_from, uint32_t addr_to,
+                                    uint32_t (*signature)[4] );
+static uint32_t lpc2900_address2sector(struct flash_bank *bank, uint32_t offset);
+static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time );
+
+
+/***********************  Helper functions  **************************/
+
+
+/**
+ * Wait for an event in mask to occur in INT_STATUS.
+ *
+ * Return when an event occurs, or after a timeout.
+ *
+ * @param[in] bank Pointer to the flash bank descriptor
+ * @param[in] mask Mask to be used for INT_STATUS
+ * @param[in] timeout Timeout in ms
+ */
+static uint32_t lpc2900_wait_status( struct flash_bank *bank,
+                                     uint32_t mask,
+                                     int timeout )
+{
+       uint32_t int_status;
+       struct target *target = bank->target;
+
+
+       do
+       {
+               alive_sleep(1);
+               timeout--;
+               target_read_u32(target, INT_STATUS, &int_status);
+       }
+       while( ((int_status & mask) == 0) && (timeout != 0) );
+
+       if (timeout == 0)
+       {
+               LOG_DEBUG("Timeout!");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+
+
+/**
+ * Set up the flash for erase/program operations.
+ *
+ * Enable the flash, and set the correct CRA clock of 66 kHz.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ */
+static void lpc2900_setup( struct flash_bank *bank )
+{
+       uint32_t fcra;
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+
+       /* Power up the flash block */
+       target_write_u32( bank->target, FCTR, FCTR_FS_WEB | FCTR_FS_CS );
+
+
+       fcra = (lpc2900_info->clk_sys_fmc / (3 * 66000)) - 1;
+       target_write_u32( bank->target, FCRA, fcra );
+}
+
+
+
+/**
+ * Check if device is ready.
+ *
+ * Check if device is ready for flash operation:
+ * Must have been successfully probed.
+ * Must be halted.
+ */
+static uint32_t lpc2900_is_ready( struct flash_bank *bank )
+{
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+       if( lpc2900_info->chipid != EXPECTED_CHIPID )
+       {
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if( bank->target->state != TARGET_HALTED )
+       {
+               LOG_ERROR( "Target not halted" );
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Read the status of sector security from the index sector.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ */
+static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
+{
+       uint32_t status;
+       if( (status = lpc2900_is_ready( bank )) != ERROR_OK )
+       {
+               return status;
+       }
+
+       struct target *target = bank->target;
+
+       /* Enable ISS access */
+       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS);
+
+       /* Read the relevant block of memory from the ISS sector */
+       uint32_t iss_secured_field[ 0x230/16 ][ 4 ];
+       target_read_memory(target, bank->base + 0xC00, 4, 0x230/4,
+                                  (uint8_t *)iss_secured_field);
+
+       /* Disable ISS access */
+       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
+
+       /* Check status of each sector. Note that the sector numbering in the LPC2900
+        * is different from the logical sector numbers used in OpenOCD!
+        * Refer to the user manual for details.
+        *
+        * All zeros (16x 0x00) are treated as a secured sector (is_protected = 1)
+        * All ones (16x 0xFF) are treated as a non-secured sector (is_protected = 0)
+        * Anything else is undefined (is_protected = -1). This is treated as
+        * a protected sector!
+        */
+       int sector;
+       int index;
+       for( sector = 0; sector < bank->num_sectors; sector++ )
+       {
+               /* Convert logical sector number to physical sector number */
+               if( sector <= 4 )
+               {
+                       index = sector + 11;
+               }
+               else if( sector <= 7 )
+               {
+                       index = sector + 27;
+               }
+               else
+               {
+                       index = sector - 8;
+               }
+
+               bank->sectors[sector].is_protected = -1;
+
+               if (
+                   (iss_secured_field[index][0] == 0x00000000) &&
+                   (iss_secured_field[index][1] == 0x00000000) &&
+                   (iss_secured_field[index][2] == 0x00000000) &&
+                   (iss_secured_field[index][3] == 0x00000000) )
+               {
+                       bank->sectors[sector].is_protected = 1;
+               }
+
+               if (
+                   (iss_secured_field[index][0] == 0xFFFFFFFF) &&
+                   (iss_secured_field[index][1] == 0xFFFFFFFF) &&
+                   (iss_secured_field[index][2] == 0xFFFFFFFF) &&
+                   (iss_secured_field[index][3] == 0xFFFFFFFF) )
+               {
+                       bank->sectors[sector].is_protected = 0;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Use BIST to calculate a 128-bit hash value over a range of flash.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ * @param addr_from
+ * @param addr_to
+ * @param signature
+ */
+static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
+                                    uint32_t addr_from,
+                                    uint32_t addr_to,
+                                    uint32_t (*signature)[4] )
+{
+       struct target *target = bank->target;
+
+       /* Clear END_OF_MISR interrupt status */
+       target_write_u32( target, INT_CLR_STATUS, INTSRC_END_OF_MISR );
+
+       /* Start address */
+       target_write_u32( target, FMSSTART, addr_from >> 4);
+       /* End address, and issue start command */
+       target_write_u32( target, FMSSTOP, (addr_to >> 4) | FMSSTOP_MISR_START );
+
+       /* Poll for end of operation. Calculate a reasonable timeout. */
+       if( lpc2900_wait_status( bank, INTSRC_END_OF_MISR, 1000 ) != ERROR_OK )
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Return the signature */
+       target_read_memory( target, FMSW0, 4, 4, (uint8_t *)signature );
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Return sector number for given address.
+ *
+ * Return the (logical) sector number for a given relative address.
+ * No sanity check is done. It assumed that the address is valid.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ * @param offset Offset address relative to bank start
+ */
+static uint32_t lpc2900_address2sector( struct flash_bank *bank,
+                                        uint32_t offset )
+{
+       uint32_t address = bank->base + offset;
+
+
+       /* Run through all sectors of this bank */
+       int sector;
+       for( sector = 0; sector < bank->num_sectors; sector++ )
+       {
+               /* Return immediately if address is within the current sector */
+               if( address < (bank->sectors[sector].offset + bank->sectors[sector].size) )
+               {
+                       return sector;
+               }
+       }
+
+       /* We should never come here. If we do, return an arbitrary sector number. */
+       return 0;
+}
+
+
+
+
+/**
+ * Write one page to the index sector.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ * @param pagenum Page number (0...7)
+ * @param page Page array (FLASH_PAGE_SIZE bytes)
+ */
+static int lpc2900_write_index_page( struct flash_bank *bank,
+                                     int pagenum,
+                                     uint8_t (*page)[FLASH_PAGE_SIZE] )
+{
+       /* Only pages 4...7 are user writable */
+       if ((pagenum < 4) || (pagenum > 7))
+       {
+               LOG_ERROR("Refuse to burn index sector page %d", pagenum);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       /* Get target, and check if it's halted */
+       struct target *target = bank->target;
+       if( target->state != TARGET_HALTED )
+       {
+               LOG_ERROR( "Target not halted" );
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Private info */
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+       /* Enable flash block and set the correct CRA clock of 66 kHz */
+       lpc2900_setup( bank );
+
+       /* Un-protect the index sector */
+       target_write_u32( target, bank->base, 0 );
+       target_write_u32( target, FCTR,
+                         FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_ISS |
+                         FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS );
+
+       /* Set latch load mode */
+       target_write_u32( target, FCTR,
+                         FCTR_FS_ISS | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS );
+
+       /* Write whole page to flash data latches */
+       if( target_write_memory( target,
+                                bank->base + pagenum * FLASH_PAGE_SIZE,
+                                4, FLASH_PAGE_SIZE / 4, (uint8_t *)page) != ERROR_OK )
+       {
+               LOG_ERROR("Index sector write failed @ page %d", pagenum);
+               target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
+
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Clear END_OF_BURN interrupt status */
+       target_write_u32( target, INT_CLR_STATUS, INTSRC_END_OF_BURN );
+
+       /* Set the program/erase time to FLASH_PROGRAM_TIME */
+       target_write_u32(target, FPTR,
+                        FPTR_EN_T | lpc2900_calc_tr( lpc2900_info->clk_sys_fmc,
+                                                     FLASH_PROGRAM_TIME ));
+
+       /* Trigger flash write */
+       target_write_u32( target, FCTR,
+                         FCTR_FS_PROGREQ | FCTR_FS_ISS |
+                         FCTR_FS_WPB | FCTR_FS_WRE | FCTR_FS_CS );
+
+       /* Wait for the end of the write operation. If it's not over after one
+        * second, something went dreadfully wrong... :-(
+        */
+       if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK)
+       {
+               LOG_ERROR("Index sector write failed @ page %d", pagenum);
+               target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
+
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
+
+       return ERROR_OK;
+}
+
+
+
+/**
+ * Calculate FPTR.TR register value for desired program/erase time.
+ *
+ * @param clock System clock in Hz
+ * @param time Program/erase time in Âµs
+ */
+static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time )
+{
+       /*           ((time[µs]/1e6) * f[Hz]) + 511
+        * FPTR.TR = -------------------------------
+        *                         512
+        *
+        * The result is the
+        */
+
+       uint32_t tr_val = (uint32_t)((((time / 1e6) * clock) + 511.0) / 512.0);
+
+       return tr_val;
+}
+
+
+/***********************  Private flash commands  **************************/
+
+
+/**
+ * Command to determine the signature of the whole flash.
+ *
+ * Uses the Built-In-Self-Test (BIST) to generate a 128-bit hash value
+ * of the flash content.
+ */
+COMMAND_HANDLER(lpc2900_handle_signature_command)
+{
+       uint32_t status;
+       uint32_t signature[4];
+
+
+       if( CMD_ARGC < 1 )
+       {
+               LOG_WARNING( "Too few arguments. Call: lpc2900 signature <bank#>" );
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if( bank->target->state != TARGET_HALTED )
+       {
+               LOG_ERROR( "Target not halted" );
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Run BIST over whole flash range */
+       if( (status = lpc2900_run_bist128( bank,
+                                          bank->base,
+                                          bank->base + (bank->size - 1),
+                                          &signature)
+                                        ) != ERROR_OK )
+       {
+               return status;
+       }
+
+       command_print( CMD_CTX, "signature: 0x%8.8" PRIx32
+                                         ":0x%8.8" PRIx32
+                                         ":0x%8.8" PRIx32
+                                         ":0x%8.8" PRIx32,
+                     signature[3], signature[2], signature[1], signature[0] );
+
+       return ERROR_OK;
+}
+
+
+
+/**
+ * Store customer info in file.
+ *
+ * Read customer info from index sector, and store that block of data into
+ * a disk file. The format is binary.
+ */
+COMMAND_HANDLER(lpc2900_handle_read_custom_command)
+{
+       if( CMD_ARGC < 2 )
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+       lpc2900_info->risky = 0;
+
+       /* Get target, and check if it's halted */
+       struct target *target = bank->target;
+       if( target->state != TARGET_HALTED )
+       {
+               LOG_ERROR( "Target not halted" );
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Storage for customer info. Read in two parts */
+       uint32_t customer[ ISS_CUSTOMER_NWORDS1 + ISS_CUSTOMER_NWORDS2 ];
+
+       /* Enable access to index sector */
+       target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS );
+
+       /* Read two parts */
+       target_read_memory( target, bank->base+ISS_CUSTOMER_START1, 4,
+                                   ISS_CUSTOMER_NWORDS1,
+                                   (uint8_t *)&customer[0] );
+       target_read_memory( target, bank->base+ISS_CUSTOMER_START2, 4,
+                                   ISS_CUSTOMER_NWORDS2,
+                                   (uint8_t *)&customer[ISS_CUSTOMER_NWORDS1] );
+
+       /* Deactivate access to index sector */
+       target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
+
+       /* Try and open the file */
+       struct fileio fileio;
+       const char *filename = CMD_ARGV[1];
+       int ret = fileio_open( &fileio, filename, FILEIO_WRITE, FILEIO_BINARY );
+       if( ret != ERROR_OK )
+       {
+               LOG_WARNING( "Could not open file %s", filename );
+               return ret;
+       }
+
+       size_t nwritten;
+       ret = fileio_write( &fileio, sizeof(customer),
+                        (const uint8_t *)customer, &nwritten );
+       if( ret != ERROR_OK )
+       {
+               LOG_ERROR( "Write operation to file %s failed", filename );
+               fileio_close( &fileio );
+               return ret;
+       }
+
+       fileio_close( &fileio );
+
+       return ERROR_OK;
+}
+
+
+
+
+/**
+ * Enter password to enable potentially dangerous options.
+ */
+COMMAND_HANDLER(lpc2900_handle_password_command)
+{
+       if (CMD_ARGC < 2)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+#define ISS_PASSWORD "I_know_what_I_am_doing"
+
+       lpc2900_info->risky = !strcmp( CMD_ARGV[1], ISS_PASSWORD );
+
+       if( !lpc2900_info->risky )
+       {
+               command_print(CMD_CTX, "Wrong password (use '%s')", ISS_PASSWORD);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       command_print(CMD_CTX,
+                  "Potentially dangerous operation allowed in next command!");
+
+       return ERROR_OK;
+}
+
+
+
+/**
+ * Write customer info from file to the index sector.
+ */
+COMMAND_HANDLER(lpc2900_handle_write_custom_command)
+{
+       if (CMD_ARGC < 2)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+       /* Check if command execution is allowed. */
+       if( !lpc2900_info->risky )
+       {
+               command_print( CMD_CTX, "Command execution not allowed!" );
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+       lpc2900_info->risky = 0;
+
+       /* Get target, and check if it's halted */
+       struct target *target = bank->target;
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* The image will always start at offset 0 */
+       struct image image;
+       image.base_address_set = 1;
+       image.base_address = 0;
+       image.start_address_set = 0;
+
+       const char *filename = CMD_ARGV[1];
+       const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL;
+       retval = image_open(&image, filename, type);
+       if (retval != ERROR_OK)
+       {
+               return retval;
+       }
+
+       /* Do a sanity check: The image must be exactly the size of the customer
+          programmable area. Any other size is rejected. */
+       if( image.num_sections != 1 )
+       {
+               LOG_ERROR("Only one section allowed in image file.");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       if( (image.sections[0].base_address != 0) ||
+        (image.sections[0].size != ISS_CUSTOMER_SIZE) )
+       {
+               LOG_ERROR("Incorrect image file size. Expected %d, "
+                       "got %" PRIu32,
+                   ISS_CUSTOMER_SIZE, image.sections[0].size);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       /* Well boys, I reckon this is it... */
+
+       /* Customer info is split into two blocks in pages 4 and 5. */
+       uint8_t page[FLASH_PAGE_SIZE];
+
+       /* Page 4 */
+       uint32_t offset = ISS_CUSTOMER_START1 % FLASH_PAGE_SIZE;
+       memset( page, 0xff, FLASH_PAGE_SIZE );
+       size_t size_read;
+       retval = image_read_section( &image, 0, 0,
+                                    ISS_CUSTOMER_SIZE1, &page[offset], &size_read);
+       if( retval != ERROR_OK )
+       {
+               LOG_ERROR("couldn't read from file '%s'", filename);
+               image_close(&image);
+               return retval;
+       }
+       if( (retval = lpc2900_write_index_page( bank, 4, &page )) != ERROR_OK )
+       {
+               image_close(&image);
+               return retval;
+       }
+
+       /* Page 5 */
+       offset = ISS_CUSTOMER_START2 % FLASH_PAGE_SIZE;
+       memset( page, 0xff, FLASH_PAGE_SIZE );
+       retval = image_read_section( &image, 0, ISS_CUSTOMER_SIZE1,
+                                    ISS_CUSTOMER_SIZE2, &page[offset], &size_read);
+       if( retval != ERROR_OK )
+       {
+               LOG_ERROR("couldn't read from file '%s'", filename);
+               image_close(&image);
+               return retval;
+       }
+       if( (retval = lpc2900_write_index_page( bank, 5, &page )) != ERROR_OK )
+       {
+               image_close(&image);
+               return retval;
+       }
+
+       image_close(&image);
+
+       return ERROR_OK;
+}
+
+
+
+/**
+ * Activate 'sector security' for a range of sectors.
+ */
+COMMAND_HANDLER(lpc2900_handle_secure_sector_command)
+{
+       if (CMD_ARGC < 3)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       /* Get the bank descriptor */
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+       /* Check if command execution is allowed. */
+       if( !lpc2900_info->risky )
+       {
+               command_print( CMD_CTX, "Command execution not allowed! "
+               "(use 'password' command first)");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+       lpc2900_info->risky = 0;
+
+       /* Read sector range, and do a sanity check. */
+       int first, last;
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
+       if( (first >= bank->num_sectors) ||
+           (last >= bank->num_sectors) ||
+           (first > last) )
+       {
+               command_print( CMD_CTX, "Illegal sector range" );
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       uint8_t page[FLASH_PAGE_SIZE];
+       int sector;
+
+       /* Sectors in page 6 */
+       if( (first <= 4) || (last >= 8) )
+       {
+               memset( &page, 0xff, FLASH_PAGE_SIZE );
+               for( sector = first; sector <= last; sector++ )
+               {
+                       if( sector <= 4 )
+                       {
+                               memset( &page[0xB0 + 16*sector], 0, 16 );
+                       }
+                       else if( sector >= 8 )
+                       {
+                               memset( &page[0x00 + 16*(sector - 8)], 0, 16 );
+                       }
+               }
+
+               if( (retval = lpc2900_write_index_page( bank, 6, &page )) != ERROR_OK )
+               {
+                       LOG_ERROR("failed to update index sector page 6");
+                       return retval;
+               }
+       }
+
+       /* Sectors in page 7 */
+       if( (first <= 7) && (last >= 5) )
+       {
+               memset( &page, 0xff, FLASH_PAGE_SIZE );
+               for( sector = first; sector <= last; sector++ )
+               {
+                       if( (sector >= 5) && (sector <= 7) )
+                       {
+                               memset( &page[0x00 + 16*(sector - 5)], 0, 16 );
+                       }
+               }
+
+               if( (retval = lpc2900_write_index_page( bank, 7, &page )) != ERROR_OK )
+               {
+                       LOG_ERROR("failed to update index sector page 7");
+                       return retval;
+               }
+       }
+
+       command_print( CMD_CTX,
+               "Sectors security will become effective after next power cycle");
+
+       /* Update the sector security status */
+       if ( lpc2900_read_security_status(bank) != ERROR_OK )
+       {
+               LOG_ERROR( "Cannot determine sector security status" );
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+
+
+/**
+ * Activate JTAG protection.
+ */
+COMMAND_HANDLER(lpc2900_handle_secure_jtag_command)
+{
+       if (CMD_ARGC < 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       /* Get the bank descriptor */
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+       /* Check if command execution is allowed. */
+       if( !lpc2900_info->risky )
+       {
+               command_print( CMD_CTX, "Command execution not allowed! "
+                                       "(use 'password' command first)");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+       lpc2900_info->risky = 0;
+
+       /* Prepare page */
+       uint8_t page[FLASH_PAGE_SIZE];
+       memset( &page, 0xff, FLASH_PAGE_SIZE );
+
+
+       /* Insert "soft" protection word */
+       page[0x30 + 15] = 0x7F;
+       page[0x30 + 11] = 0x7F;
+       page[0x30 +  7] = 0x7F;
+       page[0x30 +  3] = 0x7F;
+
+       /* Write to page 5 */
+       if( (retval = lpc2900_write_index_page( bank, 5, &page ))
+                       != ERROR_OK )
+       {
+               LOG_ERROR("failed to update index sector page 5");
+               return retval;
+       }
+
+       LOG_INFO("JTAG security set. Good bye!");
+
+       return ERROR_OK;
+}
+
+
+
+/***********************  Flash interface functions  **************************/
+
+static const struct command_registration lpc2900_exec_command_handlers[] = {
+       {
+               .name = "signature",
+               .handler = &lpc2900_handle_signature_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank>",
+               .help = "print device signature of flash bank",
+       },
+       {
+               .name = "read_custom",
+               .handler = &lpc2900_handle_read_custom_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank> <filename>",
+               .help = "read customer information from index sector to file",
+       },
+       {
+               .name = "password",
+               .handler = &lpc2900_handle_password_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank> <password>",
+               .help = "enter password to enable 'dangerous' options",
+       },
+       {
+               .name = "write_custom",
+               .handler = &lpc2900_handle_write_custom_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank> <filename> [<type>]",
+               .help = "write customer info from file to index sector",
+       },
+       {
+               .name = "secure_sector",
+               .handler = &lpc2900_handle_secure_sector_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank> <first> <last>",
+               .help = "activate sector security for a range of sectors",
+       },
+       {
+               .name = "secure_jtag",
+               .handler = &lpc2900_handle_secure_jtag_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank> <level>",
+               .help = "activate JTAG security",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration lpc2900_command_handlers[] = {
+       {
+               .name = "lpc2900",
+               .mode = COMMAND_ANY,
+               .help = "LPC2900 flash command group",
+               .chain = lpc2900_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+/// Evaluate flash bank command.
+FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
+{
+       struct lpc2900_flash_bank *lpc2900_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank LPC2900 configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       lpc2900_info = malloc(sizeof(struct lpc2900_flash_bank));
+       bank->driver_priv = lpc2900_info;
+
+       /* Get flash clock.
+        * Reject it if we can't meet the requirements for program time
+        * (if clock too slow), or for erase time (clock too fast).
+        */
+       uint32_t clk_sys_fmc;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], clk_sys_fmc);
+       lpc2900_info->clk_sys_fmc = clk_sys_fmc * 1000;
+
+       uint32_t clock_limit;
+       /* Check program time limit */
+       clock_limit = 512000000l / FLASH_PROGRAM_TIME;
+       if (lpc2900_info->clk_sys_fmc < clock_limit)
+       {
+               LOG_WARNING("flash clock must be at least %" PRIu32 " kHz",
+                    (clock_limit / 1000));
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       /* Check erase time limit */
+       clock_limit = (uint32_t)((32767.0 * 512.0 * 1e6) / FLASH_ERASE_TIME);
+       if (lpc2900_info->clk_sys_fmc > clock_limit)
+       {
+               LOG_WARNING("flash clock must be a maximum of %" PRIu32" kHz",
+                    (clock_limit / 1000));
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       /* Chip ID will be obtained by probing the device later */
+       lpc2900_info->chipid = 0;
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Erase sector(s).
+ *
+ * @param bank Pointer to the flash bank descriptor
+ * @param first First sector to be erased
+ * @param last Last sector (including) to be erased
+ */
+static int lpc2900_erase(struct flash_bank *bank, int first, int last)
+{
+       uint32_t status;
+       int sector;
+       int last_unsecured_sector;
+       struct target *target = bank->target;
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+
+
+       status = lpc2900_is_ready(bank);
+       if (status != ERROR_OK)
+       {
+               return status;
+       }
+
+       /* Sanity check on sector range */
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               LOG_INFO("Bad sector range");
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* Update the info about secured sectors */
+       lpc2900_read_security_status( bank );
+
+       /* The selected sector range might include secured sectors. An attempt
+        * to erase such a sector will cause the erase to fail also for unsecured
+        * sectors. It is necessary to determine the last unsecured sector now,
+        * because we have to treat the last relevant sector in the list in
+        * a special way.
+        */
+       last_unsecured_sector = -1;
+       for (sector = first; sector <= last; sector++)
+       {
+               if ( !bank->sectors[sector].is_protected )
+               {
+                       last_unsecured_sector = sector;
+               }
+       }
+
+       /* Exit now, in case of the rare constellation where all sectors in range
+        * are secured. This is regarded a success, since erasing/programming of
+        * secured sectors shall be handled transparently.
+        */
+       if ( last_unsecured_sector == -1 )
+       {
+               return ERROR_OK;
+       }
+
+       /* Enable flash block and set the correct CRA clock of 66 kHz */
+       lpc2900_setup(bank);
+
+       /* Clear END_OF_ERASE interrupt status */
+       target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_ERASE);
+
+       /* Set the program/erase timer to FLASH_ERASE_TIME */
+       target_write_u32(target, FPTR,
+                        FPTR_EN_T | lpc2900_calc_tr( lpc2900_info->clk_sys_fmc,
+                                                     FLASH_ERASE_TIME ));
+
+       /* Sectors are marked for erasure, then erased all together */
+       for (sector = first; sector <= last_unsecured_sector; sector++)
+       {
+               /* Only mark sectors that aren't secured. Any attempt to erase a group
+                * of sectors will fail if any single one of them is secured!
+                */
+               if ( !bank->sectors[sector].is_protected )
+               {
+                       /* Unprotect the sector */
+                       target_write_u32(target, bank->sectors[sector].offset, 0);
+                       target_write_u32(target, FCTR,
+                                        FCTR_FS_LOADREQ | FCTR_FS_WPB |
+                                        FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS);
+
+                       /* Mark the sector for erasure. The last sector in the list
+                          triggers the erasure. */
+                       target_write_u32(target, bank->sectors[sector].offset, 0);
+                       if ( sector == last_unsecured_sector )
+                       {
+                               target_write_u32(target, FCTR,
+                                                FCTR_FS_PROGREQ | FCTR_FS_WPB | FCTR_FS_CS);
+                       }
+                       else
+                       {
+                               target_write_u32(target, FCTR,
+                                                FCTR_FS_LOADREQ | FCTR_FS_WPB |
+                                                FCTR_FS_WEB | FCTR_FS_CS);
+                       }
+               }
+       }
+
+       /* Wait for the end of the erase operation. If it's not over after two seconds,
+        * something went dreadfully wrong... :-(
+        */
+       if( lpc2900_wait_status(bank, INTSRC_END_OF_ERASE, 2000) != ERROR_OK )
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Normal flash operating mode */
+       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
+
+       return ERROR_OK;
+}
+
+
+
+static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       /* This command is not supported.
+     * "Protection" in LPC2900 terms is handled transparently. Sectors will
+     * automatically be unprotected as needed.
+     * Instead we use the concept of sector security. A secured sector is shown
+     * as "protected" in OpenOCD. Sector security is a permanent feature, and
+     * cannot be disabled once activated.
+     */
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Write data to flash.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ * @param buffer Buffer with data
+ * @param offset Start address (relative to bank start)
+ * @param count Number of bytes to be programmed
+ */
+static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
+                         uint32_t offset, uint32_t count)
+{
+       uint8_t page[FLASH_PAGE_SIZE];
+       uint32_t status;
+       uint32_t num_bytes;
+       struct target *target = bank->target;
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+       int sector;
+       int retval;
+
+       static const uint32_t write_target_code[] = {
+               /* Set auto latch mode: FCTR=CS|WRE|WEB */
+               0xe3a0a007,   /* loop       mov r10, #0x007 */
+               0xe583a000,   /*            str r10,[r3,#0] */
+
+               /* Load complete page into latches */
+               0xe3a06020,   /*            mov r6,#(512/16) */
+               0xe8b00f00,   /* next       ldmia r0!,{r8-r11} */
+               0xe8a10f00,   /*            stmia r1!,{r8-r11} */
+               0xe2566001,   /*            subs r6,#1 */
+               0x1afffffb,   /*            bne next */
+
+               /* Clear END_OF_BURN interrupt status */
+               0xe3a0a002,   /*            mov r10,#(1 << 1) */
+               0xe583afe8,   /*            str r10,[r3,#0xfe8] */
+
+               /* Set the erase time to FLASH_PROGRAM_TIME */
+               0xe5834008,   /*            str r4,[r3,#8] */
+
+               /* Trigger flash write
+                       FCTR = CS | WRE | WPB | PROGREQ */
+               0xe3a0a083,   /*            mov r10,#0x83 */
+               0xe38aaa01,   /*            orr r10,#0x1000 */
+               0xe583a000,   /*            str r10,[r3,#0] */
+
+               /* Wait for end of burn */
+               0xe593afe0,   /* wait       ldr r10,[r3,#0xfe0] */
+               0xe21aa002,   /*            ands r10,#(1 << 1) */
+               0x0afffffc,   /*            beq wait */
+
+               /* End? */
+               0xe2522001,   /*            subs r2,#1 */
+               0x1affffed,   /*            bne loop */
+
+               0xeafffffe    /* done       b done */
+       };
+
+
+       status = lpc2900_is_ready(bank);
+       if (status != ERROR_OK)
+       {
+               return status;
+       }
+
+       /* Enable flash block and set the correct CRA clock of 66 kHz */
+       lpc2900_setup(bank);
+
+       /* Update the info about secured sectors */
+       lpc2900_read_security_status( bank );
+
+       /* Unprotect all involved sectors */
+       for (sector = 0; sector < bank->num_sectors; sector++)
+       {
+               /* Start address in or before this sector? */
+               /* End address in or behind this sector? */
+               if ( ((bank->base + offset) <
+                         (bank->sectors[sector].offset + bank->sectors[sector].size)) &&
+                    ((bank->base + (offset + count - 1)) >= bank->sectors[sector].offset) )
+               {
+                       /* This sector is involved and needs to be unprotected.
+                               * Don't do it for secured sectors.
+                               */
+                       if ( !bank->sectors[sector].is_protected )
+                       {
+                               target_write_u32(target, bank->sectors[sector].offset, 0);
+                               target_write_u32(target, FCTR,
+                                                FCTR_FS_LOADREQ | FCTR_FS_WPB |
+                                                FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS);
+                       }
+               }
+       }
+
+       /* Set the program/erase time to FLASH_PROGRAM_TIME */
+       uint32_t prog_time = FPTR_EN_T | lpc2900_calc_tr( lpc2900_info->clk_sys_fmc,
+                                                         FLASH_PROGRAM_TIME );
+
+       /* If there is a working area of reasonable size, use it to program via
+          a target algorithm. If not, fall back to host programming. */
+
+       /* We need some room for target code. */
+       uint32_t target_code_size = sizeof(write_target_code);
+
+       /* Try working area allocation. Start with a large buffer, and try with
+          reduced size if that fails. */
+       struct working_area *warea;
+       uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
+       while( (retval = target_alloc_working_area(target,
+                                                  buffer_size + target_code_size,
+                                                  &warea)) != ERROR_OK )
+       {
+               /* Try a smaller buffer now, and stop if it's too small. */
+               buffer_size -= 1 * KiB;
+               if (buffer_size < 2 * KiB)
+               {
+                       LOG_INFO( "no (large enough) working area"
+                                 ", falling back to host mode" );
+                       warea = NULL;
+                       break;
+               }
+       };
+
+       if( warea )
+       {
+               struct reg_param reg_params[5];
+               struct armv4_5_algorithm armv4_5_info;
+
+               /* We can use target mode. Download the algorithm. */
+               retval = target_write_buffer( target,
+                                             (warea->address)+buffer_size,
+                                             target_code_size,
+                                             (uint8_t *)write_target_code);
+               if (retval != ERROR_OK)
+               {
+                       LOG_ERROR("Unable to write block write code to target");
+                       target_free_all_working_areas(target);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+               init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+               init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+               init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+               init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
+
+               /* Write to flash in large blocks */
+               while ( count != 0 )
+               {
+                       uint32_t this_npages;
+                       uint8_t *this_buffer;
+                       int start_sector = lpc2900_address2sector( bank, offset );
+
+                       /* First page / last page / rest */
+                       if( offset % FLASH_PAGE_SIZE )
+                       {
+                               /* Block doesn't start on page boundary.
+                                  Burn first partial page separately. */
+                               memset( &page, 0xff, sizeof(page) );
+                               memcpy( &page[offset % FLASH_PAGE_SIZE],
+                                       buffer,
+                                       FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE) );
+                               this_npages = 1;
+                               this_buffer = &page[0];
+                               count = count + (offset % FLASH_PAGE_SIZE);
+                               offset = offset - (offset % FLASH_PAGE_SIZE);
+                       }
+                       else if( count < FLASH_PAGE_SIZE )
+                       {
+                               /* Download last incomplete page separately. */
+                               memset( &page, 0xff, sizeof(page) );
+                               memcpy( &page, buffer, count );
+                               this_npages = 1;
+                               this_buffer = &page[0];
+                               count = FLASH_PAGE_SIZE;
+                       }
+                       else
+                       {
+                               /* Download as many full pages as possible */
+                               this_npages = (count < buffer_size) ?
+                                              count / FLASH_PAGE_SIZE :
+                                              buffer_size / FLASH_PAGE_SIZE;
+                               this_buffer = buffer;
+
+                               /* Make sure we stop at the next secured sector */
+                               int sector = start_sector + 1;
+                               while( sector < bank->num_sectors )
+                               {
+                                       /* Secured? */
+                                       if( bank->sectors[sector].is_protected )
+                                       {
+                                               /* Is that next sector within the current block? */
+                                               if( (bank->sectors[sector].offset - bank->base) <
+                                                       (offset + (this_npages * FLASH_PAGE_SIZE)) )
+                                               {
+                                                       /* Yes! Split the block */
+                                                       this_npages =
+                                                         (bank->sectors[sector].offset - bank->base - offset)
+                                                             / FLASH_PAGE_SIZE;
+                                                       break;
+                                               }
+                                       }
+
+                                       sector++;
+                               }
+                       }
+
+                       /* Skip the current sector if it is secured */
+                       if (bank->sectors[start_sector].is_protected)
+                       {
+                               LOG_DEBUG("Skip secured sector %d",
+                                               start_sector);
+
+                               /* Stop if this is the last sector */
+                               if (start_sector == bank->num_sectors - 1)
+                               {
+                                       break;
+                               }
+
+                               /* Skip */
+                               uint32_t nskip = bank->sectors[start_sector].size -
+                                                (offset % bank->sectors[start_sector].size);
+                               offset += nskip;
+                               buffer += nskip;
+                               count = (count >= nskip) ? (count - nskip) : 0;
+                               continue;
+                       }
+
+                       /* Execute buffer download */
+                       if ((retval = target_write_buffer(target,
+                                                         warea->address,
+                                                         this_npages * FLASH_PAGE_SIZE,
+                                                         this_buffer)) != ERROR_OK)
+                       {
+                               LOG_ERROR("Unable to write data to target");
+                               target_free_all_working_areas(target);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+
+                       /* Prepare registers */
+                       buf_set_u32(reg_params[0].value, 0, 32, warea->address);
+                       buf_set_u32(reg_params[1].value, 0, 32, offset);
+                       buf_set_u32(reg_params[2].value, 0, 32, this_npages);
+                       buf_set_u32(reg_params[3].value, 0, 32, FCTR);
+                       buf_set_u32(reg_params[4].value, 0, 32, FPTR_EN_T | prog_time);
+
+                       /* Execute algorithm, assume breakpoint for last instruction */
+                       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+                       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+                       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+                       retval = target_run_algorithm(target, 0, NULL, 5, reg_params,
+                               (warea->address) + buffer_size,
+                               (warea->address) + buffer_size + target_code_size - 4,
+                               10000, /* 10s should be enough for max. 16 KiB of data */
+                               &armv4_5_info);
+
+                       if (retval != ERROR_OK)
+                       {
+                               LOG_ERROR("Execution of flash algorithm failed.");
+                               target_free_all_working_areas(target);
+                               retval = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+                       }
+
+                       count -= this_npages * FLASH_PAGE_SIZE;
+                       buffer += this_npages * FLASH_PAGE_SIZE;
+                       offset += this_npages * FLASH_PAGE_SIZE;
+               }
+
+               /* Free all resources */
+               destroy_reg_param(&reg_params[0]);
+               destroy_reg_param(&reg_params[1]);
+               destroy_reg_param(&reg_params[2]);
+               destroy_reg_param(&reg_params[3]);
+               destroy_reg_param(&reg_params[4]);
+               target_free_all_working_areas(target);
+       }
+       else
+       {
+               /* Write to flash memory page-wise */
+               while ( count != 0 )
+               {
+                       /* How many bytes do we copy this time? */
+                       num_bytes = (count >= FLASH_PAGE_SIZE) ?
+                                   FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE) :
+                                   count;
+
+                       /* Don't do anything with it if the page is in a secured sector. */
+                       if ( !bank->sectors[lpc2900_address2sector(bank, offset)].is_protected )
+                       {
+                               /* Set latch load mode */
+                               target_write_u32(target, FCTR,
+                                                FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WEB);
+
+                               /* Always clear the buffer (a little overhead, but who cares) */
+                               memset(page, 0xFF, FLASH_PAGE_SIZE);
+
+                               /* Copy them to the buffer */
+                               memcpy( &page[offset % FLASH_PAGE_SIZE],
+                                       &buffer[offset % FLASH_PAGE_SIZE],
+                                       num_bytes );
+
+                               /* Write whole page to flash data latches */
+                               if (target_write_memory(
+                                                target,
+                                                bank->base + (offset - (offset % FLASH_PAGE_SIZE)),
+                                                4, FLASH_PAGE_SIZE / 4, page) != ERROR_OK)
+                               {
+                                       LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset);
+                                       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
+
+                                       return ERROR_FLASH_OPERATION_FAILED;
+                               }
+
+                               /* Clear END_OF_BURN interrupt status */
+                               target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_BURN);
+
+                               /* Set the programming time */
+                               target_write_u32(target, FPTR, FPTR_EN_T | prog_time);
+
+                               /* Trigger flash write */
+                               target_write_u32(target, FCTR,
+                                   FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WPB | FCTR_FS_PROGREQ);
+
+                               /* Wait for the end of the write operation. If it's not over
+                                * after one second, something went dreadfully wrong... :-(
+                                */
+                               if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK)
+                               {
+                                       LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset);
+                                       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
+
+                                       return ERROR_FLASH_OPERATION_FAILED;
+                               }
+                       }
+
+                       /* Update pointers and counters */
+                       offset += num_bytes;
+                       buffer += num_bytes;
+                       count -= num_bytes;
+               }
+
+               retval = ERROR_OK;
+       }
+
+       /* Normal flash operating mode */
+       target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB);
+
+       return retval;
+}
+
+
+/**
+ * Try and identify the device.
+ *
+ * Determine type number and its memory layout.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ */
+static int lpc2900_probe(struct flash_bank *bank)
+{
+       struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
+       struct target *target = bank->target;
+       int i = 0;
+       uint32_t offset;
+
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* We want to do this only once. Check if we already have a valid CHIPID,
+        * because then we will have already successfully probed the device.
+        */
+       if (lpc2900_info->chipid == EXPECTED_CHIPID)
+       {
+               return ERROR_OK;
+       }
+
+       /* Probing starts with reading the CHIPID register. We will continue only
+        * if this identifies as an LPC2900 device.
+        */
+       target_read_u32(target, CHIPID, &lpc2900_info->chipid);
+
+       if (lpc2900_info->chipid != EXPECTED_CHIPID)
+       {
+               LOG_WARNING("Device is not an LPC29xx");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* It's an LPC29xx device. Now read the feature register FEAT0...FEAT3. */
+       uint32_t feat0, feat1, feat2, feat3;
+       target_read_u32(target, FEAT0, &feat0);
+       target_read_u32(target, FEAT1, &feat1);
+       target_read_u32(target, FEAT2, &feat2);
+       target_read_u32(target, FEAT3, &feat3);
+
+       /* Base address */
+       bank->base = 0x20000000;
+
+       /* Determine flash layout from FEAT2 register */
+       uint32_t num_64k_sectors = (feat2 >> 16) & 0xFF;
+       uint32_t num_8k_sectors = (feat2 >> 0) & 0xFF;
+       bank->num_sectors = num_64k_sectors + num_8k_sectors;
+       bank->size = KiB * (64 * num_64k_sectors + 8 * num_8k_sectors);
+
+       /* Determine maximum contiguous RAM block */
+       lpc2900_info->max_ram_block = 16 * KiB;
+       if( (feat1 & 0x30) == 0x30 )
+       {
+               lpc2900_info->max_ram_block = 32 * KiB;
+               if( (feat1 & 0x0C) == 0x0C )
+               {
+                       lpc2900_info->max_ram_block = 48 * KiB;
+               }
+       }
+
+       /* Determine package code and ITCM size */
+       uint32_t package_code = feat0 & 0x0F;
+       uint32_t itcm_code = (feat1 >> 16) & 0x1F;
+
+       /* Determine the exact type number. */
+       uint32_t found = 1;
+       if ( (package_code == 4) && (itcm_code == 5) )
+       {
+               /* Old LPC2917 or LPC2919 (non-/01 devices) */
+               lpc2900_info->target_name = (bank->size == 768*KiB) ? "LPC2919" : "LPC2917";
+       }
+       else
+       {
+               if ( package_code == 2 )
+               {
+                       /* 100-pin package */
+                       if ( bank->size == 128*KiB )
+                       {
+                               lpc2900_info->target_name = "LPC2921";
+                       }
+                       else if ( bank->size == 256*KiB )
+                       {
+                               lpc2900_info->target_name = "LPC2923";
+                       }
+                       else if ( bank->size == 512*KiB )
+                       {
+                               lpc2900_info->target_name = "LPC2925";
+                       }
+                       else
+                       {
+                               found = 0;
+                       }
+               }
+               else if ( package_code == 4 )
+               {
+                       /* 144-pin package */
+                       if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0) )
+                       {
+                               lpc2900_info->target_name = "LPC2917/01";
+                       }
+                       else if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFFF1) )
+                       {
+                               lpc2900_info->target_name = "LPC2927";
+                       }
+                       else if ( (bank->size == 768*KiB) && (feat3 == 0xFFFFFCF8) )
+                       {
+                               lpc2900_info->target_name = "LPC2919/01";
+                       }
+                       else if ( (bank->size == 768*KiB) && (feat3 == 0xFFFFFFF9) )
+                       {
+                               lpc2900_info->target_name = "LPC2929";
+                       }
+                       else
+                       {
+                               found = 0;
+                       }
+               }
+               else if ( package_code == 5 )
+               {
+                       /* 208-pin package */
+                       lpc2900_info->target_name = (bank->size == 0) ? "LPC2930" : "LPC2939";
+               }
+               else
+               {
+                       found = 0;
+               }
+       }
+
+       if ( !found )
+       {
+               LOG_WARNING("Unknown LPC29xx derivative");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Show detected device */
+       LOG_INFO("Flash bank %d"
+                ": Device %s, %" PRIu32
+                " KiB in %d sectors",
+                bank->bank_number,
+                lpc2900_info->target_name, bank->size / KiB,
+                bank->num_sectors);
+
+       /* Flashless devices cannot be handled */
+       if ( bank->num_sectors == 0 )
+       {
+               LOG_WARNING("Flashless device cannot be handled");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Sector layout.
+        * These are logical sector numbers. When doing real flash operations,
+        * the logical flash number are translated into the physical flash numbers
+        * of the device.
+        */
+       bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+
+       offset = 0;
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               bank->sectors[i].offset = offset;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
+
+               if ( i <= 7 )
+               {
+                       bank->sectors[i].size = 8 * KiB;
+               }
+               else if ( i <= 18 )
+               {
+                       bank->sectors[i].size = 64 * KiB;
+               }
+               else
+               {
+                       /* We shouldn't come here. But there might be a new part out there
+                        * that has more than 19 sectors. Politely ask for a fix then.
+                        */
+                       bank->sectors[i].size = 0;
+                       LOG_ERROR("Never heard about sector %d", i);
+               }
+
+               offset += bank->sectors[i].size;
+       }
+
+       /* Read sector security status */
+       if ( lpc2900_read_security_status(bank) != ERROR_OK )
+       {
+               LOG_ERROR("Cannot determine sector security status");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Run a blank check for each sector.
+ *
+ * For speed reasons, the device isn't read word by word.
+ * A hash value is calculated by the hardware ("BIST") for each sector.
+ * This value is then compared against the known hash of an empty sector.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ */
+static int lpc2900_erase_check(struct flash_bank *bank)
+{
+       uint32_t status = lpc2900_is_ready(bank);
+       if (status != ERROR_OK)
+       {
+               LOG_INFO("Processor not halted/not probed");
+               return status;
+       }
+
+       /* Use the BIST (Built-In Selft Test) to generate a signature of each flash
+        * sector. Compare against the expected signature of an empty sector.
+        */
+       int sector;
+       for ( sector = 0; sector < bank->num_sectors; sector++ )
+       {
+               uint32_t signature[4];
+               if ( (status = lpc2900_run_bist128( bank,
+                                                   bank->sectors[sector].offset,
+                                                   bank->sectors[sector].offset +
+                                                      (bank->sectors[sector].size - 1),
+                                                   &signature)) != ERROR_OK )
+               {
+                       return status;
+               }
+
+               /* The expected signatures for an empty sector are different
+                * for 8 KiB and 64 KiB sectors.
+                */
+               if ( bank->sectors[sector].size == 8*KiB )
+               {
+                       bank->sectors[sector].is_erased =
+                           (signature[3] == 0x01ABAAAA) &&
+                           (signature[2] == 0xAAAAAAAA) &&
+                           (signature[1] == 0xAAAAAAAA) &&
+                           (signature[0] == 0xAAA00AAA);
+               }
+               if ( bank->sectors[sector].size == 64*KiB )
+               {
+                       bank->sectors[sector].is_erased =
+                           (signature[3] == 0x11801222) &&
+                           (signature[2] == 0xB88844FF) &&
+                           (signature[1] == 0x11A22008) &&
+                           (signature[0] == 0x2B1BFE44);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+
+/**
+ * Get protection (sector security) status.
+ *
+ * Determine the status of "sector security" for each sector.
+ * A secured sector is one that can never be erased/programmed again.
+ *
+ * @param bank Pointer to the flash bank descriptor
+ */
+static int lpc2900_protect_check(struct flash_bank *bank)
+{
+       return lpc2900_read_security_status(bank);
+}
+
+
+/**
+ * Print info about the driver (not the device).
+ *
+ * @param bank Pointer to the flash bank descriptor
+ * @param buf Buffer to take the string
+ * @param buf_size Maximum number of characters that the buffer can take
+ */
+static int lpc2900_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "lpc2900 flash driver");
+
+       return ERROR_OK;
+}
+
+
+struct flash_driver lpc2900_flash =
+{
+       .name               = "lpc2900",
+       .commands           = lpc2900_command_handlers,
+       .flash_bank_command = lpc2900_flash_bank_command,
+       .erase              = lpc2900_erase,
+       .protect            = lpc2900_protect,
+       .write              = lpc2900_write,
+       .probe              = lpc2900_probe,
+       .auto_probe         = lpc2900_probe,
+       .erase_check        = lpc2900_erase_check,
+       .protect_check      = lpc2900_protect_check,
+       .info               = lpc2900_info
+};
diff --git a/src/flash/nor/non_cfi.c b/src/flash/nor/non_cfi.c
new file mode 100644 (file)
index 0000000..f98b108
--- /dev/null
@@ -0,0 +1,491 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *   Copyright (C) 2009 Michael Schwingen                                  *
+ *   michael@schwingen.org                                                 *
+ *                                                                         *
+ *   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 "non_cfi.h"
+#include "cfi.h"
+
+
+#define KB 1024
+#define MB (1024*1024)
+#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
+
+/* non-CFI compatible flashes */
+static struct non_cfi non_cfi_flashes[] = {
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd4,
+               .pri_id = 0x02,
+               .dev_size = 64*KB,
+               .interface_desc = 0x0,          /* x8 only device */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(16, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd5,
+               .pri_id = 0x02,
+               .dev_size = 128*KB,
+               .interface_desc = 0x0,          /* x8 only device */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(32, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd6,
+               .pri_id = 0x02,
+               .dev_size = 256*KB,
+               .interface_desc = 0x0,          /* x8 only device */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(64, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd7,
+               .pri_id = 0x02,
+               .dev_size = 512*KB,
+               .interface_desc = 0x0,          /* x8 only device */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(128, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x2780,
+               .pri_id = 0x02,
+               .dev_size = 512*KB,
+               .interface_desc = 0x2,          /* x8 or x16 device */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(128, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_ST,
+               .id = 0xd6,                                     /* ST29F400BB */
+               .pri_id = 0x02,
+               .dev_size = 512*KB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2,  8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(7, 64*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_ST,
+               .id = 0xd5,                                     /* ST29F400BT */
+               .pri_id = 0x02,
+               .dev_size = 512*KB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(7, 64*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(2,  8*KB),
+                       ERASE_REGION(1, 16*KB)
+               }
+       },
+
+       /* SST 39VF* do not support DQ5 status polling - this currently is
+          only supported by the host algorithm, not by the target code using
+          the work area.
+           Only true for 8-bit and 32-bit wide memories. 16-bit wide memories
+           without DQ5 status polling are supported by the target code.
+        */
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x2782,                           /* SST39xF160 */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(512, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x2783,                           /* SST39VF320 */
+               .pri_id = 0x02,
+               .dev_size = 4*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1024, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x234b,                           /* SST39VF1601 */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(512, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x234a,                           /* SST39VF1602 */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(512, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x235b,                           /* SST39VF3201 */
+               .pri_id = 0x02,
+               .dev_size = 4*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1024, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0x235a,                           /* SST39VF3202 */
+               .pri_id = 0x02,
+               .dev_size = 4*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1024, 4*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_AMD,
+               .id = 0x22ab,                           /* AM29F400BB */
+               .pri_id = 0x02,
+               .dev_size = 512*KB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2,  8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(7, 64*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_AMD,
+               .id = 0x2223,                           /* AM29F400BT */
+               .pri_id = 0x02,
+               .dev_size = 512*KB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(7, 64*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(2,  8*KB),
+                       ERASE_REGION(1, 16*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_FUJITSU,
+               .id = 0x226b,                           /* AM29SL800DB */
+               .pri_id = 0x02,
+               .dev_size = 1*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2,  8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(15, 64*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_AMIC,
+               .id = 0xb31a,                           /* A29L800A */
+               .pri_id = 0x02,
+               .dev_size = 1*MB,
+               .interface_desc = 0x2,
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2,  8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(15, 64*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_MX,
+               .id = 0x225b,                           /* MX29LV800B */
+               .pri_id = 0x02,
+               .dev_size = 1*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2, 8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(15, 64*KB)
+               }
+       },
+
+       {
+               .mfr = CFI_MFR_MX,
+               .id = 0x2249,                           /* MX29LV160AB: 2MB */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2, 8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(31, 64*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_MX,
+               .id = 0x22C4,                           /* MX29LV160AT: 2MB */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(31, 64*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(2, 8*KB),
+                       ERASE_REGION(1, 16*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_ATMEL,
+               .id = 0x00c0,                           /* Atmel 49BV1614 */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 3,
+               .erase_region_info =
+               {
+                       ERASE_REGION(8,  8*KB),
+                       ERASE_REGION(2, 32*KB),
+                       ERASE_REGION(30, 64*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_ATMEL,
+               .id = 0xC2,                                     /* Atmel 49BV1614T */
+               .pri_id = 0x02,
+               .dev_size = 2*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 3,
+               .erase_region_info =
+               {
+                       ERASE_REGION(30, 64*KB),
+                       ERASE_REGION(2, 32*KB),
+                       ERASE_REGION(8,  8*KB)
+               }
+       },
+       {
+               .mfr = CFI_MFR_AMD,
+               .id = 0x225b,                           /* S29AL008D */
+               .pri_id = 0x02,
+               .dev_size = 1*MB,
+               .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
+               .max_buf_write_size = 0x0,
+               .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
+               .num_erase_regions = 4,
+               .erase_region_info =
+               {
+                       ERASE_REGION(1, 16*KB),
+                       ERASE_REGION(2, 8*KB),
+                       ERASE_REGION(1, 32*KB),
+                       ERASE_REGION(15, 64*KB)
+               }
+       },
+       {
+               .mfr = 0,
+               .id = 0,
+       }
+};
+
+void cfi_fixup_non_cfi(struct flash_bank *bank)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       struct non_cfi *non_cfi = non_cfi_flashes;
+
+       for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
+       {
+               if ((cfi_info->manufacturer == non_cfi->mfr)
+                       && (cfi_info->device_id == non_cfi->id))
+               {
+                       break;
+               }
+       }
+
+       /* only fixup jedec flashs found in table */
+       if (!non_cfi->mfr)
+               return;
+
+       cfi_info->not_cfi = 1;
+
+       /* fill in defaults for non-critical data */
+       cfi_info->vcc_min = 0x0;
+       cfi_info->vcc_max = 0x0;
+       cfi_info->vpp_min = 0x0;
+       cfi_info->vpp_max = 0x0;
+       cfi_info->word_write_timeout_typ = 0x0;
+       cfi_info->buf_write_timeout_typ = 0x0;
+       cfi_info->block_erase_timeout_typ = 0x0;
+       cfi_info->chip_erase_timeout_typ = 0x0;
+       cfi_info->word_write_timeout_max = 0x0;
+       cfi_info->buf_write_timeout_max = 0x0;
+       cfi_info->block_erase_timeout_max = 0x0;
+       cfi_info->chip_erase_timeout_max = 0x0;
+
+       cfi_info->qry[0] = 'Q';
+       cfi_info->qry[1] = 'R';
+       cfi_info->qry[2] = 'Y';
+
+       cfi_info->pri_id = non_cfi->pri_id;
+       cfi_info->pri_addr = 0x0;
+       cfi_info->alt_id = 0x0;
+       cfi_info->alt_addr = 0x0;
+       cfi_info->alt_ext = NULL;
+
+       cfi_info->interface_desc = non_cfi->interface_desc;
+       cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
+       cfi_info->status_poll_mask = non_cfi->status_poll_mask;
+       cfi_info->num_erase_regions = non_cfi->num_erase_regions;
+       cfi_info->erase_region_info = non_cfi->erase_region_info;
+       cfi_info->dev_size = non_cfi->dev_size;
+
+       if (cfi_info->pri_id == 0x2)
+       {
+               struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
+
+               pri_ext->pri[0] = 'P';
+               pri_ext->pri[1] = 'R';
+               pri_ext->pri[2] = 'I';
+
+               pri_ext->major_version = '1';
+               pri_ext->minor_version = '0';
+
+               pri_ext->SiliconRevision = 0x0;
+               pri_ext->EraseSuspend = 0x0;
+               pri_ext->EraseSuspend = 0x0;
+               pri_ext->BlkProt = 0x0;
+               pri_ext->TmpBlkUnprotect = 0x0;
+               pri_ext->BlkProtUnprot = 0x0;
+               pri_ext->SimultaneousOps = 0x0;
+               pri_ext->BurstMode = 0x0;
+               pri_ext->PageMode = 0x0;
+               pri_ext->VppMin = 0x0;
+               pri_ext->VppMax = 0x0;
+               pri_ext->TopBottom = 0x0;
+
+               pri_ext->_unlock1 = 0x5555;
+               pri_ext->_unlock2 = 0x2AAA;
+               pri_ext->_reversed_geometry = 0;
+
+               cfi_info->pri_ext = pri_ext;
+       } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
+       {
+               LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
+               exit(-1);
+       }
+}
diff --git a/src/flash/nor/non_cfi.h b/src/flash/nor/non_cfi.h
new file mode 100644 (file)
index 0000000..44c92db
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef NON_CFI_H
+#define NON_CFI_H
+
+#include "flash.h"
+
+struct non_cfi
+{
+       uint16_t mfr;
+       uint16_t id;
+       uint16_t pri_id;
+       uint32_t dev_size;
+       uint16_t interface_desc;
+       uint16_t max_buf_write_size;
+       uint8_t num_erase_regions;
+       uint32_t erase_region_info[6];
+       uint8_t  status_poll_mask;
+};
+
+void cfi_fixup_non_cfi(struct flash_bank *bank);
+
+#endif /* NON_CFI_H */
diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c
new file mode 100644 (file)
index 0000000..388395f
--- /dev/null
@@ -0,0 +1,361 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Pavel Chromy                                    *
+ *   chromy@asix.cz                                                        *
+ *                                                                         *
+ *   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 "ocl.h"
+#include "flash.h"
+#include "embeddedice.h"
+
+
+struct ocl_priv
+{
+       struct arm_jtag *jtag_info;
+       unsigned int buflen;
+       unsigned int bufalign;
+};
+
+static int ocl_erase_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static int ocl_protect_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+/* flash_bank ocl 0 0 0 0 <target#> */
+FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
+{
+       struct arm7_9_common *arm7_9;
+       struct ocl_priv *ocl;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank ocl configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       arm7_9 = target_to_arm7_9(bank->target);
+       if (!is_arm7_9(arm7_9))
+               return ERROR_TARGET_INVALID;
+
+       ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv));
+       ocl->jtag_info = &arm7_9->jtag_info;
+       ocl->buflen = 0;
+       ocl->bufalign = 1;
+
+       return ERROR_OK;
+}
+
+static int ocl_erase(struct flash_bank *bank, int first, int last)
+{
+       struct ocl_priv *ocl = bank->driver_priv;
+       int retval;
+       uint32_t dcc_buffer[3];
+
+       /* check preconditions */
+       if (bank->num_sectors == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       if (bank->target->state != TARGET_RUNNING)
+       {
+               LOG_ERROR("target has to be running to communicate with the loader");
+               return ERROR_TARGET_NOT_RUNNING;
+       }
+
+       if ((first == 0) && (last == bank->num_sectors - 1))
+       {
+               dcc_buffer[0] = OCL_ERASE_ALL;
+               if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+                       return retval;
+       }
+       else
+       {
+               dcc_buffer[0] = OCL_ERASE_BLOCK;
+               dcc_buffer[1] = first;
+               dcc_buffer[2] = last;
+               if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3) != ERROR_OK))
+                       return retval;
+       }
+
+       /* wait for response, fixed timeout of 1 s */
+       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
+       {
+               if (retval == ERROR_TARGET_TIMEOUT)
+                       LOG_ERROR("loader not responding");
+               return retval;
+       }
+
+       /* receive response */
+       if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1) != ERROR_OK))
+               return retval;
+
+       if (dcc_buffer[1] != OCL_CMD_DONE)
+       {
+               if (dcc_buffer[0] == OCL_ERASE_ALL)
+                       LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
+               else
+                       LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       return ERROR_OK;
+}
+
+static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct ocl_priv *ocl = bank->driver_priv;
+       int retval;
+       uint32_t *dcc_buffer;
+       uint32_t *dcc_bufptr;
+       int byteofs;
+       int runlen;
+       uint32_t chksum;
+
+       int i;
+
+       /* check preconditions */
+       if (ocl->buflen == 0 || ocl->bufalign == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       if (bank->target->state != TARGET_RUNNING)
+       {
+               LOG_ERROR("target has to be running to communicate with the loader");
+               return ERROR_TARGET_NOT_RUNNING;
+       }
+
+       /* allocate buffer for max. ocl buffer + overhead */
+       dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
+
+       while (count)
+       {
+               if (count + (offset % ocl->bufalign) > ocl->buflen)
+                       runlen = ocl->buflen - (offset % ocl->bufalign);
+               else
+                       runlen = count;
+
+               dcc_buffer[0] = OCL_FLASH_BLOCK | runlen;
+               dcc_buffer[1] = offset;
+               dcc_bufptr = &dcc_buffer[2];
+
+               *dcc_bufptr = 0xffffffff;
+               byteofs = (offset % ocl->bufalign) % 4;
+               chksum = OCL_CHKS_INIT;
+
+               /* copy data to DCC buffer in proper byte order and properly aligned */
+               for (i = 0; i < runlen; i++)
+               {
+                       switch (byteofs++)
+                       {
+                               case 0:
+                                       *dcc_bufptr &= *(buffer++) | 0xffffff00;
+                                       break;
+                               case 1:
+                                       *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff;
+                                       break;
+                               case 2:
+                                       *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff;
+                                       break;
+                               case 3:
+                                       *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff;
+                                       chksum ^= *(dcc_bufptr++);
+                                       *dcc_bufptr = 0xffffffff;
+                                       byteofs = 0;
+                                       break;
+                       }
+               }
+
+               /* add the remaining word to checksum */
+               if (byteofs)
+                       chksum ^= *(dcc_bufptr++);
+
+               *(dcc_bufptr++) = chksum;
+
+               /* send the data */
+               if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer)) != ERROR_OK)
+               {
+                       free(dcc_buffer);
+                 return retval;
+               }
+
+               /* wait for response, fixed timeout of 1 s */
+               if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
+               {
+                       if (retval == ERROR_TARGET_TIMEOUT)
+                               LOG_ERROR("loader not responding");
+                       free(dcc_buffer);
+                       return retval;
+               }
+
+               /* receive response */
+               if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               {
+                       free(dcc_buffer);
+                       return retval;
+               }
+
+               if (dcc_buffer[0] != OCL_CMD_DONE)
+               {
+                       LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
+                       free(dcc_buffer);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               count -= runlen;
+               offset += runlen;
+       }
+
+       free(dcc_buffer);
+       return ERROR_OK;
+}
+
+static int ocl_probe(struct flash_bank *bank)
+{
+       struct ocl_priv *ocl = bank->driver_priv;
+       int retval;
+       uint32_t dcc_buffer[1];
+       int sectsize;
+       int i;
+
+       /* purge pending data in DCC */
+       embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
+
+       dcc_buffer[0] = OCL_PROBE;
+       if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               return retval;
+
+       /* wait for response, fixed timeout of 1 s */
+       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
+       {
+               if (retval == ERROR_TARGET_TIMEOUT)
+                       LOG_ERROR("loader not responding");
+               return retval;
+       }
+
+       /* receive response */
+       if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               return retval;
+
+       if (dcc_buffer[0] != OCL_CMD_DONE)
+       {
+               LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* receive and fill in parameters, detection of loader is important, receive it one by one */
+       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
+               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               return retval;
+       bank->base = dcc_buffer[0];
+
+       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
+               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               return retval;
+       bank->size = dcc_buffer[0];
+
+       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
+               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               return retval;
+       bank->num_sectors = dcc_buffer[0];
+
+       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
+               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
+               return retval;
+       ocl->buflen = dcc_buffer[0] & 0xffff;
+       ocl->bufalign = dcc_buffer[0] >> 16;
+
+       bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
+       if (bank->num_sectors == 0)
+       {
+               LOG_ERROR("number of sectors shall be non zero value");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       if (bank->size % bank->num_sectors) {
+               LOG_ERROR("bank size not divisible by number of sectors");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       sectsize = bank->size / bank->num_sectors;
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               bank->sectors[i].offset = i * sectsize;
+               bank->sectors[i].size = sectsize;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
+       }
+
+       if (ocl->bufalign == 0)
+               ocl->bufalign = 1;
+
+       if (ocl->buflen == 0)
+       {
+               LOG_ERROR("buflen shall be non zero value");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign))
+       {
+               LOG_ERROR("buflen is not multiple of bufalign");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       if (ocl->buflen % 4)
+       {
+               LOG_ERROR("buflen shall be divisible by 4");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       return ERROR_OK;
+}
+
+static int ocl_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       return ERROR_OK;
+}
+
+static int ocl_auto_probe(struct flash_bank *bank)
+{
+       struct ocl_priv *ocl = bank->driver_priv;
+
+       if (ocl->buflen == 0 || ocl->bufalign == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       return ERROR_OK;
+}
+
+struct flash_driver ocl_flash = {
+               .name = "ocl",
+               .flash_bank_command = &ocl_flash_bank_command,
+               .erase = &ocl_erase,
+               .protect = &ocl_protect,
+               .write = &ocl_write,
+               .probe = &ocl_probe,
+               .erase_check = &ocl_erase_check,
+               .protect_check = &ocl_protect_check,
+               .info = &ocl_info,
+               .auto_probe = &ocl_auto_probe,
+       };
diff --git a/src/flash/nor/ocl.h b/src/flash/nor/ocl.h
new file mode 100644 (file)
index 0000000..d5c430b
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Pavel Chromy                                    *
+ *   chromy@asix.cz                                                        *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef OCL_H
+#define OCL_H
+
+/* command/response mask */
+#define OCL_CMD_MASK 0xFFFF0000L
+
+/* commads */
+#define OCL_FLASH_BLOCK 0x0CFB0000L
+#define OCL_ERASE_BLOCK 0x0CEB0000L
+#define OCL_ERASE_ALL 0x0CEA0000L
+#define OCL_PROBE 0x0CBE0000L
+
+/* responses */
+#define OCL_CMD_DONE 0x0ACD0000L
+#define OCL_CMD_ERR 0x0ACE0000L
+#define OCL_CHKS_FAIL 0x0ACF0000L
+#define OCL_BUFF_OVER 0x0AB00000L
+
+#define OCL_CHKS_INIT 0xC100CD0CL
+
+#endif /* OCL_H */
diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c
new file mode 100644 (file)
index 0000000..9bb6c97
--- /dev/null
@@ -0,0 +1,922 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   Copyright (C) 2008 by John McCarthy                                   *
+ *   jgmcc@magma.ca                                                        *
+ *                                                                         *
+ *   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 "pic32mx.h"
+#include "mips32.h"
+
+
+static
+struct pic32mx_devs_s {
+       uint8_t devid;
+       char    *name;
+       uint32_t        pfm_size;
+} pic32mx_devs[] = {
+       { 0x78, "460F512L USB", 512 },
+       { 0x74, "460F256L USB", 256 },
+       { 0x6D, "440F128L USB", 128 },
+       { 0x56, "440F512H USB", 512 },
+       { 0x52, "440F256H USB", 256 },
+       { 0x4D, "440F128H USB", 128 },
+       { 0x42, "420F032H USB",  32 },
+       { 0x38, "360F512L",     512 },
+       { 0x34, "360F256L",     256 },
+       { 0x2D, "340F128L",     128 },
+       { 0x2A, "320F128L",     128 },
+       { 0x16, "340F512H",     512 },
+       { 0x12, "340F256H",     256 },
+       { 0x0D, "340F128H",     128 },
+       { 0x0A, "320F128H",     128 },
+       { 0x06, "320F064H",      64 },
+       { 0x02, "320F032H",      32 },
+       { 0x00, NULL, 0 }
+};
+
+static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr);
+static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word);
+
+/* flash bank pic32mx <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command)
+{
+       struct pic32mx_flash_bank *pic32mx_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank pic32mx configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank));
+       bank->driver_priv = pic32mx_info;
+
+       pic32mx_info->write_algorithm = NULL;
+       pic32mx_info->probed = 0;
+
+       return ERROR_OK;
+}
+
+static uint32_t pic32mx_get_flash_status(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t status;
+
+       target_read_u32(target, PIC32MX_NVMCON, &status);
+
+       return status;
+}
+
+static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+       uint32_t status;
+
+       /* wait for busy to clear */
+       while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0))
+       {
+               LOG_DEBUG("status: 0x%" PRIx32, status);
+               alive_sleep(1);
+       }
+       if (timeout <= 0)
+               LOG_DEBUG("timeout: status: 0x%" PRIx32, status);
+
+       return status;
+}
+
+static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout)
+{
+       struct target *target = bank->target;
+       uint32_t status;
+
+       target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
+
+       /* unlock flash registers */
+       target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1);
+       target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2);
+
+       /* start operation */
+       target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR);
+
+       status = pic32mx_wait_status_busy(bank, timeout);
+
+       /* lock flash registers */
+       target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN);
+
+       return status;
+}
+
+static int pic32mx_protect_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+
+       uint32_t devcfg0;
+       int s;
+       int num_pages;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       target_read_u32(target, PIC32MX_DEVCFG0, &devcfg0);
+       if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */
+               num_pages = 0xffff;  /* All pages protected */
+       else if (bank->base == PIC32MX_KSEG1_BOOT_FLASH)
+       {
+               if (devcfg0 & (1 << 24))
+                       num_pages = 0;       /* All pages unprotected */
+               else
+                       num_pages = 0xffff;  /* All pages protected */
+       }
+       else /* pgm flash */
+               num_pages = (~devcfg0 >> 12) & 0xff;
+       for (s = 0; s < bank->num_sectors && s < num_pages; s++)
+               bank->sectors[s].is_protected = 1;
+       for (; s < bank->num_sectors; s++)
+               bank->sectors[s].is_protected = 0;
+
+       return ERROR_OK;
+}
+
+static int pic32mx_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       int i;
+       uint32_t status;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first == 0) && (last == (bank->num_sectors - 1)) && (bank->base == PIC32MX_KSEG0_PGM_FLASH || bank->base == PIC32MX_KSEG1_PGM_FLASH))
+       {
+               LOG_DEBUG("Erasing entire program flash");
+               status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);
+               if (status & NVMCON_NVMERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               if (status & NVMCON_LVDERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               return ERROR_OK;
+       }
+
+       for (i = first; i <= last; i++)
+       {
+               if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
+                       target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(bank->base + bank->sectors[i].offset));
+               else
+                       target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(bank->base + bank->sectors[i].offset));
+
+               status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);
+
+               if (status & NVMCON_NVMERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               if (status & NVMCON_LVDERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               bank->sectors[i].is_erased = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       struct pic32mx_flash_bank *pic32mx_info = NULL;
+       struct target *target = bank->target;
+#if 0
+       uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+       int i, reg, bit;
+       int status;
+       uint32_t protection;
+#endif
+
+       pic32mx_info = bank->driver_priv;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+#if 0
+       if ((first && (first % pic32mx_info->ppage_size)) || ((last + 1) && (last + 1) % pic32mx_info->ppage_size))
+       {
+               LOG_WARNING("sector start/end incorrect - stm32 has %dK sector protection", pic32mx_info->ppage_size);
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* medium density - each bit refers to a 4bank protection
+        * high density - each bit refers to a 2bank protection */
+       target_read_u32(target, PIC32MX_FLASH_WRPR, &protection);
+
+       prot_reg[0] = (uint16_t)protection;
+       prot_reg[1] = (uint16_t)(protection >> 8);
+       prot_reg[2] = (uint16_t)(protection >> 16);
+       prot_reg[3] = (uint16_t)(protection >> 24);
+
+       if (pic32mx_info->ppage_size == 2)
+       {
+               /* high density flash */
+
+               /* bit 7 controls sector 62 - 255 protection */
+               if (last > 61)
+               {
+                       if (set)
+                               prot_reg[3] &= ~(1 << 7);
+                       else
+                               prot_reg[3] |= (1 << 7);
+               }
+
+               if (first > 61)
+                       first = 62;
+               if (last > 61)
+                       last = 61;
+
+               for (i = first; i <= last; i++)
+               {
+                       reg = (i / pic32mx_info->ppage_size) / 8;
+                       bit = (i / pic32mx_info->ppage_size) - (reg * 8);
+
+                       if (set)
+                               prot_reg[reg] &= ~(1 << bit);
+                       else
+                               prot_reg[reg] |= (1 << bit);
+               }
+       }
+       else
+       {
+               /* medium density flash */
+               for (i = first; i <= last; i++)
+               {
+                       reg = (i / pic32mx_info->ppage_size) / 8;
+                       bit = (i / pic32mx_info->ppage_size) - (reg * 8);
+
+                       if (set)
+                               prot_reg[reg] &= ~(1 << bit);
+                       else
+                               prot_reg[reg] |= (1 << bit);
+               }
+       }
+
+       if ((status = pic32mx_erase_options(bank)) != ERROR_OK)
+               return status;
+
+       pic32mx_info->option_bytes.protection[0] = prot_reg[0];
+       pic32mx_info->option_bytes.protection[1] = prot_reg[1];
+       pic32mx_info->option_bytes.protection[2] = prot_reg[2];
+       pic32mx_info->option_bytes.protection[3] = prot_reg[3];
+
+       return pic32mx_write_options(bank);
+#else
+       return ERROR_OK;
+#endif
+}
+
+static int pic32mx_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       uint32_t buffer_size = 512;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       int retval = ERROR_OK;
+#if 0
+       struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+       struct armv7m_algorithm armv7m_info;
+
+       uint8_t pic32mx_flash_write_code[] = {
+                                                                       /* write: */
+               0xDF, 0xF8, 0x24, 0x40,         /* ldr  r4, PIC32MX_FLASH_CR */
+               0x09, 0x4D,                                     /* ldr  r5, PIC32MX_FLASH_SR */
+               0x4F, 0xF0, 0x01, 0x03,         /* mov  r3, #1 */
+               0x23, 0x60,                                     /* str  r3, [r4, #0] */
+               0x30, 0xF8, 0x02, 0x3B,         /* ldrh r3, [r0], #2 */
+               0x21, 0xF8, 0x02, 0x3B,         /* strh r3, [r1], #2 */
+                                                                       /* busy: */
+               0x2B, 0x68,                                     /* ldr  r3, [r5, #0] */
+               0x13, 0xF0, 0x01, 0x0F,         /* tst  r3, #0x01 */
+               0xFB, 0xD0,                                     /* beq  busy */
+               0x13, 0xF0, 0x14, 0x0F,         /* tst  r3, #0x14 */
+               0x01, 0xD1,                                     /* bne  exit */
+               0x01, 0x3A,                                     /* subs r2, r2, #1 */
+               0xED, 0xD1,                                     /* bne  write */
+                                                                       /* exit: */
+               0xFE, 0xE7,                                     /* b exit */
+               0x10, 0x20, 0x02, 0x40,         /* PIC32MX_FLASH_CR:    .word 0x40022010 */
+               0x0C, 0x20, 0x02, 0x40          /* PIC32MX_FLASH_SR:    .word 0x4002200C */
+       };
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code), &pic32mx_info->write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       if ((retval = target_write_buffer(target, pic32mx_info->write_algorithm->address, sizeof(pic32mx_flash_write_code), pic32mx_flash_write_code)) != ERROR_OK)
+               return retval;
+#endif
+
+       /* memory buffer */
+       if (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       {
+#if 0
+               /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
+               if (pic32mx_info->write_algorithm)
+                       target_free_working_area(target, pic32mx_info->write_algorithm);
+#endif
+
+               LOG_WARNING("no large enough working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       while (count >= buffer_size/4)
+       {
+               uint32_t status;
+
+               if ((retval = target_write_buffer(target, source->address, buffer_size, buffer)) != ERROR_OK) {
+                       LOG_ERROR("Failed to write row buffer (%d words) to RAM", (int)(buffer_size/4));
+                       break;
+               }
+
+#if 0
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, buffer_size/4);
+
+               if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, pic32mx_info->write_algorithm->address, \
+                               pic32mx_info->write_algorithm->address + (sizeof(pic32mx_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing pic32mx flash write algorithm");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)
+               {
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+#endif
+               status = pic32mx_write_row(bank, address, source->address);
+               if (status & NVMCON_NVMERR) {
+                       LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+               if (status & NVMCON_LVDERR) {
+                       LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer  += buffer_size;
+               address += buffer_size;
+               count   -= buffer_size/4;
+       }
+
+       target_free_working_area(target, source);
+
+       while (count > 0)
+       {
+               uint32_t value;
+               memcpy(&value, buffer, sizeof(uint32_t));
+
+               uint32_t status = pic32mx_write_word(bank, address, value);
+               if (status & NVMCON_NVMERR) {
+                       LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+               if (status & NVMCON_LVDERR) {
+                       LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer  += 4;
+               address += 4;
+               count--;
+       }
+
+       return retval;
+}
+
+static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
+{
+       struct target *target = bank->target;
+
+       if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
+               target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(address));
+       else
+               target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(address));
+       target_write_u32(target, PIC32MX_NVMDATA, word);
+
+       return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);
+}
+
+/*
+ * Write a 128 word (512 byte) row to flash address from RAM srcaddr.
+ */
+static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr)
+{
+       struct target *target = bank->target;
+
+       LOG_DEBUG("addr: 0x%08" PRIx32 " srcaddr: 0x%08" PRIx32 "", address, srcaddr);
+
+       if (address >= PIC32MX_KSEG1_PGM_FLASH)
+               target_write_u32(target, PIC32MX_NVMADDR,    KS1Virt2Phys(address));
+       else
+               target_write_u32(target, PIC32MX_NVMADDR,    KS0Virt2Phys(address));
+       if (srcaddr >= PIC32MX_KSEG1_RAM)
+               target_write_u32(target, PIC32MX_NVMSRCADDR, KS1Virt2Phys(srcaddr));
+       else
+               target_write_u32(target, PIC32MX_NVMSRCADDR, KS0Virt2Phys(srcaddr));
+
+       return pic32mx_nvm_exec(bank, NVMCON_OP_ROW_PROG, 100);
+}
+
+static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       uint32_t words_remaining = (count / 4);
+       uint32_t bytes_remaining = (count & 0x00000003);
+       uint32_t address = bank->base + offset;
+       uint32_t bytes_written = 0;
+       uint32_t status;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x3)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       /* multiple words (4-byte) to be programmed? */
+       if (words_remaining > 0)
+       {
+               /* try using a block write */
+               if ((retval = pic32mx_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */
+                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
+                       {
+                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       buffer += words_remaining * 4;
+                       address += words_remaining * 4;
+                       words_remaining = 0;
+               }
+       }
+
+       while (words_remaining > 0)
+       {
+               uint32_t value;
+               memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
+
+               status = pic32mx_write_word(bank, address, value);
+               if (status & NVMCON_NVMERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               if (status & NVMCON_LVDERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               bytes_written += 4;
+               words_remaining--;
+               address += 4;
+       }
+
+       if (bytes_remaining)
+       {
+               uint32_t value = 0xffffffff;
+               memcpy(&value, buffer + bytes_written, bytes_remaining);
+
+               status = pic32mx_write_word(bank, address, value);
+               if (status & NVMCON_NVMERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               if (status & NVMCON_LVDERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int pic32mx_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+       struct mips32_common *mips32 = target->arch_info;
+       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+       int i;
+       uint16_t num_pages = 0;
+       uint32_t device_id;
+       int page_size;
+
+       pic32mx_info->probed = 0;
+
+       device_id = ejtag_info->idcode;
+       LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%02x, ver 0x%03x)",
+                         device_id,
+                         (unsigned)((device_id >> 1)&0x7ff),
+                         (unsigned)((device_id >> 12)&0xff),
+                         (unsigned)((device_id >> 20)&0xfff));
+
+       if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
+               LOG_WARNING("Cannot identify target as a PIC32MX family.");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       page_size = 4096;
+       if (bank->base == PIC32MX_KSEG1_BOOT_FLASH || bank->base == 1) {
+               /* 0xBFC00000: Boot flash size fixed at 12k */
+               num_pages = 12;
+       } else {
+               /* 0xBD000000: Program flash size varies with device */
+               for (i = 0; pic32mx_devs[i].name != NULL; i++)
+                       if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
+                               num_pages = pic32mx_devs[i].pfm_size;
+                               break;
+                       }
+               if (pic32mx_devs[i].name == NULL) {
+                       LOG_WARNING("Cannot identify target as a PIC32MX family.");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+
+#if 0
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* get flash size from target */
+       if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)
+       {
+               /* failed reading flash size, default to max target family */
+               num_pages = 0xffff;
+       }
+#endif
+
+       LOG_INFO("flash size = %dkbytes", num_pages);
+
+       /* calculate numbers of pages */
+       num_pages /= (page_size / 1024);
+
+       if (bank->base == 0) bank->base = PIC32MX_KSEG1_PGM_FLASH;
+       if (bank->base == 1) bank->base = PIC32MX_KSEG1_BOOT_FLASH;
+       bank->size = (num_pages * page_size);
+       bank->num_sectors = num_pages;
+       bank->chip_width = 4;
+       bank->bus_width  = 4;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+
+       for (i = 0; i < num_pages; i++)
+       {
+               bank->sectors[i].offset = i * page_size;
+               bank->sectors[i].size = page_size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 1;
+       }
+
+       pic32mx_info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int pic32mx_auto_probe(struct flash_bank *bank)
+{
+       struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
+       if (pic32mx_info->probed)
+               return ERROR_OK;
+       return pic32mx_probe(bank);
+}
+
+#if 0
+COMMAND_HANDLER(pic32mx_handle_part_id_command)
+{
+       return ERROR_OK;
+}
+#endif
+
+static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct target *target = bank->target;
+       struct mips32_common *mips32 = target->arch_info;
+       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+       uint32_t device_id;
+       int printed = 0, i;
+
+       device_id = ejtag_info->idcode;
+
+       if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
+               snprintf(buf, buf_size,
+                                "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n",
+                                (unsigned)((device_id >> 1)&0x7ff),
+                                PIC32MX_MANUF_ID);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       for (i = 0; pic32mx_devs[i].name != NULL; i++)
+               if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
+                       printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
+                       break;
+               }
+       if (pic32mx_devs[i].name == NULL) {
+               snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family\n");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       buf += printed;
+       buf_size -= printed;
+       printed = snprintf(buf, buf_size, "  Ver: 0x%03x",
+                                          (unsigned)((device_id >> 20)&0xfff));
+
+       return ERROR_OK;
+}
+
+#if 0
+COMMAND_HANDLER(pic32mx_handle_lock_command)
+{
+       struct target *target = NULL;
+       struct pic32mx_flash_bank *pic32mx_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "pic32mx lock <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       pic32mx_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (pic32mx_erase_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "pic32mx failed to erase options");
+               return ERROR_OK;
+       }
+
+       /* set readout protection */
+       pic32mx_info->option_bytes.RDP = 0;
+
+       if (pic32mx_write_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "pic32mx failed to lock device");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "pic32mx locked");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(pic32mx_handle_unlock_command)
+{
+       struct target *target = NULL;
+       struct pic32mx_flash_bank *pic32mx_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "pic32mx unlock <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       pic32mx_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (pic32mx_erase_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "pic32mx failed to unlock device");
+               return ERROR_OK;
+       }
+
+       if (pic32mx_write_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "pic32mx failed to lock device");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "pic32mx unlocked");
+
+       return ERROR_OK;
+}
+#endif
+
+#if 0
+static int pic32mx_chip_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+#if 0
+       uint32_t status;
+#endif
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       LOG_INFO("PIC32MX chip erase called");
+
+#if 0
+       /* unlock option flash registers */
+       target_write_u32(target, PIC32MX_FLASH_KEYR, KEY1);
+       target_write_u32(target, PIC32MX_FLASH_KEYR, KEY2);
+
+       /* chip erase flash memory */
+       target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER);
+       target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER | FLASH_STRT);
+
+       status = pic32mx_wait_status_busy(bank, 10);
+
+       target_write_u32(target, PIC32MX_FLASH_CR, FLASH_LOCK);
+
+       if (status & FLASH_WRPRTERR)
+       {
+               LOG_ERROR("pic32mx device protected");
+               return ERROR_OK;
+       }
+
+       if (status & FLASH_PGERR)
+       {
+               LOG_ERROR("pic32mx device programming failed");
+               return ERROR_OK;
+       }
+#endif
+
+       return ERROR_OK;
+}
+#endif
+
+COMMAND_HANDLER(pic32mx_handle_chip_erase_command)
+{
+#if 0
+       int i;
+
+       if (CMD_ARGC != 0)
+       {
+               command_print(CMD_CTX, "pic32mx chip_erase");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (pic32mx_chip_erase(bank) == ERROR_OK)
+       {
+               /* set all sectors as erased */
+               for (i = 0; i < bank->num_sectors; i++)
+               {
+                       bank->sectors[i].is_erased = 1;
+               }
+
+               command_print(CMD_CTX, "pic32mx chip erase complete");
+       }
+       else
+       {
+               command_print(CMD_CTX, "pic32mx chip erase failed");
+       }
+#endif
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
+{
+       uint32_t address, value;
+       int status, res;
+
+       if (CMD_ARGC != 3)
+       {
+               command_print(CMD_CTX, "pic32mx pgm_word <addr> <value> <bank>");
+               return ERROR_OK;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (address < bank->base || address >= (bank->base + bank->size))
+       {
+               command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+
+       res = ERROR_OK;
+       status = pic32mx_write_word(bank, address, value);
+       if (status & NVMCON_NVMERR)
+               res = ERROR_FLASH_OPERATION_FAILED;
+       if (status & NVMCON_LVDERR)
+               res = ERROR_FLASH_OPERATION_FAILED;
+
+       if (res == ERROR_OK)
+               command_print(CMD_CTX, "pic32mx pgm word complete");
+       else
+               command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
+
+       return ERROR_OK;
+}
+static const struct command_registration pic32mx_exec_command_handlers[] = {
+       {
+               .name = "chip_erase",
+               .handler = &pic32mx_handle_chip_erase_command,
+               .mode = COMMAND_EXEC,
+               .help = "erase device",
+       },
+       {
+               .name = "pgm_word",
+               .handler = &pic32mx_handle_pgm_word_command,
+               .mode = COMMAND_EXEC,
+               .help = "program a word",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration pic32mx_command_handlers[] = {
+       {
+               .name = "pic32mx",
+               .mode = COMMAND_ANY,
+               .help = "pic32mx flash command group",
+               .chain = pic32mx_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver pic32mx_flash = {
+               .name = "pic32mx",
+               .commands = pic32mx_command_handlers,
+               .flash_bank_command = &pic32mx_flash_bank_command,
+               .erase = &pic32mx_erase,
+               .protect = &pic32mx_protect,
+               .write = &pic32mx_write,
+               .probe = &pic32mx_probe,
+               .auto_probe = &pic32mx_auto_probe,
+               .erase_check = &default_flash_mem_blank_check,
+               .protect_check = &pic32mx_protect_check,
+               .info = &pic32mx_info,
+       };
diff --git a/src/flash/nor/pic32mx.h b/src/flash/nor/pic32mx.h
new file mode 100644 (file)
index 0000000..92f40c2
--- /dev/null
@@ -0,0 +1,113 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   Copyright (C) 2008 by John McCarthy                                   *
+ *   jgmcc@magma.ca                                                        *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef PIC32MX_H
+#define PIC32MX_H
+
+#include "flash.h"
+
+struct pic32mx_flash_bank
+{
+       struct working_area *write_algorithm;
+       int devid;
+       int ppage_size;
+       int probed;
+};
+
+#define PIC32MX_MANUF_ID       0x029
+
+/* pic32mx memory locations */
+
+#define PIC32MX_KUSEG_PGM_FLASH                0x7D000000
+#define PIC32MX_KUSEG_RAM                      0x7F000000
+
+#define PIC32MX_KSEG0_RAM                      0x80000000
+#define PIC32MX_KSEG0_PGM_FLASH                0x9D000000
+#define PIC32MX_KSEG0_BOOT_FLASH       0x9FC00000
+
+#define PIC32MX_KSEG1_RAM                      0xA0000000
+#define PIC32MX_KSEG1_PGM_FLASH                0xBD000000
+#define PIC32MX_KSEG1_PERIPHERAL       0xBF800000
+#define PIC32MX_KSEG1_BOOT_FLASH       0xBFC00000
+
+#define PIC32MX_PHYS_RAM                       0x00000000
+#define PIC32MX_PHYS_PGM_FLASH         0x1D000000
+#define PIC32MX_PHYS_PERIPHERALS       0x1F800000
+#define PIC32MX_PHYS_BOOT_FLASH                0x1FC00000
+
+/*
+ * Translate Virtual and Physical addresses.
+ * Note: These macros only work for KSEG0/KSEG1 addresses.
+ */
+#define KS1Virt2Phys(vaddr)                    ((vaddr)-0xA0000000)
+#define Phys2KS1Virt(paddr)                    ((paddr) + 0xA0000000)
+#define KS0Virt2Phys(vaddr)                    ((vaddr)-0x80000000)
+#define Phys2KS0Virt(paddr)                    ((paddr) + 0x80000000)
+
+/* pic32mx configuration register locations */
+
+#define PIC32MX_DEVCFG0                0xBFC02FFC
+#define PIC32MX_DEVCFG1                0xBFC02FF8
+#define PIC32MX_DEVCFG2                0xBFC02FF4
+#define PIC32MX_DEVCFG3                0XBFC02FF0
+#define PIC32MX_DEVID          0xBF80F220
+
+/* pic32mx flash controller register locations */
+
+#define PIC32MX_NVMCON         0xBF80F400
+#define PIC32MX_NVMCONCLR      0xBF80F404
+#define PIC32MX_NVMCONSET      0xBF80F408
+#define PIC32MX_NVMCONINV      0xBF80F40C
+#define NVMCON_NVMWR           (1 << 15)
+#define NVMCON_NVMWREN         (1 << 14)
+#define NVMCON_NVMERR          (1 << 13)
+#define NVMCON_LVDERR          (1 << 12)
+#define NVMCON_LVDSTAT         (1 << 11)
+#define NVMCON_OP_PFM_ERASE            0x5
+#define NVMCON_OP_PAGE_ERASE   0x4
+#define NVMCON_OP_ROW_PROG             0x3
+#define NVMCON_OP_WORD_PROG            0x1
+#define NVMCON_OP_NOP                  0x0
+
+#define PIC32MX_NVMKEY         0xBF80F410
+#define PIC32MX_NVMADDR                0xBF80F420
+#define PIC32MX_NVMADDRCLR     0xBF80F424
+#define PIC32MX_NVMADDRSET     0xBF80F428
+#define PIC32MX_NVMADDRINV     0xBF80F42C
+#define PIC32MX_NVMDATA                0xBF80F430
+#define PIC32MX_NVMSRCADDR     0xBF80F440
+
+/* flash unlock keys */
+
+#define NVMKEY1                        0xAA996655
+#define NVMKEY2                        0x556699AA
+
+struct pic32mx_mem_layout {
+       uint32_t sector_start;
+       uint32_t sector_size;
+};
+
+#endif /* PIC32MX_H */
+
diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c
new file mode 100644 (file)
index 0000000..771f0a7
--- /dev/null
@@ -0,0 +1,1195 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Magnus Lundin                                   *
+ *   lundin@mlu.mine.nu                                                    *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/***************************************************************************
+* STELLARIS is tested on LM3S811, LM3S6965
+***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "stellaris.h"
+#include "armv7m.h"
+#include "binarybuffer.h"
+#include "algorithm.h"
+
+
+#define DID0_VER(did0) ((did0 >> 28)&0x07)
+
+static int stellaris_read_part_info(struct flash_bank *bank);
+static uint32_t stellaris_get_flash_status(struct flash_bank *bank);
+static void stellaris_set_flash_mode(struct flash_bank *bank,int mode);
+//static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
+
+static int stellaris_mass_erase(struct flash_bank *bank);
+
+static struct {
+       uint32_t partno;
+       char *partname;
+}      StellarisParts[] =
+{
+       {0x01,"LM3S101"},
+       {0x02,"LM3S102"},
+       {0x03,"LM3S1625"},
+       {0x04,"LM3S1626"},
+       {0x05,"LM3S1627"},
+       {0x06,"LM3S1607"},
+       {0x10,"LM3S1776"},
+       {0x19,"LM3S300"},
+       {0x11,"LM3S301"},
+       {0x12,"LM3S310"},
+       {0x1A,"LM3S308"},
+       {0x13,"LM3S315"},
+       {0x14,"LM3S316"},
+       {0x17,"LM3S317"},
+       {0x18,"LM3S318"},
+       {0x15,"LM3S328"},
+       {0x2A,"LM3S600"},
+       {0x21,"LM3S601"},
+       {0x2B,"LM3S608"},
+       {0x22,"LM3S610"},
+       {0x23,"LM3S611"},
+       {0x24,"LM3S612"},
+       {0x25,"LM3S613"},
+       {0x26,"LM3S615"},
+       {0x28,"LM3S617"},
+       {0x29,"LM3S618"},
+       {0x27,"LM3S628"},
+       {0x38,"LM3S800"},
+       {0x31,"LM3S801"},
+       {0x39,"LM3S808"},
+       {0x32,"LM3S811"},
+       {0x33,"LM3S812"},
+       /*{0x33,"LM3S2616"},*/
+       {0x34,"LM3S815"},
+       {0x36,"LM3S817"},
+       {0x37,"LM3S818"},
+       {0x35,"LM3S828"},
+       {0x39,"LM3S2276"},
+       {0x3A,"LM3S2776"},
+       {0x43,"LM3S3651"},
+       {0x44,"LM3S3739"},
+       {0x45,"LM3S3749"},
+       {0x46,"LM3S3759"},
+       {0x48,"LM3S3768"},
+       {0x49,"LM3S3748"},
+       {0x50,"LM3S2678"},
+       {0x51,"LM3S2110"},
+       {0x52,"LM3S2739"},
+       {0x53,"LM3S2651"},
+       {0x54,"LM3S2939"},
+       {0x55,"LM3S2965"},
+       {0x56,"LM3S2432"},
+       {0x57,"LM3S2620"},
+       {0x58,"LM3S2950"},
+       {0x59,"LM3S2412"},
+       {0x5A,"LM3S2533"},
+       {0x61,"LM3S8630"},
+       {0x62,"LM3S8970"},
+       {0x63,"LM3S8730"},
+       {0x64,"LM3S8530"},
+       {0x65,"LM3S8930"},
+       {0x71,"LM3S6610"},
+       {0x72,"LM3S6950"},
+       {0x73,"LM3S6965"},
+       {0x74,"LM3S6110"},
+       {0x75,"LM3S6432"},
+       {0x76,"LM3S6537"},
+       {0x77,"LM3S6753"},
+       {0x78,"LM3S6952"},
+       {0x80,"LM3S2671"},
+       {0x81,"LM3S5632"},
+       {0x82,"LM3S6422"},
+       {0x83,"LM3S6633"},
+       {0x84,"LM3S2139"},
+       {0x85,"LM3S2637"},
+       {0x86,"LM3S8738"},
+       {0x88,"LM3S8938"},
+       {0x89,"LM3S6938"},
+       {0x8A,"LM3S5652"},
+       {0x8B,"LM3S6637"},
+       {0x8C,"LM3S8933"},
+       {0x8D,"LM3S8733"},
+       {0x8E,"LM3S8538"},
+       {0x8F,"LM3S2948"},
+       {0x91,"LM3S5662"},
+       {0x96,"LM3S5732"},
+       {0x97,"LM3S5737"},
+       {0x99,"LM3S5747"},
+       {0x9A,"LM3S5752"},
+       {0x9B,"LM3S5757"},
+       {0x9C,"LM3S5762"},
+       {0x9D,"LM3S5767"},
+       {0xA0,"LM3S5739"},
+       {0xA1,"LM3S6100"},
+       {0xA2,"LM3S2410"},
+       {0xA3,"LM3S6730"},
+       {0xA4,"LM3S2730"},
+       {0xA5,"LM3S6420"},
+       {0xA6,"LM3S8962"},
+       {0xA7,"LM3S5749"},
+       {0xA8,"LM3S5769"},
+       {0xA9,"LM3S5768"},
+       {0xB3,"LM3S1635"},
+       {0xB4,"LM3S1850"},
+       {0xB5,"LM3S1960"},
+       {0xB7,"LM3S1937"},
+       {0xB8,"LM3S1968"},
+       {0xB9,"LM3S1751"},
+       {0xBA,"LM3S1439"},
+       {0xBB,"LM3S1512"},
+       {0xBC,"LM3S1435"},
+       {0xBD,"LM3S1637"},
+       {0xBE,"LM3S1958"},
+       {0xBF,"LM3S1110"},
+       {0xC0,"LM3S1620"},
+       {0xC1,"LM3S1150"},
+       {0xC2,"LM3S1165"},
+       {0xC3,"LM3S1133"},
+       {0xC4,"LM3S1162"},
+       {0xC5,"LM3S1138"},
+       {0xC6,"LM3S1332"},
+       {0xC7,"LM3S1538"},
+       {0xD0,"LM3S6815"},
+       {0xD1,"LM3S6816"},
+       {0xD2,"LM3S6915"},
+       {0xD3,"LM3S6916"},
+       {0xD4,"LM3S2016"},
+       {0xD5,"LM3S1615"},
+       {0xD6,"LM3S1616"},
+       {0xD7,"LM3S8971"},
+       {0xD8,"LM3S1108"},
+       {0xD9,"LM3S1101"},
+       {0xDA,"LM3S1608"},
+       {0xDB,"LM3S1601"},
+       {0xDC,"LM3S1918"},
+       {0xDD,"LM3S1911"},
+       {0xDE,"LM3S2108"},
+       {0xDF,"LM3S2101"},
+       {0xE0,"LM3S2608"},
+       {0xE1,"LM3S2601"},
+       {0xE2,"LM3S2918"},
+       {0xE3,"LM3S2911"},
+       {0xE4,"LM3S6118"},
+       {0xE5,"LM3S6111"},
+       {0xE6,"LM3S6618"},
+       {0xE7,"LM3S6611"},
+       {0xE8,"LM3S6918"},
+       {0xE9,"LM3S6911"},
+       {0,"Unknown part"}
+};
+
+static char * StellarisClassname[5] =
+{
+       "Sandstorm",
+       "Fury",
+       "Unknown",
+       "DustDevil",
+       "Tempest"
+};
+
+/***************************************************************************
+*      openocd command interface                                              *
+***************************************************************************/
+
+/* flash_bank stellaris <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command)
+{
+       struct stellaris_flash_bank *stellaris_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank stellaris configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1);
+       bank->base = 0x0;
+       bank->driver_priv = stellaris_info;
+
+       stellaris_info->target_name = "Unknown target";
+
+       /* part wasn't probed for info yet */
+       stellaris_info->did1 = 0;
+
+       /* TODO Specify the main crystal speed in kHz using an optional
+        * argument; ditto, the speed of an external oscillator used
+        * instead of a crystal.  Avoid programming flash using IOSC.
+        */
+       return ERROR_OK;
+}
+
+static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int printed, device_class;
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+
+       stellaris_read_part_info(bank);
+
+       if (stellaris_info->did1 == 0)
+       {
+               printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");
+               buf += printed;
+               buf_size -= printed;
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (DID0_VER(stellaris_info->did0) > 0)
+       {
+               device_class = (stellaris_info->did0 >> 16) & 0xFF;
+       }
+       else
+       {
+               device_class = 0;
+       }
+       printed = snprintf(buf,
+                          buf_size,
+                          "\nTI/LMI Stellaris information: Chip is "
+                          "class %i (%s) %s rev %c%i\n",
+                          device_class,
+                          StellarisClassname[device_class],
+                          stellaris_info->target_name,
+                          (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)),
+                          (int)((stellaris_info->did0) & 0xFF));
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf,
+                          buf_size,
+                          "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32
+                          ", eproc: %s, ramsize: %ik, flashsize: %ik\n",
+                          stellaris_info->did1,
+                          stellaris_info->did1,
+                          "ARMv7M",
+                          (int)((1 + ((stellaris_info->dc0 >> 16) & 0xFFFF))/4),
+                          (int)((1 + (stellaris_info->dc0 & 0xFFFF))*2));
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf,
+                          buf_size,
+                          "master clock: %ikHz%s, "
+                          "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n",
+                          (int)(stellaris_info->mck_freq / 1000),
+                          stellaris_info->mck_desc,
+                          stellaris_info->rcc,
+                          stellaris_info->rcc2);
+       buf += printed;
+       buf_size -= printed;
+
+       if (stellaris_info->num_lockbits > 0)
+       {
+               printed = snprintf(buf,
+                                  buf_size,
+                                  "pagesize: %" PRIi32 ", lockbits: %i 0x%4.4" PRIx32 ", pages in lock region: %i \n",
+                                  stellaris_info->pagesize,
+                                  stellaris_info->num_lockbits,
+                                  stellaris_info->lockbits,
+                                  (int)(stellaris_info->num_pages/stellaris_info->num_lockbits));
+               buf += printed;
+               buf_size -= printed;
+       }
+       return ERROR_OK;
+}
+
+/***************************************************************************
+*      chip identification and status                                         *
+***************************************************************************/
+
+static uint32_t stellaris_get_flash_status(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t fmc;
+
+       target_read_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, &fmc);
+
+       return fmc;
+}
+
+/** Read clock configuration and set stellaris_info->usec_clocks*/
+
+static const unsigned rcc_xtal[32] = {
+       [0x00] = 1000000,               /* no pll */
+       [0x01] = 1843200,               /* no pll */
+       [0x02] = 2000000,               /* no pll */
+       [0x03] = 2457600,               /* no pll */
+
+       [0x04] = 3579545,
+       [0x05] = 3686400,
+       [0x06] = 4000000,               /* usb */
+       [0x07] = 4096000,
+
+       [0x08] = 4915200,
+       [0x09] = 5000000,               /* usb */
+       [0x0a] = 5120000,
+       [0x0b] = 6000000,               /* (reset) usb */
+
+       [0x0c] = 6144000,
+       [0x0d] = 7372800,
+       [0x0e] = 8000000,               /* usb */
+       [0x0f] = 8192000,
+
+       /* parts before DustDevil use just 4 bits for xtal spec */
+
+       [0x10] = 10000000,              /* usb */
+       [0x11] = 12000000,              /* usb */
+       [0x12] = 12288000,
+       [0x13] = 13560000,
+
+       [0x14] = 14318180,
+       [0x15] = 16000000,              /* usb */
+       [0x16] = 16384000,
+};
+
+static void stellaris_read_clock_info(struct flash_bank *bank)
+{
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
+       unsigned xtal;
+       unsigned long mainfreq;
+
+       target_read_u32(target, SCB_BASE | RCC, &rcc);
+       LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc);
+
+       target_read_u32(target, SCB_BASE | RCC2, &rcc2);
+       LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc);
+
+       target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg);
+       LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg);
+
+       stellaris_info->rcc = rcc;
+       stellaris_info->rcc = rcc2;
+
+       sysdiv = (rcc >> 23) & 0xF;
+       usesysdiv = (rcc >> 22) & 0x1;
+       bypass = (rcc >> 11) & 0x1;
+       oscsrc = (rcc >> 4) & 0x3;
+       xtal = (rcc >> 6) & stellaris_info->xtal_mask;
+
+       /* NOTE: post-Sandstorm parts have RCC2 which may override
+        * parts of RCC ... with more sysdiv options, option for
+        * 32768 Hz mainfreq, PLL controls.  On Sandstorm it reads
+        * as zero, so the "use RCC2" flag is always clear.
+        */
+       if (rcc2 & (1 << 31)) {
+               sysdiv = (rcc2 >> 23) & 0x3F;
+               bypass = (rcc2 >> 11) & 0x1;
+               oscsrc = (rcc2 >> 4) & 0x7;
+
+               /* FIXME Tempest parts have an additional lsb for
+                * fractional sysdiv (200 MHz / 2.5 == 80 MHz)
+                */
+       }
+
+       stellaris_info->mck_desc = "";
+
+       switch (oscsrc)
+       {
+               case 0:                         /* MOSC */
+                       mainfreq = rcc_xtal[xtal];
+                       break;
+               case 1:                         /* IOSC */
+                       mainfreq = stellaris_info->iosc_freq;
+                       stellaris_info->mck_desc = stellaris_info->iosc_desc;
+                       break;
+               case 2:                         /* IOSC/4 */
+                       mainfreq = stellaris_info->iosc_freq / 4;
+                       stellaris_info->mck_desc = stellaris_info->iosc_desc;
+                       break;
+               case 3:                         /* lowspeed */
+                       /* Sandstorm doesn't have this 30K +/- 30% osc */
+                       mainfreq = 30000;
+                       stellaris_info->mck_desc = " (±30%)";
+                       break;
+               case 8:                         /* hibernation osc */
+                       /* not all parts support hibernation */
+                       mainfreq = 32768;
+                       break;
+
+               default: /* NOTREACHED */
+                       mainfreq = 0;
+                       break;
+       }
+
+       /* PLL is used if it's not bypassed; its output is 200 MHz
+        * even when it runs at 400 MHz (adds divide-by-two stage).
+        */
+       if (!bypass)
+               mainfreq = 200000000;
+
+       if (usesysdiv)
+               stellaris_info->mck_freq = mainfreq/(1 + sysdiv);
+       else
+               stellaris_info->mck_freq = mainfreq;
+
+       /* Forget old flash timing */
+       stellaris_set_flash_mode(bank, 0);
+}
+
+/* Setup the timimg registers */
+static void stellaris_set_flash_mode(struct flash_bank *bank,int mode)
+{
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1);
+       LOG_DEBUG("usecrl = %i",(int)(usecrl));
+       target_write_u32(target, SCB_BASE | USECRL, usecrl);
+}
+
+#if 0
+static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
+{
+       uint32_t status;
+
+       /* Stellaris waits for cmdbit to clear */
+       while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
+       {
+               LOG_DEBUG("status: 0x%x", status);
+               alive_sleep(1);
+       }
+
+       /* Flash errors are reflected in the FLASH_CRIS register */
+
+       return status;
+}
+
+/* Send one command to the flash controller */
+static int stellaris_flash_command(struct flash_bank *bank,uint8_t cmd,uint16_t pagen)
+{
+       uint32_t fmc;
+       struct target *target = bank->target;
+
+       fmc = FMC_WRKEY | cmd;
+       target_write_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, fmc);
+       LOG_DEBUG("Flash command: 0x%x", fmc);
+
+       if (stellaris_wait_status_busy(bank, cmd, 100))
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+#endif
+
+/* Read device id register, main clock frequency register and fill in driver info structure */
+static int stellaris_read_part_info(struct flash_bank *bank)
+{
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t did0, did1, ver, fam, status;
+       int i;
+
+       /* Read and parse chip identification register */
+       target_read_u32(target, SCB_BASE | DID0, &did0);
+       target_read_u32(target, SCB_BASE | DID1, &did1);
+       target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0);
+       target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1);
+       LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "",
+                 did0, did1, stellaris_info->dc0, stellaris_info->dc1);
+
+       ver = did0 >> 28;
+       if ((ver != 0) && (ver != 1))
+       {
+               LOG_WARNING("Unknown did0 version, cannot identify target");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (did1 == 0)
+       {
+               LOG_WARNING("Cannot identify target as a Stellaris");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       ver = did1 >> 28;
+       fam = (did1 >> 24) & 0xF;
+       if (((ver != 0) && (ver != 1)) || (fam != 0))
+       {
+               LOG_WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
+       }
+
+       /* For Sandstorm, Fury, DustDevil:  current data sheets say IOSC
+        * is 12 MHz, but some older parts have 15 MHz.  A few data sheets
+        * even give _both_ numbers!  We'll use current numbers; IOSC is
+        * always approximate.
+        *
+        * For Tempest:  IOSC is calibrated, 16 MHz
+        */
+       stellaris_info->iosc_freq = 12000000;
+       stellaris_info->iosc_desc = " (±30%)";
+       stellaris_info->xtal_mask = 0x0f;
+
+       switch ((did0 >> 28) & 0x7) {
+       case 0:                         /* Sandstorm */
+               /*
+                * Current (2009-August) parts seem to be rev C2 and use 12 MHz.
+                * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz
+                * (LM3S618), but some other C0 parts are 12 MHz (LM3S811).
+                */
+               if (((did0 >> 8) & 0xff) < 2) {
+                       stellaris_info->iosc_freq = 15000000;
+                       stellaris_info->iosc_desc = " (±50%)";
+               }
+               break;
+       case 1:
+               switch ((did0 >> 16) & 0xff) {
+               case 1:                 /* Fury */
+                       break;
+               case 4:                 /* Tempest */
+                       stellaris_info->iosc_freq = 16000000;   /* +/- 1% */
+                       stellaris_info->iosc_desc = " (±1%)";
+                       /* FALL THROUGH */
+               case 3:                 /* DustDevil */
+                       stellaris_info->xtal_mask = 0x1f;
+                       break;
+               default:
+                       LOG_WARNING("Unknown did0 class");
+               }
+       default:
+               break;
+               LOG_WARNING("Unknown did0 version");
+       }
+
+       for (i = 0; StellarisParts[i].partno; i++)
+       {
+               if (StellarisParts[i].partno == ((did1 >> 16) & 0xFF))
+                       break;
+       }
+
+       stellaris_info->target_name = StellarisParts[i].partname;
+
+       stellaris_info->did0 = did0;
+       stellaris_info->did1 = did1;
+
+       stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
+       stellaris_info->num_pages = 2 *(1 + (stellaris_info->dc0 & 0xFFFF));
+       stellaris_info->pagesize = 1024;
+       bank->size = 1024 * stellaris_info->num_pages;
+       stellaris_info->pages_in_lockregion = 2;
+       target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
+
+       /* provide this for the benefit of the higher flash driver layers */
+       bank->num_sectors = stellaris_info->num_pages;
+       bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               bank->sectors[i].offset = i * stellaris_info->pagesize;
+               bank->sectors[i].size = stellaris_info->pagesize;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
+       }
+
+       /* Read main and master clock freqency register */
+       stellaris_read_clock_info(bank);
+
+       status = stellaris_get_flash_status(bank);
+
+       return ERROR_OK;
+}
+
+/***************************************************************************
+*      flash operations                                                       *
+***************************************************************************/
+
+static int stellaris_protect_check(struct flash_bank *bank)
+{
+       uint32_t status;
+
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               stellaris_read_part_info(bank);
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               LOG_WARNING("Cannot identify target as Stellaris");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       status = stellaris_get_flash_status(bank);
+       stellaris_info->lockbits = status >> 16;
+
+       return ERROR_OK;
+}
+
+static int stellaris_erase(struct flash_bank *bank, int first, int last)
+{
+       int banknr;
+       uint32_t flash_fmc, flash_cris;
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               stellaris_read_part_info(bank);
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               LOG_WARNING("Cannot identify target as Stellaris");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       if ((first == 0) && (last == ((int)stellaris_info->num_pages-1)))
+       {
+               return stellaris_mass_erase(bank);
+       }
+
+       /* Configure the flash controller timing */
+       stellaris_read_clock_info(bank);
+       stellaris_set_flash_mode(bank,0);
+
+       /* Clear and disable flash programming interrupts */
+       target_write_u32(target, FLASH_CIM, 0);
+       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
+
+       for (banknr = first; banknr <= last; banknr++)
+       {
+               /* Address is first word in page */
+               target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize);
+               /* Write erase command */
+               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);
+               /* Wait until erase complete */
+               do
+               {
+                       target_read_u32(target, FLASH_FMC, &flash_fmc);
+               }
+               while (flash_fmc & FMC_ERASE);
+
+               /* Check acess violations */
+               target_read_u32(target, FLASH_CRIS, &flash_cris);
+               if (flash_cris & (AMASK))
+               {
+                       LOG_WARNING("Error erasing flash page %i,  flash_cris 0x%" PRIx32 "", banknr, flash_cris);
+                       target_write_u32(target, FLASH_CRIS, 0);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               bank->sectors[banknr].is_erased = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int stellaris_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       uint32_t fmppe, flash_fmc, flash_cris;
+       int lockregion;
+
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= stellaris_info->num_lockbits))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               stellaris_read_part_info(bank);
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               LOG_WARNING("Cannot identify target as an Stellaris MCU");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Configure the flash controller timing */
+       stellaris_read_clock_info(bank);
+       stellaris_set_flash_mode(bank, 0);
+
+       fmppe = stellaris_info->lockbits;
+       for (lockregion = first; lockregion <= last; lockregion++)
+       {
+               if (set)
+                       fmppe &= ~(1 << lockregion);
+               else
+                       fmppe |= (1 << lockregion);
+       }
+
+       /* Clear and disable flash programming interrupts */
+       target_write_u32(target, FLASH_CIM, 0);
+       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
+
+       LOG_DEBUG("fmppe 0x%" PRIx32 "",fmppe);
+       target_write_u32(target, SCB_BASE | FMPPE, fmppe);
+       /* Commit FMPPE */
+       target_write_u32(target, FLASH_FMA, 1);
+       /* Write commit command */
+       /* TODO safety check, sice this cannot be undone */
+       LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
+       /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
+       /* Wait until erase complete */
+       do
+       {
+               target_read_u32(target, FLASH_FMC, &flash_fmc);
+       }
+       while (flash_fmc & FMC_COMT);
+
+       /* Check acess violations */
+       target_read_u32(target, FLASH_CRIS, &flash_cris);
+       if (flash_cris & (AMASK))
+       {
+               LOG_WARNING("Error setting flash page protection,  flash_cris 0x%" PRIx32 "", flash_cris);
+               target_write_u32(target, FLASH_CRIS, 0);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
+
+       return ERROR_OK;
+}
+
+static uint8_t stellaris_write_code[] =
+{
+/*
+       Call with :
+       r0 = buffer address
+       r1 = destination address
+       r2 = bytecount (in) - endaddr (work)
+
+       Used registers:
+       r3 = pFLASH_CTRL_BASE
+       r4 = FLASHWRITECMD
+       r5 = #1
+       r6 = bytes written
+       r7 = temp reg
+*/
+       0x07,0x4B,                      /* ldr r3,pFLASH_CTRL_BASE */
+       0x08,0x4C,                      /* ldr r4,FLASHWRITECMD */
+       0x01,0x25,                      /* movs r5, 1 */
+       0x00,0x26,                      /* movs r6, #0 */
+/* mainloop: */
+       0x19,0x60,                      /* str  r1, [r3, #0] */
+       0x87,0x59,                      /* ldr  r7, [r0, r6] */
+       0x5F,0x60,                      /* str  r7, [r3, #4] */
+       0x9C,0x60,                      /* str  r4, [r3, #8] */
+/* waitloop: */
+       0x9F,0x68,                      /* ldr  r7, [r3, #8] */
+       0x2F,0x42,                      /* tst  r7, r5 */
+       0xFC,0xD1,                      /* bne  waitloop */
+       0x04,0x31,                      /* adds r1, r1, #4 */
+       0x04,0x36,                      /* adds r6, r6, #4 */
+       0x96,0x42,                      /* cmp  r6, r2 */
+       0xF4,0xD1,                      /* bne  mainloop */
+                                               /* exit: */
+       0xFE,0xE7,                      /* b exit */
+/* pFLASH_CTRL_BASE: */
+       0x00,0xD0,0x0F,0x40,    /* .word        0x400FD000 */
+/* FLASHWRITECMD: */
+       0x01,0x00,0x42,0xA4     /* .word        0xA4420001 */
+};
+
+static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t wcount)
+{
+       struct target *target = bank->target;
+       uint32_t buffer_size = 8192;
+       struct working_area *source;
+       struct working_area *write_algorithm;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[3];
+       struct armv7m_algorithm armv7m_info;
+       int retval = ERROR_OK;
+
+       LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
+                       bank, buffer, offset, wcount);
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), stellaris_write_code);
+
+       /* memory buffer */
+       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       {
+               LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
+                               target, buffer_size, source);
+               buffer_size /= 2;
+               if (buffer_size <= 256)
+               {
+                       /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
+                       if (write_algorithm)
+                               target_free_working_area(target, write_algorithm);
+
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       };
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARMV7M_MODE_ANY;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+
+       while (wcount > 0)
+       {
+               uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
+
+               target_write_buffer(target, source->address, thisrun_count * 4, buffer);
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
+               LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
+               LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
+               if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing stellaris flash write algorithm");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer += thisrun_count * 4;
+               address += thisrun_count * 4;
+               wcount -= thisrun_count;
+       }
+
+       target_free_working_area(target, write_algorithm);
+       target_free_working_area(target, source);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+
+       return retval;
+}
+
+static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t address = offset;
+       uint32_t flash_cris, flash_fmc;
+       uint32_t words_remaining = (count / 4);
+       uint32_t bytes_remaining = (count & 0x00000003);
+       uint32_t bytes_written = 0;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "",
+                       bank, buffer, offset, count);
+
+       if (stellaris_info->did1 == 0)
+       {
+               stellaris_read_part_info(bank);
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               LOG_WARNING("Cannot identify target as a Stellaris processor");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (offset & 0x3)
+       {
+               LOG_WARNING("offset size must be word aligned");
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       if (offset + count > bank->size)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       /* Configure the flash controller timing */
+       stellaris_read_clock_info(bank);
+       stellaris_set_flash_mode(bank, 0);
+
+       /* Clear and disable flash programming interrupts */
+       target_write_u32(target, FLASH_CIM, 0);
+       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
+
+       /* multiple words to be programmed? */
+       if (words_remaining > 0)
+       {
+               /* try using a block write */
+               if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */
+                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
+                       {
+                               /* if an error occured, we examine the reason, and quit */
+                               target_read_u32(target, FLASH_CRIS, &flash_cris);
+
+                               LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       buffer += words_remaining * 4;
+                       address += words_remaining * 4;
+                       words_remaining = 0;
+               }
+       }
+
+       while (words_remaining > 0)
+       {
+               if (!(address & 0xff))
+                       LOG_DEBUG("0x%" PRIx32 "", address);
+
+               /* Program one word */
+               target_write_u32(target, FLASH_FMA, address);
+               target_write_buffer(target, FLASH_FMD, 4, buffer);
+               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
+               /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
+               /* Wait until write complete */
+               do
+               {
+                       target_read_u32(target, FLASH_FMC, &flash_fmc);
+               } while (flash_fmc & FMC_WRITE);
+
+               buffer += 4;
+               address += 4;
+               words_remaining--;
+       }
+
+       if (bytes_remaining)
+       {
+               uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
+               int i = 0;
+
+               while (bytes_remaining > 0)
+               {
+                       last_word[i++] = *(buffer + bytes_written);
+                       bytes_remaining--;
+                       bytes_written++;
+               }
+
+               if (!(address & 0xff))
+                       LOG_DEBUG("0x%" PRIx32 "", address);
+
+               /* Program one word */
+               target_write_u32(target, FLASH_FMA, address);
+               target_write_buffer(target, FLASH_FMD, 4, last_word);
+               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
+               /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
+               /* Wait until write complete */
+               do
+               {
+                       target_read_u32(target, FLASH_FMC, &flash_fmc);
+               } while (flash_fmc & FMC_WRITE);
+       }
+
+       /* Check access violations */
+       target_read_u32(target, FLASH_CRIS, &flash_cris);
+       if (flash_cris & (AMASK))
+       {
+               LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       return ERROR_OK;
+}
+
+static int stellaris_probe(struct flash_bank *bank)
+{
+       /* we can't probe on an stellaris
+        * if this is an stellaris, it has the configured flash
+        */
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* stellaris_read_part_info() already takes care about error checking and reporting */
+       return stellaris_read_part_info(bank);
+}
+
+static int stellaris_auto_probe(struct flash_bank *bank)
+{
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       if (stellaris_info->did1)
+               return ERROR_OK;
+       return stellaris_probe(bank);
+}
+
+static int stellaris_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = NULL;
+       struct stellaris_flash_bank *stellaris_info = NULL;
+       uint32_t flash_fmc;
+
+       stellaris_info = bank->driver_priv;
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               stellaris_read_part_info(bank);
+       }
+
+       if (stellaris_info->did1 == 0)
+       {
+               LOG_WARNING("Cannot identify target as Stellaris");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* Configure the flash controller timing */
+       stellaris_read_clock_info(bank);
+       stellaris_set_flash_mode(bank, 0);
+
+       /* Clear and disable flash programming interrupts */
+       target_write_u32(target, FLASH_CIM, 0);
+       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
+
+       target_write_u32(target, FLASH_FMA, 0);
+       target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
+       /* Wait until erase complete */
+       do
+       {
+               target_read_u32(target, FLASH_FMC, &flash_fmc);
+       }
+       while (flash_fmc & FMC_MERASE);
+
+       /* if device has > 128k, then second erase cycle is needed
+        * this is only valid for older devices, but will not hurt */
+       if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
+       {
+               target_write_u32(target, FLASH_FMA, 0x20000);
+               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
+               /* Wait until erase complete */
+               do
+               {
+                       target_read_u32(target, FLASH_FMC, &flash_fmc);
+               }
+               while (flash_fmc & FMC_MERASE);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stellaris_handle_mass_erase_command)
+{
+       int i;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "stellaris mass_erase <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (stellaris_mass_erase(bank) == ERROR_OK)
+       {
+               /* set all sectors as erased */
+               for (i = 0; i < bank->num_sectors; i++)
+               {
+                       bank->sectors[i].is_erased = 1;
+               }
+
+               command_print(CMD_CTX, "stellaris mass erase complete");
+       }
+       else
+       {
+               command_print(CMD_CTX, "stellaris mass erase failed");
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration stellaris_exec_command_handlers[] = {
+       {
+               .name = "mass_erase",
+               .handler = &stellaris_handle_mass_erase_command,
+               .mode = COMMAND_EXEC,
+               .help = "erase entire device",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration stellaris_command_handlers[] = {
+       {
+               .name = "stellaris",
+               .mode = COMMAND_ANY,
+               .help = "Stellaris flash command group",
+               .chain = stellaris_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver stellaris_flash = {
+               .name = "stellaris",
+               .commands = stellaris_command_handlers,
+               .flash_bank_command = &stellaris_flash_bank_command,
+               .erase = &stellaris_erase,
+               .protect = &stellaris_protect,
+               .write = &stellaris_write,
+               .probe = &stellaris_probe,
+               .auto_probe = &stellaris_auto_probe,
+               .erase_check = &default_flash_mem_blank_check,
+               .protect_check = &stellaris_protect_check,
+               .info = &stellaris_info,
+       };
diff --git a/src/flash/nor/stellaris.h b/src/flash/nor/stellaris.h
new file mode 100644 (file)
index 0000000..949a346
--- /dev/null
@@ -0,0 +1,99 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Magnus Lundin                                   *
+ *   lundin@mlu.mine.nu                                                    *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef STELLARIS_FLASH_H
+#define STELLARIS_FLASH_H
+
+#include "flash.h"
+
+struct stellaris_flash_bank
+{
+       /* chip id register */
+       uint32_t did0;
+       uint32_t did1;
+       uint32_t dc0;
+       uint32_t dc1;
+
+       char * target_name;
+
+       uint32_t sramsiz;
+       uint32_t flshsz;
+       /* flash geometry */
+       uint32_t num_pages;
+       uint32_t pagesize;
+       uint32_t pages_in_lockregion;
+
+       /* nv memory bits */
+       uint16_t num_lockbits;
+       uint32_t lockbits;
+
+       /* main clock status */
+       uint32_t rcc;
+       uint32_t rcc2;
+       uint8_t  mck_valid;
+       uint8_t  xtal_mask;
+       uint32_t iosc_freq;
+       uint32_t mck_freq;
+       const char *iosc_desc;
+       const char *mck_desc;
+};
+
+/* STELLARIS control registers */
+#define SCB_BASE       0x400FE000
+#define        DID0            0x000
+#define        DID1            0x004
+#define        DC0                     0x008
+#define        DC1                     0x010
+#define        DC2                     0x014
+#define        DC3                     0x018
+#define        DC4                     0x01C
+
+#define        RIS                     0x050
+#define        RCC                     0x060
+#define        PLLCFG          0x064
+#define        RCC2            0x070
+
+#define FMPRE          0x130
+#define FMPPE          0x134
+#define USECRL         0x140
+
+#define FLASH_CONTROL_BASE     0x400FD000
+#define FLASH_FMA      (FLASH_CONTROL_BASE | 0x000)
+#define FLASH_FMD      (FLASH_CONTROL_BASE | 0x004)
+#define FLASH_FMC      (FLASH_CONTROL_BASE | 0x008)
+#define FLASH_CRIS     (FLASH_CONTROL_BASE | 0x00C)
+#define FLASH_CIM      (FLASH_CONTROL_BASE | 0x010)
+#define FLASH_MISC     (FLASH_CONTROL_BASE | 0x014)
+
+#define AMISC  1
+#define PMISC  2
+
+#define AMASK  1
+#define PMASK  2
+
+/* Flash Controller Command bits */
+#define FMC_WRKEY      (0xA442 << 16)
+#define FMC_COMT       (1 << 3)
+#define FMC_MERASE     (1 << 2)
+#define FMC_ERASE      (1 << 1)
+#define FMC_WRITE      (1 << 0)
+
+/* STELLARIS constants */
+
+#endif /* STELLARIS_H */
diff --git a/src/flash/nor/stm32x.c b/src/flash/nor/stm32x.c
new file mode 100644 (file)
index 0000000..2f51aa5
--- /dev/null
@@ -0,0 +1,1240 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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 "stm32x.h"
+#include "armv7m.h"
+#include "binarybuffer.h"
+#include "algorithm.h"
+
+
+static int stm32x_mass_erase(struct flash_bank *bank);
+
+/* flash bank stm32x <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
+{
+       struct stm32x_flash_bank *stm32x_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank stm32x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
+       bank->driver_priv = stm32x_info;
+
+       stm32x_info->write_algorithm = NULL;
+       stm32x_info->probed = 0;
+
+       return ERROR_OK;
+}
+
+static uint32_t stm32x_get_flash_status(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t status;
+
+       target_read_u32(target, STM32_FLASH_SR, &status);
+
+       return status;
+}
+
+static uint32_t stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+       struct target *target = bank->target;
+       uint32_t status;
+
+       /* wait for busy to clear */
+       while (((status = stm32x_get_flash_status(bank)) & FLASH_BSY) && (timeout-- > 0))
+       {
+               LOG_DEBUG("status: 0x%" PRIx32 "", status);
+               alive_sleep(1);
+       }
+       /* Clear but report errors */
+       if (status & (FLASH_WRPRTERR | FLASH_PGERR))
+       {
+               target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR);
+       }
+       return status;
+}
+
+static int stm32x_read_options(struct flash_bank *bank)
+{
+       uint32_t optiondata;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+       struct target *target = bank->target;
+
+       stm32x_info = bank->driver_priv;
+
+       /* read current option bytes */
+       target_read_u32(target, STM32_FLASH_OBR, &optiondata);
+
+       stm32x_info->option_bytes.user_options = (uint16_t)0xFFF8 | ((optiondata >> 2) & 0x07);
+       stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
+
+       if (optiondata & (1 << OPT_READOUT))
+               LOG_INFO("Device Security Bit Set");
+
+       /* each bit refers to a 4bank protection */
+       target_read_u32(target, STM32_FLASH_WRPR, &optiondata);
+
+       stm32x_info->option_bytes.protection[0] = (uint16_t)optiondata;
+       stm32x_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8);
+       stm32x_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16);
+       stm32x_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24);
+
+       return ERROR_OK;
+}
+
+static int stm32x_erase_options(struct flash_bank *bank)
+{
+       struct stm32x_flash_bank *stm32x_info = NULL;
+       struct target *target = bank->target;
+       uint32_t status;
+
+       stm32x_info = bank->driver_priv;
+
+       /* read current options */
+       stm32x_read_options(bank);
+
+       /* unlock flash registers */
+       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+
+       /* unlock option flash registers */
+       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
+
+       /* erase option bytes */
+       target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE);
+       target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* clear readout protection and complementary option bytes
+        * this will also force a device unlock if set */
+       stm32x_info->option_bytes.RDP = 0x5AA5;
+
+       return ERROR_OK;
+}
+
+static int stm32x_write_options(struct flash_bank *bank)
+{
+       struct stm32x_flash_bank *stm32x_info = NULL;
+       struct target *target = bank->target;
+       uint32_t status;
+
+       stm32x_info = bank->driver_priv;
+
+       /* unlock flash registers */
+       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+
+       /* unlock option flash registers */
+       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
+
+       /* program option bytes */
+       target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE);
+
+       /* write user option byte */
+       target_write_u16(target, STM32_OB_USER, stm32x_info->option_bytes.user_options);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* write protection byte 1 */
+       target_write_u16(target, STM32_OB_WRP0, stm32x_info->option_bytes.protection[0]);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* write protection byte 2 */
+       target_write_u16(target, STM32_OB_WRP1, stm32x_info->option_bytes.protection[1]);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* write protection byte 3 */
+       target_write_u16(target, STM32_OB_WRP2, stm32x_info->option_bytes.protection[2]);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* write protection byte 4 */
+       target_write_u16(target, STM32_OB_WRP3, stm32x_info->option_bytes.protection[3]);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* write readout protection bit */
+       target_write_u16(target, STM32_OB_RDP, stm32x_info->option_bytes.RDP);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       if (status & FLASH_WRPRTERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+       if (status & FLASH_PGERR)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+
+       return ERROR_OK;
+}
+
+static int stm32x_protect_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+
+       uint32_t protection;
+       int i, s;
+       int num_bits;
+       int set;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* medium density - each bit refers to a 4bank protection
+        * high density - each bit refers to a 2bank protection */
+       target_read_u32(target, STM32_FLASH_WRPR, &protection);
+
+       /* medium density - each protection bit is for 4 * 1K pages
+        * high density - each protection bit is for 2 * 2K pages */
+       num_bits = (bank->num_sectors / stm32x_info->ppage_size);
+
+       if (stm32x_info->ppage_size == 2)
+       {
+               /* high density flash/connectivity line protection */
+
+               set = 1;
+
+               if (protection & (1 << 31))
+                       set = 0;
+
+               /* bit 31 controls sector 62 - 255 protection for high density
+                * bit 31 controls sector 62 - 127 protection for connectivity line */
+               for (s = 62; s < bank->num_sectors; s++)
+               {
+                       bank->sectors[s].is_protected = set;
+               }
+
+               if (bank->num_sectors > 61)
+                       num_bits = 31;
+
+               for (i = 0; i < num_bits; i++)
+               {
+                       set = 1;
+
+                       if (protection & (1 << i))
+                               set = 0;
+
+                       for (s = 0; s < stm32x_info->ppage_size; s++)
+                               bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set;
+               }
+       }
+       else
+       {
+               /* low/medium density flash protection */
+               for (i = 0; i < num_bits; i++)
+               {
+                       set = 1;
+
+                       if (protection & (1 << i))
+                               set = 0;
+
+                       for (s = 0; s < stm32x_info->ppage_size; s++)
+                               bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int stm32x_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       int i;
+       uint32_t status;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first == 0) && (last == (bank->num_sectors - 1)))
+       {
+               return stm32x_mass_erase(bank);
+       }
+
+       /* unlock flash registers */
+       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+
+       for (i = first; i <= last; i++)
+       {
+               target_write_u32(target, STM32_FLASH_CR, FLASH_PER);
+               target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset);
+               target_write_u32(target, STM32_FLASH_CR, FLASH_PER | FLASH_STRT);
+
+               status = stm32x_wait_status_busy(bank, 10);
+
+               if (status & FLASH_WRPRTERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               if (status & FLASH_PGERR)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               bank->sectors[i].is_erased = 1;
+       }
+
+       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+
+       return ERROR_OK;
+}
+
+static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       struct stm32x_flash_bank *stm32x_info = NULL;
+       struct target *target = bank->target;
+       uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+       int i, reg, bit;
+       int status;
+       uint32_t protection;
+
+       stm32x_info = bank->driver_priv;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first && (first % stm32x_info->ppage_size)) || ((last + 1) && (last + 1) % stm32x_info->ppage_size))
+       {
+               LOG_WARNING("Error: start and end sectors must be on a %d sector boundary", stm32x_info->ppage_size);
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* medium density - each bit refers to a 4bank protection
+        * high density - each bit refers to a 2bank protection */
+       target_read_u32(target, STM32_FLASH_WRPR, &protection);
+
+       prot_reg[0] = (uint16_t)protection;
+       prot_reg[1] = (uint16_t)(protection >> 8);
+       prot_reg[2] = (uint16_t)(protection >> 16);
+       prot_reg[3] = (uint16_t)(protection >> 24);
+
+       if (stm32x_info->ppage_size == 2)
+       {
+               /* high density flash */
+
+               /* bit 7 controls sector 62 - 255 protection */
+               if (last > 61)
+               {
+                       if (set)
+                               prot_reg[3] &= ~(1 << 7);
+                       else
+                               prot_reg[3] |= (1 << 7);
+               }
+
+               if (first > 61)
+                       first = 62;
+               if (last > 61)
+                       last = 61;
+
+               for (i = first; i <= last; i++)
+               {
+                       reg = (i / stm32x_info->ppage_size) / 8;
+                       bit = (i / stm32x_info->ppage_size) - (reg * 8);
+
+                       if (set)
+                               prot_reg[reg] &= ~(1 << bit);
+                       else
+                               prot_reg[reg] |= (1 << bit);
+               }
+       }
+       else
+       {
+               /* medium density flash */
+               for (i = first; i <= last; i++)
+               {
+                       reg = (i / stm32x_info->ppage_size) / 8;
+                       bit = (i / stm32x_info->ppage_size) - (reg * 8);
+
+                       if (set)
+                               prot_reg[reg] &= ~(1 << bit);
+                       else
+                               prot_reg[reg] |= (1 << bit);
+               }
+       }
+
+       if ((status = stm32x_erase_options(bank)) != ERROR_OK)
+               return status;
+
+       stm32x_info->option_bytes.protection[0] = prot_reg[0];
+       stm32x_info->option_bytes.protection[1] = prot_reg[1];
+       stm32x_info->option_bytes.protection[2] = prot_reg[2];
+       stm32x_info->option_bytes.protection[3] = prot_reg[3];
+
+       return stm32x_write_options(bank);
+}
+
+static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 16384;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[4];
+       struct armv7m_algorithm armv7m_info;
+       int retval = ERROR_OK;
+
+       uint8_t stm32x_flash_write_code[] = {
+                                                                       /* write: */
+               0xDF, 0xF8, 0x24, 0x40,         /* ldr  r4, STM32_FLASH_CR */
+               0x09, 0x4D,                                     /* ldr  r5, STM32_FLASH_SR */
+               0x4F, 0xF0, 0x01, 0x03,         /* mov  r3, #1 */
+               0x23, 0x60,                                     /* str  r3, [r4, #0] */
+               0x30, 0xF8, 0x02, 0x3B,         /* ldrh r3, [r0], #2 */
+               0x21, 0xF8, 0x02, 0x3B,         /* strh r3, [r1], #2 */
+                                                                       /* busy: */
+               0x2B, 0x68,                                     /* ldr  r3, [r5, #0] */
+               0x13, 0xF0, 0x01, 0x0F,         /* tst  r3, #0x01 */
+               0xFB, 0xD0,                                     /* beq  busy */
+               0x13, 0xF0, 0x14, 0x0F,         /* tst  r3, #0x14 */
+               0x01, 0xD1,                                     /* bne  exit */
+               0x01, 0x3A,                                     /* subs r2, r2, #1 */
+               0xED, 0xD1,                                     /* bne  write */
+                                                                       /* exit: */
+               0xFE, 0xE7,                                     /* b exit */
+               0x10, 0x20, 0x02, 0x40,         /* STM32_FLASH_CR:      .word 0x40022010 */
+               0x0C, 0x20, 0x02, 0x40          /* STM32_FLASH_SR:      .word 0x4002200C */
+       };
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code)) != 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 (stm32x_info->write_algorithm)
+                               target_free_working_area(target, stm32x_info->write_algorithm);
+
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       };
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARMV7M_MODE_ANY;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
+
+       while (count > 0)
+       {
+               uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+
+               if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK)
+                       break;
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+
+               if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
+                               stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing stm32x flash write algorithm");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR)
+               {
+                       LOG_ERROR("flash memory not erased before writing");
+                       /* Clear but report errors */
+                       target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR)
+               {
+                       LOG_ERROR("flash memory write protected");
+                       /* Clear but report errors */
+                       target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer += thisrun_count * 2;
+               address += thisrun_count * 2;
+               count -= thisrun_count;
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, stm32x_info->write_algorithm);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+
+       return retval;
+}
+
+static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       uint32_t words_remaining = (count / 2);
+       uint32_t bytes_remaining = (count & 0x00000001);
+       uint32_t address = bank->base + offset;
+       uint32_t bytes_written = 0;
+       uint8_t status;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x1)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       /* unlock flash registers */
+       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+
+       /* multiple half words (2-byte) to be programmed? */
+       if (words_remaining > 0)
+       {
+               /* try using a block write */
+               if ((retval = stm32x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */
+                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
+                       {
+                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       buffer += words_remaining * 2;
+                       address += words_remaining * 2;
+                       words_remaining = 0;
+               }
+       }
+
+       while (words_remaining > 0)
+       {
+               uint16_t value;
+               memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
+
+               target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
+               target_write_u16(target, address, value);
+
+               status = stm32x_wait_status_busy(bank, 5);
+
+               if (status & FLASH_WRPRTERR)
+               {
+                       LOG_ERROR("flash memory not erased before writing");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               if (status & FLASH_PGERR)
+               {
+                       LOG_ERROR("flash memory write protected");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               bytes_written += 2;
+               words_remaining--;
+               address += 2;
+       }
+
+       if (bytes_remaining)
+       {
+               uint16_t value = 0xffff;
+               memcpy(&value, buffer + bytes_written, bytes_remaining);
+
+               target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
+               target_write_u16(target, address, value);
+
+               status = stm32x_wait_status_busy(bank, 5);
+
+               if (status & FLASH_WRPRTERR)
+               {
+                       LOG_ERROR("flash memory not erased before writing");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               if (status & FLASH_PGERR)
+               {
+                       LOG_ERROR("flash memory write protected");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+
+       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+
+       return ERROR_OK;
+}
+
+static int stm32x_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+       int i;
+       uint16_t num_pages;
+       uint32_t device_id;
+       int page_size;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       stm32x_info->probed = 0;
+
+       /* read stm32 device id register */
+       target_read_u32(target, 0xE0042000, &device_id);
+       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
+
+       /* get flash size from target */
+       if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)
+       {
+               /* failed reading flash size, default to max target family */
+               num_pages = 0xffff;
+       }
+
+       if ((device_id & 0x7ff) == 0x410)
+       {
+               /* medium density - we have 1k pages
+                * 4 pages for a protection area */
+               page_size = 1024;
+               stm32x_info->ppage_size = 4;
+
+               /* check for early silicon */
+               if (num_pages == 0xffff)
+               {
+                       /* number of sectors incorrect on revA */
+                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 128k flash");
+                       num_pages = 128;
+               }
+       }
+       else if ((device_id & 0x7ff) == 0x412)
+       {
+               /* low density - we have 1k pages
+                * 4 pages for a protection area */
+               page_size = 1024;
+               stm32x_info->ppage_size = 4;
+
+               /* check for early silicon */
+               if (num_pages == 0xffff)
+               {
+                       /* number of sectors incorrect on revA */
+                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 32k flash");
+                       num_pages = 32;
+               }
+       }
+       else if ((device_id & 0x7ff) == 0x414)
+       {
+               /* high density - we have 2k pages
+                * 2 pages for a protection area */
+               page_size = 2048;
+               stm32x_info->ppage_size = 2;
+
+               /* check for early silicon */
+               if (num_pages == 0xffff)
+               {
+                       /* number of sectors incorrect on revZ */
+                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 512k flash");
+                       num_pages = 512;
+               }
+       }
+       else if ((device_id & 0x7ff) == 0x418)
+       {
+               /* connectivity line density - we have 2k pages
+                * 2 pages for a protection area */
+               page_size = 2048;
+               stm32x_info->ppage_size = 2;
+
+               /* check for early silicon */
+               if (num_pages == 0xffff)
+               {
+                       /* number of sectors incorrect on revZ */
+                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 256k flash");
+                       num_pages = 256;
+               }
+       }
+       else
+       {
+               LOG_WARNING("Cannot identify target as a STM32 family.");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       LOG_INFO("flash size = %dkbytes", num_pages);
+
+       /* calculate numbers of pages */
+       num_pages /= (page_size / 1024);
+
+       bank->base = 0x08000000;
+       bank->size = (num_pages * page_size);
+       bank->num_sectors = num_pages;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+
+       for (i = 0; i < num_pages; i++)
+       {
+               bank->sectors[i].offset = i * page_size;
+               bank->sectors[i].size = page_size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 1;
+       }
+
+       stm32x_info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int stm32x_auto_probe(struct flash_bank *bank)
+{
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+       if (stm32x_info->probed)
+               return ERROR_OK;
+       return stm32x_probe(bank);
+}
+
+#if 0
+COMMAND_HANDLER(stm32x_handle_part_id_command)
+{
+       return ERROR_OK;
+}
+#endif
+
+static int stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct target *target = bank->target;
+       uint32_t device_id;
+       int printed;
+
+       /* read stm32 device id register */
+       target_read_u32(target, 0xE0042000, &device_id);
+
+       if ((device_id & 0x7ff) == 0x410)
+       {
+               printed = snprintf(buf, buf_size, "stm32x (Medium Density) - Rev: ");
+               buf += printed;
+               buf_size -= printed;
+
+               switch (device_id >> 16)
+               {
+                       case 0x0000:
+                               snprintf(buf, buf_size, "A");
+                               break;
+
+                       case 0x2000:
+                               snprintf(buf, buf_size, "B");
+                               break;
+
+                       case 0x2001:
+                               snprintf(buf, buf_size, "Z");
+                               break;
+
+                       case 0x2003:
+                               snprintf(buf, buf_size, "Y");
+                               break;
+
+                       default:
+                               snprintf(buf, buf_size, "unknown");
+                               break;
+               }
+       }
+       else if ((device_id & 0x7ff) == 0x412)
+       {
+               printed = snprintf(buf, buf_size, "stm32x (Low Density) - Rev: ");
+               buf += printed;
+               buf_size -= printed;
+
+               switch (device_id >> 16)
+               {
+                       case 0x1000:
+                               snprintf(buf, buf_size, "A");
+                               break;
+
+                       default:
+                               snprintf(buf, buf_size, "unknown");
+                               break;
+               }
+       }
+       else if ((device_id & 0x7ff) == 0x414)
+       {
+               printed = snprintf(buf, buf_size, "stm32x (High Density) - Rev: ");
+               buf += printed;
+               buf_size -= printed;
+
+               switch (device_id >> 16)
+               {
+                       case 0x1000:
+                               snprintf(buf, buf_size, "A");
+                               break;
+
+                       case 0x1001:
+                               snprintf(buf, buf_size, "Z");
+                               break;
+
+                       default:
+                               snprintf(buf, buf_size, "unknown");
+                               break;
+               }
+       }
+       else if ((device_id & 0x7ff) == 0x418)
+       {
+               printed = snprintf(buf, buf_size, "stm32x (Connectivity) - Rev: ");
+               buf += printed;
+               buf_size -= printed;
+
+               switch (device_id >> 16)
+               {
+                       case 0x1000:
+                               snprintf(buf, buf_size, "A");
+                               break;
+
+                       case 0x1001:
+                               snprintf(buf, buf_size, "Z");
+                               break;
+
+                       default:
+                               snprintf(buf, buf_size, "unknown");
+                               break;
+               }
+       }
+       else
+       {
+               snprintf(buf, buf_size, "Cannot identify target as a stm32x\n");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_lock_command)
+{
+       struct target *target = NULL;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "stm32x lock <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       stm32x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (stm32x_erase_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "stm32x failed to erase options");
+               return ERROR_OK;
+       }
+
+       /* set readout protection */
+       stm32x_info->option_bytes.RDP = 0;
+
+       if (stm32x_write_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "stm32x failed to lock device");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "stm32x locked");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_unlock_command)
+{
+       struct target *target = NULL;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "stm32x unlock <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       stm32x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (stm32x_erase_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "stm32x failed to unlock device");
+               return ERROR_OK;
+       }
+
+       if (stm32x_write_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "stm32x failed to lock device");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "stm32x unlocked");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_options_read_command)
+{
+       uint32_t optionbyte;
+       struct target *target = NULL;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "stm32x options_read <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       stm32x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       target_read_u32(target, STM32_FLASH_OBR, &optionbyte);
+       command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte);
+
+       if (buf_get_u32((uint8_t*)&optionbyte, OPT_ERROR, 1))
+               command_print(CMD_CTX, "Option Byte Complement Error");
+
+       if (buf_get_u32((uint8_t*)&optionbyte, OPT_READOUT, 1))
+               command_print(CMD_CTX, "Readout Protection On");
+       else
+               command_print(CMD_CTX, "Readout Protection Off");
+
+       if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDWDGSW, 1))
+               command_print(CMD_CTX, "Software Watchdog");
+       else
+               command_print(CMD_CTX, "Hardware Watchdog");
+
+       if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTOP, 1))
+               command_print(CMD_CTX, "Stop: No reset generated");
+       else
+               command_print(CMD_CTX, "Stop: Reset generated");
+
+       if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTDBY, 1))
+               command_print(CMD_CTX, "Standby: No reset generated");
+       else
+               command_print(CMD_CTX, "Standby: Reset generated");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_options_write_command)
+{
+       struct target *target = NULL;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+       uint16_t optionbyte = 0xF8;
+
+       if (CMD_ARGC < 4)
+       {
+               command_print(CMD_CTX, "stm32x options_write <bank> <SWWDG | HWWDG> <RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       stm32x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (strcmp(CMD_ARGV[1], "SWWDG") == 0)
+       {
+               optionbyte |= (1 << 0);
+       }
+       else
+       {
+               optionbyte &= ~(1 << 0);
+       }
+
+       if (strcmp(CMD_ARGV[2], "NORSTSTNDBY") == 0)
+       {
+               optionbyte |= (1 << 1);
+       }
+       else
+       {
+               optionbyte &= ~(1 << 1);
+       }
+
+       if (strcmp(CMD_ARGV[3], "NORSTSTOP") == 0)
+       {
+               optionbyte |= (1 << 2);
+       }
+       else
+       {
+               optionbyte &= ~(1 << 2);
+       }
+
+       if (stm32x_erase_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "stm32x failed to erase options");
+               return ERROR_OK;
+       }
+
+       stm32x_info->option_bytes.user_options = optionbyte;
+
+       if (stm32x_write_options(bank) != ERROR_OK)
+       {
+               command_print(CMD_CTX, "stm32x failed to write options");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "stm32x write options complete");
+
+       return ERROR_OK;
+}
+
+static int stm32x_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t status;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* unlock option flash registers */
+       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+
+       /* mass erase flash memory */
+       target_write_u32(target, STM32_FLASH_CR, FLASH_MER);
+       target_write_u32(target, STM32_FLASH_CR, FLASH_MER | FLASH_STRT);
+
+       status = stm32x_wait_status_busy(bank, 10);
+
+       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+
+       if (status & FLASH_WRPRTERR)
+       {
+               LOG_ERROR("stm32x device protected");
+               return ERROR_OK;
+       }
+
+       if (status & FLASH_PGERR)
+       {
+               LOG_ERROR("stm32x device programming failed");
+               return ERROR_OK;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_mass_erase_command)
+{
+       int i;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "stm32x mass_erase <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (stm32x_mass_erase(bank) == ERROR_OK)
+       {
+               /* set all sectors as erased */
+               for (i = 0; i < bank->num_sectors; i++)
+               {
+                       bank->sectors[i].is_erased = 1;
+               }
+
+               command_print(CMD_CTX, "stm32x mass erase complete");
+       }
+       else
+       {
+               command_print(CMD_CTX, "stm32x mass erase failed");
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration stm32x_exec_command_handlers[] = {
+       {
+               .name = "lock",
+               .handler = &stm32x_handle_lock_command,
+               .mode = COMMAND_EXEC,
+               .help = "lock device",
+       },
+       {
+               .name = "unlock",
+               .handler = &stm32x_handle_unlock_command,
+               .mode = COMMAND_EXEC,
+               .help = "unlock protected device",
+       },
+       {
+               .name = "mass_erase",
+               .handler = &stm32x_handle_mass_erase_command,
+               .mode = COMMAND_EXEC,
+               .help = "mass erase device",
+       },
+       {
+               .name = "options_read",
+               .handler = &stm32x_handle_options_read_command,
+               .mode = COMMAND_EXEC,
+               .help = "read device option bytes",
+       },
+       {
+               .name = "options_write",
+               .handler = &stm32x_handle_options_write_command,
+               .mode = COMMAND_EXEC,
+               .help = "write device option bytes",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration stm32x_command_handlers[] = {
+       {
+               .name = "stm32x",
+               .mode = COMMAND_ANY,
+               .help = "stm32x flash command group",
+               .chain = stm32x_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver stm32x_flash = {
+               .name = "stm32x",
+               .commands = stm32x_command_handlers,
+               .flash_bank_command = &stm32x_flash_bank_command,
+               .erase = &stm32x_erase,
+               .protect = &stm32x_protect,
+               .write = &stm32x_write,
+               .probe = &stm32x_probe,
+               .auto_probe = &stm32x_auto_probe,
+               .erase_check = &default_flash_mem_blank_check,
+               .protect_check = &stm32x_protect_check,
+               .info = &stm32x_info,
+       };
diff --git a/src/flash/nor/stm32x.h b/src/flash/nor/stm32x.h
new file mode 100644 (file)
index 0000000..6cd047e
--- /dev/null
@@ -0,0 +1,101 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef STM32X_H
+#define STM32X_H
+
+#include "flash.h"
+
+struct stm32x_options
+{
+       uint16_t RDP;
+       uint16_t user_options;
+       uint16_t protection[4];
+};
+
+struct stm32x_flash_bank
+{
+       struct stm32x_options option_bytes;
+       struct working_area *write_algorithm;
+       int ppage_size;
+       int probed;
+};
+
+/* stm32x register locations */
+
+#define STM32_FLASH_ACR                0x40022000
+#define STM32_FLASH_KEYR       0x40022004
+#define STM32_FLASH_OPTKEYR    0x40022008
+#define STM32_FLASH_SR         0x4002200C
+#define STM32_FLASH_CR         0x40022010
+#define STM32_FLASH_AR         0x40022014
+#define STM32_FLASH_OBR                0x4002201C
+#define STM32_FLASH_WRPR       0x40022020
+
+/* option byte location */
+
+#define STM32_OB_RDP           0x1FFFF800
+#define STM32_OB_USER          0x1FFFF802
+#define STM32_OB_DATA0         0x1FFFF804
+#define STM32_OB_DATA1         0x1FFFF806
+#define STM32_OB_WRP0          0x1FFFF808
+#define STM32_OB_WRP1          0x1FFFF80A
+#define STM32_OB_WRP2          0x1FFFF80C
+#define STM32_OB_WRP3          0x1FFFF80E
+
+/* FLASH_CR register bits */
+
+#define FLASH_PG               (1 << 0)
+#define FLASH_PER              (1 << 1)
+#define FLASH_MER              (1 << 2)
+#define FLASH_OPTPG            (1 << 4)
+#define FLASH_OPTER            (1 << 5)
+#define FLASH_STRT             (1 << 6)
+#define FLASH_LOCK             (1 << 7)
+#define FLASH_OPTWRE   (1 << 9)
+
+/* FLASH_SR register bits */
+
+#define FLASH_BSY              (1 << 0)
+#define FLASH_PGERR            (1 << 2)
+#define FLASH_WRPRTERR (1 << 4)
+#define FLASH_EOP              (1 << 5)
+
+/* STM32_FLASH_OBR bit definitions (reading) */
+
+#define OPT_ERROR              0
+#define OPT_READOUT            1
+#define OPT_RDWDGSW            2
+#define OPT_RDRSTSTOP  3
+#define OPT_RDRSTSTDBY 4
+
+/* register unlock keys */
+
+#define KEY1                   0x45670123
+#define KEY2                   0xCDEF89AB
+
+struct stm32x_mem_layout {
+       uint32_t sector_start;
+       uint32_t sector_size;
+};
+
+#endif /* STM32X_H */
diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c
new file mode 100644 (file)
index 0000000..7edffac
--- /dev/null
@@ -0,0 +1,706 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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 "str7x.h"
+#include "armv4_5.h"
+#include "binarybuffer.h"
+#include "algorithm.h"
+
+
+struct str7x_mem_layout mem_layout_str7bank0[] = {
+       {0x00000000, 0x02000, 0x01},
+       {0x00002000, 0x02000, 0x02},
+       {0x00004000, 0x02000, 0x04},
+       {0x00006000, 0x02000, 0x08},
+       {0x00008000, 0x08000, 0x10},
+       {0x00010000, 0x10000, 0x20},
+       {0x00020000, 0x10000, 0x40},
+       {0x00030000, 0x10000, 0x80}
+};
+
+struct str7x_mem_layout mem_layout_str7bank1[] = {
+       {0x00000000, 0x02000, 0x10000},
+       {0x00002000, 0x02000, 0x20000}
+};
+
+static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg)
+{
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+       return (str7x_info->register_base | reg);
+}
+
+static int str7x_build_block_list(struct flash_bank *bank)
+{
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+
+       int i;
+       int num_sectors;
+       int b0_sectors = 0, b1_sectors = 0;
+
+       switch (bank->size)
+       {
+               case 16 * 1024:
+                       b1_sectors = 2;
+                       break;
+               case 64 * 1024:
+                       b0_sectors = 5;
+                       break;
+               case 128 * 1024:
+                       b0_sectors = 6;
+                       break;
+               case 256 * 1024:
+                       b0_sectors = 8;
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown bank->size encountered");
+                       exit(-1);
+       }
+
+       num_sectors = b0_sectors + b1_sectors;
+
+       bank->num_sectors = num_sectors;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+       str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
+
+       num_sectors = 0;
+
+       for (i = 0; i < b0_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start;
+               bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit;
+       }
+
+       for (i = 0; i < b1_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start;
+               bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit;
+       }
+
+       return ERROR_OK;
+}
+
+/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
+ */
+FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command)
+{
+       struct str7x_flash_bank *str7x_info;
+
+       if (CMD_ARGC < 7)
+       {
+               LOG_WARNING("incomplete flash_bank str7x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       str7x_info = malloc(sizeof(struct str7x_flash_bank));
+       bank->driver_priv = str7x_info;
+
+       /* set default bits for str71x flash */
+       str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
+       str7x_info->disable_bit = (1 << 1);
+
+       if (strcmp(CMD_ARGV[6], "STR71x") == 0)
+       {
+               str7x_info->register_base = 0x40100000;
+       }
+       else if (strcmp(CMD_ARGV[6], "STR73x") == 0)
+       {
+               str7x_info->register_base = 0x80100000;
+               str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
+       }
+       else if (strcmp(CMD_ARGV[6], "STR75x") == 0)
+       {
+               str7x_info->register_base = 0x20100000;
+               str7x_info->disable_bit = (1 << 0);
+       }
+       else
+       {
+               LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]);
+               free(str7x_info);
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       str7x_build_block_list(bank);
+
+       str7x_info->write_algorithm = NULL;
+
+       return ERROR_OK;
+}
+
+static uint32_t str7x_status(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t retval;
+
+       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
+
+       return retval;
+}
+
+static uint32_t str7x_result(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t retval;
+
+       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
+
+       return retval;
+}
+
+static int str7x_protect_check(struct flash_bank *bank)
+{
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       int i;
+       uint32_t retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &retval);
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               if (retval & str7x_info->sector_bits[i])
+                       bank->sectors[i].is_protected = 0;
+               else
+                       bank->sectors[i].is_protected = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int str7x_erase(struct flash_bank *bank, int first, int last)
+{
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       int i;
+       uint32_t cmd;
+       uint32_t retval;
+       uint32_t sectors = 0;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       for (i = first; i <= last; i++)
+       {
+               sectors |= str7x_info->sector_bits[i];
+       }
+
+       LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors);
+
+       /* clear FLASH_ER register */
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
+
+       cmd = FLASH_SER;
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+       cmd = sectors;
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
+
+       cmd = FLASH_SER | FLASH_WMS;
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+       while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
+               alive_sleep(1);
+       }
+
+       retval = str7x_result(bank);
+
+       if (retval)
+       {
+               LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32 "", retval);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       for (i = first; i <= last; i++)
+               bank->sectors[i].is_erased = 1;
+
+       return ERROR_OK;
+}
+
+static int str7x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       int i;
+       uint32_t cmd;
+       uint32_t retval;
+       uint32_t protect_blocks;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       protect_blocks = 0xFFFFFFFF;
+
+       if (set)
+       {
+               for (i = first; i <= last; i++)
+                       protect_blocks &= ~(str7x_info->sector_bits[i]);
+       }
+
+       /* clear FLASH_ER register */
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
+
+       cmd = FLASH_SPR;
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+       cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
+
+       cmd = protect_blocks;
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
+
+       cmd = FLASH_SPR | FLASH_WMS;
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+       while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
+               alive_sleep(1);
+       }
+
+       retval = str7x_result(bank);
+
+       LOG_DEBUG("retval: 0x%8.8" PRIx32 "", retval);
+
+       if (retval & FLASH_ERER)
+               return ERROR_FLASH_SECTOR_NOT_ERASED;
+       else if (retval & FLASH_WPF)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       return ERROR_OK;
+}
+
+static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 8192;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[6];
+       struct armv4_5_algorithm armv4_5_info;
+       int retval = ERROR_OK;
+
+       uint32_t str7x_flash_write_code[] = {
+                                       /* write:                               */
+               0xe3a04201, /*  mov r4, #0x10000000     */
+               0xe5824000, /*  str r4, [r2, #0x0]      */
+               0xe5821010, /*  str r1, [r2, #0x10]     */
+               0xe4904004, /*  ldr r4, [r0], #4        */
+               0xe5824008, /*  str r4, [r2, #0x8]      */
+               0xe4904004, /*  ldr r4, [r0], #4        */
+               0xe582400c, /*  str r4, [r2, #0xc]      */
+               0xe3a04209, /*  mov r4, #0x90000000     */
+               0xe5824000, /*  str r4, [r2, #0x0]      */
+                           /* busy:                            */
+               0xe5924000, /*  ldr r4, [r2, #0x0]      */
+               0xe1140005,     /*      tst r4, r5                      */
+               0x1afffffc, /*  bne busy                        */
+               0xe5924014, /*  ldr r4, [r2, #0x14]     */
+               0xe31400ff, /*  tst r4, #0xff           */
+               0x03140c01, /*  tsteq r4, #0x100        */
+               0x1a000002, /*  bne exit                        */
+               0xe2811008, /*  add r1, r1, #0x8        */
+               0xe2533001, /*  subs r3, r3, #1         */
+               0x1affffec, /*  bne write                       */
+                                       /* exit:                                */
+               0xeafffffe, /*  b exit                          */
+       };
+
+       /* flash write code */
+       if (target_alloc_working_area(target, 4 * 20, &str7x_info->write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (uint8_t*)str7x_flash_write_code);
+
+       /* 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 (str7x_info->write_algorithm)
+                               target_free_working_area(target, str7x_info->write_algorithm);
+
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
+
+       while (count > 0)
+       {
+               uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
+
+               target_write_buffer(target, source->address, thisrun_count * 8, buffer);
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
+               buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
+               buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
+
+               if ((retval = target_run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing str7x flash write algorithm");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
+               {
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer += thisrun_count * 8;
+               address += thisrun_count * 8;
+               count -= thisrun_count;
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, str7x_info->write_algorithm);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+
+       return retval;
+}
+
+static int str7x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct str7x_flash_bank *str7x_info = bank->driver_priv;
+       uint32_t dwords_remaining = (count / 8);
+       uint32_t bytes_remaining = (count & 0x00000007);
+       uint32_t address = bank->base + offset;
+       uint32_t bytes_written = 0;
+       uint32_t cmd;
+       int retval;
+       uint32_t check_address = offset;
+       int i;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x7)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint32_t sec_start = bank->sectors[i].offset;
+               uint32_t sec_end = sec_start + bank->sectors[i].size;
+
+               /* check if destination falls within the current sector */
+               if ((check_address >= sec_start) && (check_address < sec_end))
+               {
+                       /* check if destination ends in the current sector */
+                       if (offset + count < sec_end)
+                               check_address = offset + count;
+                       else
+                               check_address = sec_end;
+               }
+       }
+
+       if (check_address != offset + count)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       /* clear FLASH_ER register */
+       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
+
+       /* multiple dwords (8-byte) to be programmed? */
+       if (dwords_remaining > 0)
+       {
+               /* try using a block write */
+               if ((retval = str7x_write_block(bank, buffer, offset, dwords_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */
+                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
+                       {
+                               /* if an error occured, we examine the reason, and quit */
+                               retval = str7x_result(bank);
+
+                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       buffer += dwords_remaining * 8;
+                       address += dwords_remaining * 8;
+                       dwords_remaining = 0;
+               }
+       }
+
+       while (dwords_remaining > 0)
+       {
+               /* command */
+               cmd = FLASH_DWPG;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+               /* address */
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
+
+               /* data word 1 */
+               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
+               bytes_written += 4;
+
+               /* data word 2 */
+               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
+               bytes_written += 4;
+
+               /* start programming cycle */
+               cmd = FLASH_DWPG | FLASH_WMS;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+               while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
+               {
+                       alive_sleep(1);
+               }
+
+               retval = str7x_result(bank);
+
+               if (retval & FLASH_PGER)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               else if (retval & FLASH_WPF)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               dwords_remaining--;
+               address += 8;
+       }
+
+       if (bytes_remaining)
+       {
+               uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+               int i = 0;
+
+               while (bytes_remaining > 0)
+               {
+                       last_dword[i++] = *(buffer + bytes_written);
+                       bytes_remaining--;
+                       bytes_written++;
+               }
+
+               /* command */
+               cmd = FLASH_DWPG;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+               /* address */
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
+
+               /* data word 1 */
+               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
+               bytes_written += 4;
+
+               /* data word 2 */
+               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
+               bytes_written += 4;
+
+               /* start programming cycle */
+               cmd = FLASH_DWPG | FLASH_WMS;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+               while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
+               {
+                       alive_sleep(1);
+               }
+
+               retval = str7x_result(bank);
+
+               if (retval & FLASH_PGER)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               else if (retval & FLASH_WPF)
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int str7x_probe(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+#if 0
+COMMAND_HANDLER(str7x_handle_part_id_command)
+{
+       return ERROR_OK;
+}
+#endif
+
+static int str7x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "str7x flash driver info");
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str7x_handle_disable_jtag_command)
+{
+       struct target *target = NULL;
+       struct str7x_flash_bank *str7x_info = NULL;
+
+       uint32_t flash_cmd;
+       uint16_t ProtectionLevel = 0;
+       uint16_t ProtectionRegs;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str7x disable_jtag <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str7x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* first we get protection status */
+       uint32_t reg;
+       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &reg);
+
+       if (!(reg & str7x_info->disable_bit))
+       {
+               ProtectionLevel = 1;
+       }
+
+       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &reg);
+       ProtectionRegs = ~(reg >> 16);
+
+       while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))
+       {
+               ProtectionRegs >>= 1;
+               ProtectionLevel++;
+       }
+
+       if (ProtectionLevel == 0)
+       {
+               flash_cmd = FLASH_SPR;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);
+               flash_cmd = FLASH_SPR | FLASH_WMS;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+       }
+       else
+       {
+               flash_cmd = FLASH_SPR;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1 << (15 + ProtectionLevel)));
+               flash_cmd = FLASH_SPR | FLASH_WMS;
+               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration str7x_exec_command_handlers[] = {
+       {
+               .name = "disable_jtag",
+               .handler = &str7x_handle_disable_jtag_command,
+               .mode = COMMAND_EXEC,
+               .help = "disable jtag access",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration str7x_command_handlers[] = {
+       {
+               .name = "str7x",
+               .mode = COMMAND_ANY,
+               .help = "str7x flash command group",
+               .chain = str7x_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver str7x_flash = {
+               .name = "str7x",
+               .commands = str7x_command_handlers,
+               .flash_bank_command = &str7x_flash_bank_command,
+               .erase = &str7x_erase,
+               .protect = &str7x_protect,
+               .write = &str7x_write,
+               .probe = &str7x_probe,
+               .auto_probe = &str7x_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &str7x_protect_check,
+               .info = &str7x_info,
+       };
diff --git a/src/flash/nor/str7x.h b/src/flash/nor/str7x.h
new file mode 100644 (file)
index 0000000..81af0f1
--- /dev/null
@@ -0,0 +1,110 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef STR7X_H
+#define STR7X_H
+
+#include "flash.h"
+
+struct str7x_flash_bank
+{
+       uint32_t *sector_bits;
+       uint32_t disable_bit;
+       uint32_t busy_bits;
+       uint32_t register_base;
+       struct working_area *write_algorithm;
+};
+
+enum str7x_status_codes
+{
+       STR7X_CMD_SUCCESS = 0,
+       STR7X_INVALID_COMMAND = 1,
+       STR7X_SRC_ADDR_ERROR = 2,
+       STR7X_DST_ADDR_ERROR = 3,
+       STR7X_SRC_ADDR_NOT_MAPPED = 4,
+       STR7X_DST_ADDR_NOT_MAPPED = 5,
+       STR7X_COUNT_ERROR = 6,
+       STR7X_INVALID_SECTOR = 7,
+       STR7X_SECTOR_NOT_BLANK = 8,
+       STR7X_SECTOR_NOT_PREPARED = 9,
+       STR7X_COMPARE_ERROR = 10,
+       STR7X_BUSY = 11
+};
+
+/*  Flash registers */
+
+#define FLASH_CR0              0x00000000
+#define FLASH_CR1              0x00000004
+#define FLASH_DR0              0x00000008
+#define FLASH_DR1              0x0000000C
+#define FLASH_AR               0x00000010
+#define FLASH_ER               0x00000014
+#define FLASH_NVWPAR   0x0000DFB0
+#define FLASH_NVAPR0   0x0000DFB8
+#define FLASH_NVAPR1   0x0000DFBC
+
+/* FLASH_CR0 register bits */
+
+#define FLASH_WMS              0x80000000
+#define FLASH_SUSP             0x40000000
+#define FLASH_WPG              0x20000000
+#define FLASH_DWPG             0x10000000
+#define FLASH_SER              0x08000000
+#define FLASH_SPR              0x01000000
+#define FLASH_BER              0x04000000
+#define FLASH_MER              0x02000000
+#define FLASH_LOCK             0x00000010
+#define FLASH_BSYA1            0x00000004
+#define FLASH_BSYA0            0x00000002
+
+/* FLASH_CR1 register bits */
+
+#define FLASH_B1S              0x02000000
+#define FLASH_B0S              0x01000000
+#define FLASH_B1F1             0x00020000
+#define FLASH_B1F0             0x00010000
+#define FLASH_B0F7             0x00000080
+#define FLASH_B0F6             0x00000040
+#define FLASH_B0F5             0x00000020
+#define FLASH_B0F4             0x00000010
+#define FLASH_B0F3             0x00000008
+#define FLASH_B0F2             0x00000004
+#define FLASH_B0F1             0x00000002
+#define FLASH_B0F0             0x00000001
+
+/* FLASH_ER register bits */
+
+#define FLASH_WPF              0x00000100
+#define FLASH_RESER            0x00000080
+#define FLASH_SEQER            0x00000040
+#define FLASH_10ER             0x00000008
+#define FLASH_PGER             0x00000004
+#define FLASH_ERER             0x00000002
+#define FLASH_ERR              0x00000001
+
+struct str7x_mem_layout {
+       uint32_t sector_start;
+       uint32_t sector_size;
+       uint32_t sector_bit;
+};
+
+#endif /* STR7X_H */
diff --git a/src/flash/nor/str9x.c b/src/flash/nor/str9x.c
new file mode 100644 (file)
index 0000000..98f15e7
--- /dev/null
@@ -0,0 +1,711 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *
+ *   Copyright (C) 2008 by Oyvind Harboe                                   *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
+ *   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 "str9x.h"
+#include "arm966e.h"
+#include "algorithm.h"
+
+
+static uint32_t bank1start = 0x00080000;
+
+static int str9x_build_block_list(struct flash_bank *bank)
+{
+       struct str9x_flash_bank *str9x_info = bank->driver_priv;
+
+       int i;
+       int num_sectors;
+       int b0_sectors = 0, b1_sectors = 0;
+       uint32_t offset = 0;
+
+       /* set if we have large flash str9 */
+       str9x_info->variant = 0;
+       str9x_info->bank1 = 0;
+
+       switch (bank->size)
+       {
+               case (256 * 1024):
+                       b0_sectors = 4;
+                       break;
+               case (512 * 1024):
+                       b0_sectors = 8;
+                       break;
+               case (1024 * 1024):
+                       bank1start = 0x00100000;
+                       str9x_info->variant = 1;
+                       b0_sectors = 16;
+                       break;
+               case (2048 * 1024):
+                       bank1start = 0x00200000;
+                       str9x_info->variant = 1;
+                       b0_sectors = 32;
+                       break;
+               case (128 * 1024):
+                       str9x_info->variant = 1;
+                       str9x_info->bank1 = 1;
+                       b1_sectors = 8;
+                       bank1start = bank->base;
+                       break;
+               case (32 * 1024):
+                       str9x_info->bank1 = 1;
+                       b1_sectors = 4;
+                       bank1start = bank->base;
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown bank->size encountered");
+                       exit(-1);
+       }
+
+       num_sectors = b0_sectors + b1_sectors;
+
+       bank->num_sectors = num_sectors;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+       str9x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
+
+       num_sectors = 0;
+
+       for (i = 0; i < b0_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = offset;
+               bank->sectors[num_sectors].size = 0x10000;
+               offset += bank->sectors[i].size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str9x_info->sector_bits[num_sectors++] = (1 << i);
+       }
+
+       for (i = 0; i < b1_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = offset;
+               bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000;
+               offset += bank->sectors[i].size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               if (str9x_info->variant)
+                       str9x_info->sector_bits[num_sectors++] = (1 << i);
+               else
+                       str9x_info->sector_bits[num_sectors++] = (1 << (i + 8));
+       }
+
+       return ERROR_OK;
+}
+
+/* flash bank str9x <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command)
+{
+       struct str9x_flash_bank *str9x_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank str9x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       str9x_info = malloc(sizeof(struct str9x_flash_bank));
+       bank->driver_priv = str9x_info;
+
+       str9x_build_block_list(bank);
+
+       str9x_info->write_algorithm = NULL;
+
+       return ERROR_OK;
+}
+
+static int str9x_protect_check(struct flash_bank *bank)
+{
+       int retval;
+       struct str9x_flash_bank *str9x_info = bank->driver_priv;
+       struct target *target = bank->target;
+
+       int i;
+       uint32_t adr;
+       uint32_t status = 0;
+       uint16_t hstatus = 0;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* read level one protection */
+
+       if (str9x_info->variant)
+       {
+               if (str9x_info->bank1)
+               {
+                       adr = bank1start + 0x18;
+                       if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       status = hstatus;
+               }
+               else
+               {
+                       adr = bank1start + 0x14;
+                       if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if ((retval = target_read_u32(target, adr, &status)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+               }
+       }
+       else
+       {
+               adr = bank1start + 0x10;
+               if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               status = hstatus;
+       }
+
+       /* read array command */
+       if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               if (status & str9x_info->sector_bits[i])
+                       bank->sectors[i].is_protected = 1;
+               else
+                       bank->sectors[i].is_protected = 0;
+       }
+
+       return ERROR_OK;
+}
+
+static int str9x_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       int i;
+       uint32_t adr;
+       uint8_t status;
+       uint8_t erase_cmd;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Check if we erase whole bank */
+       if ((first == 0) && (last == (bank->num_sectors - 1)))
+       {
+               /* Optimize to run erase bank command instead of sector */
+               erase_cmd = 0x80;
+       }
+       else
+       {
+               /* Erase sector command */
+               erase_cmd = 0x20;
+       }
+
+       for (i = first; i <= last; i++)
+       {
+               int retval;
+               adr = bank->base + bank->sectors[i].offset;
+
+               /* erase sectors */
+               if ((retval = target_write_u16(target, adr, erase_cmd)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               if ((retval = target_write_u16(target, adr, 0xD0)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               /* get status */
+               if ((retval = target_write_u16(target, adr, 0x70)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               int timeout;
+               for (timeout = 0; timeout < 1000; timeout++) {
+                       if ((retval = target_read_u8(target, adr, &status)) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if (status & 0x80)
+                               break;
+                       alive_sleep(1);
+               }
+               if (timeout == 1000)
+               {
+                       LOG_ERROR("erase timed out");
+                       return ERROR_FAIL;
+               }
+
+               /* clear status, also clear read array */
+               if ((retval = target_write_u16(target, adr, 0x50)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               /* read array command */
+               if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
+               {
+                       return retval;
+               }
+
+               if (status & 0x22)
+               {
+                       LOG_ERROR("error erasing flash bank, status: 0x%x", status);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+
+               /* If we ran erase bank command, we are finished */
+               if (erase_cmd == 0x80)
+                       break;
+       }
+
+       for (i = first; i <= last; i++)
+               bank->sectors[i].is_erased = 1;
+
+       return ERROR_OK;
+}
+
+static int str9x_protect(struct flash_bank *bank,
+               int set, int first, int last)
+{
+       struct target *target = bank->target;
+       int i;
+       uint32_t adr;
+       uint8_t status;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       for (i = first; i <= last; i++)
+       {
+               /* Level One Protection */
+
+               adr = bank->base + bank->sectors[i].offset;
+
+               target_write_u16(target, adr, 0x60);
+               if (set)
+                       target_write_u16(target, adr, 0x01);
+               else
+                       target_write_u16(target, adr, 0xD0);
+
+               /* query status */
+               target_read_u8(target, adr, &status);
+
+               /* clear status, also clear read array */
+               target_write_u16(target, adr, 0x50);
+
+               /* read array command */
+               target_write_u16(target, adr, 0xFF);
+       }
+
+       return ERROR_OK;
+}
+
+static int str9x_write_block(struct flash_bank *bank,
+               uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct str9x_flash_bank *str9x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 8192;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[4];
+       struct armv4_5_algorithm armv4_5_info;
+       int retval = ERROR_OK;
+
+       uint32_t str9x_flash_write_code[] = {
+                                       /* write:                               */
+               0xe3c14003,     /*      bic     r4, r1, #3              */
+               0xe3a03040,     /*      mov     r3, #0x40               */
+               0xe1c430b0,     /*      strh r3, [r4, #0]       */
+               0xe0d030b2,     /*      ldrh r3, [r0], #2       */
+               0xe0c130b2,     /*      strh r3, [r1], #2       */
+               0xe3a03070,     /*      mov r3, #0x70           */
+               0xe1c430b0,     /*      strh r3, [r4, #0]       */
+                                       /* busy:                                */
+               0xe5d43000,     /*      ldrb r3, [r4, #0]       */
+               0xe3130080,     /*      tst r3, #0x80           */
+               0x0afffffc,     /*      beq busy                        */
+               0xe3a05050,     /*      mov     r5, #0x50               */
+               0xe1c450b0,     /*      strh r5, [r4, #0]       */
+               0xe3a050ff,     /*      mov     r5, #0xFF               */
+               0xe1c450b0,     /*      strh r5, [r4, #0]       */
+               0xe3130012,     /*      tst     r3, #0x12               */
+               0x1a000001,     /*      bne exit                        */
+               0xe2522001,     /*      subs r2, r2, #1         */
+               0x1affffed,     /*      bne write                       */
+                                       /* exit:                                */
+               0xeafffffe,     /*      b exit                          */
+       };
+
+       /* flash write code */
+       if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (uint8_t*)str9x_flash_write_code);
+
+       /* 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 (str9x_info->write_algorithm)
+                               target_free_working_area(target, str9x_info->write_algorithm);
+
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
+
+       while (count > 0)
+       {
+               uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+
+               target_write_buffer(target, source->address, thisrun_count * 2, buffer);
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+
+               if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing str9x flash write algorithm");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
+               {
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer += thisrun_count * 2;
+               address += thisrun_count * 2;
+               count -= thisrun_count;
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, str9x_info->write_algorithm);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+
+       return retval;
+}
+
+static int str9x_write(struct flash_bank *bank,
+               uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       uint32_t words_remaining = (count / 2);
+       uint32_t bytes_remaining = (count & 0x00000001);
+       uint32_t address = bank->base + offset;
+       uint32_t bytes_written = 0;
+       uint8_t status;
+       int retval;
+       uint32_t check_address = offset;
+       uint32_t bank_adr;
+       int i;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x1)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint32_t sec_start = bank->sectors[i].offset;
+               uint32_t sec_end = sec_start + bank->sectors[i].size;
+
+               /* check if destination falls within the current sector */
+               if ((check_address >= sec_start) && (check_address < sec_end))
+               {
+                       /* check if destination ends in the current sector */
+                       if (offset + count < sec_end)
+                               check_address = offset + count;
+                       else
+                               check_address = sec_end;
+               }
+       }
+
+       if (check_address != offset + count)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       /* multiple half words (2-byte) to be programmed? */
+       if (words_remaining > 0)
+       {
+               /* try using a block write */
+               if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */
+                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
+                       {
+                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       buffer += words_remaining * 2;
+                       address += words_remaining * 2;
+                       words_remaining = 0;
+               }
+       }
+
+       while (words_remaining > 0)
+       {
+               bank_adr = address & ~0x03;
+
+               /* write data command */
+               target_write_u16(target, bank_adr, 0x40);
+               target_write_memory(target, address, 2, 1, buffer + bytes_written);
+
+               /* get status command */
+               target_write_u16(target, bank_adr, 0x70);
+
+               int timeout;
+               for (timeout = 0; timeout < 1000; timeout++)
+               {
+                       target_read_u8(target, bank_adr, &status);
+                       if (status & 0x80)
+                               break;
+                       alive_sleep(1);
+               }
+               if (timeout == 1000)
+               {
+                       LOG_ERROR("write timed out");
+                       return ERROR_FAIL;
+               }
+
+               /* clear status reg and read array */
+               target_write_u16(target, bank_adr, 0x50);
+               target_write_u16(target, bank_adr, 0xFF);
+
+               if (status & 0x10)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               else if (status & 0x02)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               bytes_written += 2;
+               words_remaining--;
+               address += 2;
+       }
+
+       if (bytes_remaining)
+       {
+               uint8_t last_halfword[2] = {0xff, 0xff};
+               int i = 0;
+
+               while (bytes_remaining > 0)
+               {
+                       last_halfword[i++] = *(buffer + bytes_written);
+                       bytes_remaining--;
+                       bytes_written++;
+               }
+
+               bank_adr = address & ~0x03;
+
+               /* write data command */
+               target_write_u16(target, bank_adr, 0x40);
+               target_write_memory(target, address, 2, 1, last_halfword);
+
+               /* query status command */
+               target_write_u16(target, bank_adr, 0x70);
+
+               int timeout;
+               for (timeout = 0; timeout < 1000; timeout++)
+               {
+                       target_read_u8(target, bank_adr, &status);
+                       if (status & 0x80)
+                               break;
+                       alive_sleep(1);
+               }
+               if (timeout == 1000)
+               {
+                       LOG_ERROR("write timed out");
+                       return ERROR_FAIL;
+               }
+
+               /* clear status reg and read array */
+               target_write_u16(target, bank_adr, 0x50);
+               target_write_u16(target, bank_adr, 0xFF);
+
+               if (status & 0x10)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               else if (status & 0x02)
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int str9x_probe(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+#if 0
+COMMAND_HANDLER(str9x_handle_part_id_command)
+{
+       return ERROR_OK;
+}
+#endif
+
+static int str9x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "str9x flash driver info");
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9x_handle_flash_config_command)
+{
+       struct str9x_flash_bank *str9x_info;
+       struct target *target = NULL;
+
+       if (CMD_ARGC < 5)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       uint32_t bbsr, nbbsr, bbadr, nbbadr;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], bbsr);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], nbbsr);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], bbadr);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], nbbadr);
+
+       str9x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* config flash controller */
+       target_write_u32(target, FLASH_BBSR, bbsr);
+       target_write_u32(target, FLASH_NBBSR, nbbsr);
+       target_write_u32(target, FLASH_BBADR, bbadr >> 2);
+       target_write_u32(target, FLASH_NBBADR, nbbadr >> 2);
+
+       /* set bit 18 instruction TCM order as per flash programming manual */
+       arm966e_write_cp15(target, 62, 0x40000);
+
+       /* enable flash bank 1 */
+       target_write_u32(target, FLASH_CR, 0x18);
+       return ERROR_OK;
+}
+
+static const struct command_registration str9x_config_command_handlers[] = {
+       {
+               .name = "disable_jtag",
+               .handler = &str9x_handle_flash_config_command,
+               .mode = COMMAND_EXEC,
+               .help = "configure str9x flash controller",
+               .usage = "<bank_id> <BBSR> <NBBSR> <BBADR> <NBBADR>",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration str9x_command_handlers[] = {
+       {
+               .name = "str9x",
+               .mode = COMMAND_ANY,
+               .help = "str9x flash command group",
+               .chain = str9x_config_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver str9x_flash = {
+               .name = "str9x",
+               .commands = str9x_command_handlers,
+               .flash_bank_command = &str9x_flash_bank_command,
+               .erase = &str9x_erase,
+               .protect = &str9x_protect,
+               .write = &str9x_write,
+               .probe = &str9x_probe,
+               .auto_probe = &str9x_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &str9x_protect_check,
+               .info = &str9x_info,
+       };
diff --git a/src/flash/nor/str9x.h b/src/flash/nor/str9x.h
new file mode 100644 (file)
index 0000000..c9d5152
--- /dev/null
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef STR9X_H
+#define STR9X_H
+
+#include "flash.h"
+
+struct str9x_flash_bank
+{
+       uint32_t *sector_bits;
+       int variant;
+       int bank1;
+       struct working_area *write_algorithm;
+};
+
+enum str9x_status_codes
+{
+       STR9X_CMD_SUCCESS = 0,
+       STR9X_INVALID_COMMAND = 1,
+       STR9X_SRC_ADDR_ERROR = 2,
+       STR9X_DST_ADDR_ERROR = 3,
+       STR9X_SRC_ADDR_NOT_MAPPED = 4,
+       STR9X_DST_ADDR_NOT_MAPPED = 5,
+       STR9X_COUNT_ERROR = 6,
+       STR9X_INVALID_SECTOR = 7,
+       STR9X_SECTOR_NOT_BLANK = 8,
+       STR9X_SECTOR_NOT_PREPARED = 9,
+       STR9X_COMPARE_ERROR = 10,
+       STR9X_BUSY = 11
+};
+
+/* Flash registers */
+
+#define FLASH_BBSR             0x54000000              /* Boot Bank Size Register                */
+#define FLASH_NBBSR            0x54000004              /* Non-Boot Bank Size Register            */
+#define FLASH_BBADR            0x5400000C              /* Boot Bank Base Address Register        */
+#define FLASH_NBBADR   0x54000010              /* Non-Boot Bank Base Address Register    */
+#define FLASH_CR               0x54000018              /* Control Register                       */
+#define FLASH_SR               0x5400001C              /* Status Register                        */
+#define FLASH_BCE5ADDR 0x54000020              /* BC Fifth Entry Target Address Register */
+
+#endif /* STR9X_H */
diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c
new file mode 100644 (file)
index 0000000..96e1259
--- /dev/null
@@ -0,0 +1,1257 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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 "str9xpec.h"
+#include "arm7_9_common.h"
+
+
+static int str9xpec_erase_area(struct flash_bank *bank, int first, int last);
+static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector);
+static int str9xpec_write_options(struct flash_bank *bank);
+
+int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state)
+{
+       if (tap == NULL) {
+               return ERROR_TARGET_INVALID;
+       }
+
+       if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr)
+       {
+               struct scan_field field;
+
+               field.tap = tap;
+               field.num_bits = tap->ir_length;
+               field.out_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+               buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
+               field.in_value = NULL;
+
+               jtag_add_ir_scan(1, &field, end_state);
+
+               free(field.out_value);
+       }
+
+       return ERROR_OK;
+}
+
+static uint8_t str9xpec_isc_status(struct jtag_tap *tap)
+{
+       struct scan_field field;
+       uint8_t status;
+
+       if (str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE) != ERROR_OK)
+               return ISC_STATUS_ERROR;
+
+       field.tap = tap;
+       field.num_bits = 8;
+       field.out_value = NULL;
+       field.in_value = &status;
+
+
+       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+       jtag_execute_queue();
+
+       LOG_DEBUG("status: 0x%2.2x", status);
+
+       if (status & ISC_STATUS_SECURITY)
+               LOG_INFO("Device Security Bit Set");
+
+       return status;
+}
+
+static int str9xpec_isc_enable(struct flash_bank *bank)
+{
+       uint8_t status;
+       struct jtag_tap *tap;
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       tap = str9xpec_info->tap;
+
+       if (str9xpec_info->isc_enable)
+               return ERROR_OK;
+
+       /* enter isc mode */
+       if (str9xpec_set_instr(tap, ISC_ENABLE, TAP_IDLE) != ERROR_OK)
+               return ERROR_TARGET_INVALID;
+
+       /* check ISC status */
+       status = str9xpec_isc_status(tap);
+       if (status & ISC_STATUS_MODE)
+       {
+               /* we have entered isc mode */
+               str9xpec_info->isc_enable = 1;
+               LOG_DEBUG("ISC_MODE Enabled");
+       }
+
+       return ERROR_OK;
+}
+
+static int str9xpec_isc_disable(struct flash_bank *bank)
+{
+       uint8_t status;
+       struct jtag_tap *tap;
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       tap = str9xpec_info->tap;
+
+       if (!str9xpec_info->isc_enable)
+               return ERROR_OK;
+
+       if (str9xpec_set_instr(tap, ISC_DISABLE, TAP_IDLE) != ERROR_OK)
+               return ERROR_TARGET_INVALID;
+
+       /* delay to handle aborts */
+       jtag_add_sleep(50);
+
+       /* check ISC status */
+       status = str9xpec_isc_status(tap);
+       if (!(status & ISC_STATUS_MODE))
+       {
+               /* we have left isc mode */
+               str9xpec_info->isc_enable = 0;
+               LOG_DEBUG("ISC_MODE Disabled");
+       }
+
+       return ERROR_OK;
+}
+
+static int str9xpec_read_config(struct flash_bank *bank)
+{
+       struct scan_field field;
+       uint8_t status;
+       struct jtag_tap *tap;
+
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       tap = str9xpec_info->tap;
+
+       LOG_DEBUG("ISC_CONFIGURATION");
+
+       /* execute ISC_CONFIGURATION command */
+       str9xpec_set_instr(tap, ISC_CONFIGURATION, TAP_IRPAUSE);
+
+       field.tap = tap;
+       field.num_bits = 64;
+       field.out_value = NULL;
+       field.in_value = str9xpec_info->options;
+
+
+       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+       jtag_execute_queue();
+
+       status = str9xpec_isc_status(tap);
+
+       return status;
+}
+
+static int str9xpec_build_block_list(struct flash_bank *bank)
+{
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       int i;
+       int num_sectors;
+       int b0_sectors = 0, b1_sectors = 0;
+       uint32_t offset = 0;
+       int b1_size = 0x2000;
+
+       switch (bank->size)
+       {
+               case (256 * 1024):
+                       b0_sectors = 4;
+                       break;
+               case (512 * 1024):
+                       b0_sectors = 8;
+                       break;
+               case (1024 * 1024):
+                       b0_sectors = 16;
+                       break;
+               case (2048 * 1024):
+                       b0_sectors = 32;
+                       break;
+               case (128 * 1024):
+                       b1_size = 0x4000;
+                       b1_sectors = 8;
+                       break;
+               case (32 * 1024):
+                       b1_sectors = 4;
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown bank->size encountered");
+                       exit(-1);
+       }
+
+       num_sectors = b0_sectors + b1_sectors;
+
+       bank->num_sectors = num_sectors;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+       str9xpec_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
+
+       num_sectors = 0;
+
+       for (i = 0; i < b0_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = offset;
+               bank->sectors[num_sectors].size = 0x10000;
+               offset += bank->sectors[i].size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str9xpec_info->sector_bits[num_sectors++] = i;
+       }
+
+       for (i = 0; i < b1_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = offset;
+               bank->sectors[num_sectors].size = b1_size;
+               offset += bank->sectors[i].size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str9xpec_info->sector_bits[num_sectors++] = i + 32;
+       }
+
+       return ERROR_OK;
+}
+
+/* flash bank str9x <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(str9xpec_flash_bank_command)
+{
+       struct str9xpec_flash_controller *str9xpec_info;
+       struct arm *armv4_5 = NULL;
+       struct arm7_9_common *arm7_9 = NULL;
+       struct arm_jtag *jtag_info = NULL;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank str9x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       str9xpec_info = malloc(sizeof(struct str9xpec_flash_controller));
+       bank->driver_priv = str9xpec_info;
+
+       /* REVISIT verify that the jtag position of flash controller is
+        * right after *THIS* core, which must be a STR9xx core ...
+        */
+       armv4_5 = bank->target->arch_info;
+       arm7_9 = armv4_5->arch_info;
+       jtag_info = &arm7_9->jtag_info;
+
+       str9xpec_info->tap = bank->target->tap;
+       str9xpec_info->isc_enable = 0;
+
+       str9xpec_build_block_list(bank);
+
+       /* clear option byte register */
+       buf_set_u32(str9xpec_info->options, 0, 64, 0);
+
+       return ERROR_OK;
+}
+
+static int str9xpec_blank_check(struct flash_bank *bank, int first, int last)
+{
+       struct scan_field field;
+       uint8_t status;
+       struct jtag_tap *tap;
+       int i;
+       uint8_t *buffer = NULL;
+
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       tap = str9xpec_info->tap;
+
+       if (!str9xpec_info->isc_enable) {
+               str9xpec_isc_enable(bank);
+       }
+
+       if (!str9xpec_info->isc_enable) {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       buffer = calloc(DIV_ROUND_UP(64, 8), 1);
+
+       LOG_DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);
+
+       for (i = first; i <= last; i++) {
+               buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
+       }
+
+       /* execute ISC_BLANK_CHECK command */
+       str9xpec_set_instr(tap, ISC_BLANK_CHECK, TAP_IRPAUSE);
+
+       field.tap = tap;
+       field.num_bits = 64;
+       field.out_value = buffer;
+       field.in_value = NULL;
+
+       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+       jtag_add_sleep(40000);
+
+       /* read blank check result */
+       field.tap = tap;
+       field.num_bits = 64;
+       field.out_value = NULL;
+       field.in_value = buffer;
+
+       jtag_add_dr_scan(1, &field, TAP_IRPAUSE);
+       jtag_execute_queue();
+
+       status = str9xpec_isc_status(tap);
+
+       for (i = first; i <= last; i++)
+       {
+               if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))
+                       bank->sectors[i].is_erased = 0;
+               else
+                       bank->sectors[i].is_erased = 1;
+       }
+
+       free(buffer);
+
+       str9xpec_isc_disable(bank);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+       return ERROR_OK;
+}
+
+static int str9xpec_protect_check(struct flash_bank *bank)
+{
+       uint8_t status;
+       int i;
+
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       status = str9xpec_read_config(bank);
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))
+                       bank->sectors[i].is_protected = 1;
+               else
+                       bank->sectors[i].is_protected = 0;
+       }
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+       return ERROR_OK;
+}
+
+static int str9xpec_erase_area(struct flash_bank *bank, int first, int last)
+{
+       struct scan_field field;
+       uint8_t status;
+       struct jtag_tap *tap;
+       int i;
+       uint8_t *buffer = NULL;
+
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       tap = str9xpec_info->tap;
+
+       if (!str9xpec_info->isc_enable) {
+               str9xpec_isc_enable(bank);
+       }
+
+       if (!str9xpec_info->isc_enable) {
+               return ISC_STATUS_ERROR;
+       }
+
+       buffer = calloc(DIV_ROUND_UP(64, 8), 1);
+
+       LOG_DEBUG("erase: first_bank: %i, last_bank: %i", first, last);
+
+       /* last bank: 0xFF signals a full erase (unlock complete device) */
+       /* last bank: 0xFE signals a option byte erase */
+       if (last == 0xFF)
+       {
+               for (i = 0; i < 64; i++) {
+                       buf_set_u32(buffer, i, 1, 1);
+               }
+       }
+       else if (last == 0xFE)
+       {
+               buf_set_u32(buffer, 49, 1, 1);
+       }
+       else
+       {
+               for (i = first; i <= last; i++) {
+                       buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
+               }
+       }
+
+       LOG_DEBUG("ISC_ERASE");
+
+       /* execute ISC_ERASE command */
+       str9xpec_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
+
+       field.tap = tap;
+       field.num_bits = 64;
+       field.out_value = buffer;
+       field.in_value = NULL;
+
+       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+       jtag_execute_queue();
+
+       jtag_add_sleep(10);
+
+       /* wait for erase completion */
+       while (!((status = str9xpec_isc_status(tap)) & ISC_STATUS_BUSY)) {
+               alive_sleep(1);
+       }
+
+       free(buffer);
+
+       str9xpec_isc_disable(bank);
+
+       return status;
+}
+
+static int str9xpec_erase(struct flash_bank *bank, int first, int last)
+{
+       int status;
+
+       status = str9xpec_erase_area(bank, first, last);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       return ERROR_OK;
+}
+
+static int str9xpec_lock_device(struct flash_bank *bank)
+{
+       struct scan_field field;
+       uint8_t status;
+       struct jtag_tap *tap;
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       str9xpec_info = bank->driver_priv;
+       tap = str9xpec_info->tap;
+
+       if (!str9xpec_info->isc_enable) {
+               str9xpec_isc_enable(bank);
+       }
+
+       if (!str9xpec_info->isc_enable) {
+               return ISC_STATUS_ERROR;
+       }
+
+       /* set security address */
+       str9xpec_set_address(bank, 0x80);
+
+       /* execute ISC_PROGRAM command */
+       str9xpec_set_instr(tap, ISC_PROGRAM_SECURITY, TAP_IDLE);
+
+       str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+       do {
+               field.tap = tap;
+               field.num_bits = 8;
+               field.out_value = NULL;
+               field.in_value = &status;
+
+               jtag_add_dr_scan(1, &field, jtag_get_end_state());
+               jtag_execute_queue();
+
+       } while (!(status & ISC_STATUS_BUSY));
+
+       str9xpec_isc_disable(bank);
+
+       return status;
+}
+
+static int str9xpec_unlock_device(struct flash_bank *bank)
+{
+       uint8_t status;
+
+       status = str9xpec_erase_area(bank, 0, 255);
+
+       return status;
+}
+
+static int str9xpec_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       uint8_t status;
+       int i;
+
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       status = str9xpec_read_config(bank);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       LOG_DEBUG("protect: first_bank: %i, last_bank: %i", first, last);
+
+       /* last bank: 0xFF signals a full device protect */
+       if (last == 0xFF)
+       {
+               if (set)
+               {
+                       status = str9xpec_lock_device(bank);
+               }
+               else
+               {
+                       /* perform full erase to unlock device */
+                       status = str9xpec_unlock_device(bank);
+               }
+       }
+       else
+       {
+               for (i = first; i <= last; i++)
+               {
+                       if (set)
+                               buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);
+                       else
+                               buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);
+               }
+
+               status = str9xpec_write_options(bank);
+       }
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       return ERROR_OK;
+}
+
+static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector)
+{
+       struct jtag_tap *tap;
+       struct scan_field field;
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+       tap = str9xpec_info->tap;
+
+       /* set flash controller address */
+       str9xpec_set_instr(tap, ISC_ADDRESS_SHIFT, TAP_IRPAUSE);
+
+       field.tap = tap;
+       field.num_bits = 8;
+       field.out_value = &sector;
+       field.in_value = NULL;
+
+       jtag_add_dr_scan(1, &field, jtag_get_end_state());
+
+       return ERROR_OK;
+}
+
+static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+       uint32_t dwords_remaining = (count / 8);
+       uint32_t bytes_remaining = (count & 0x00000007);
+       uint32_t bytes_written = 0;
+       uint8_t status;
+       uint32_t check_address = offset;
+       struct jtag_tap *tap;
+       struct scan_field field;
+       uint8_t *scanbuf;
+       int i;
+       int first_sector = 0;
+       int last_sector = 0;
+
+       tap = str9xpec_info->tap;
+
+       if (!str9xpec_info->isc_enable) {
+               str9xpec_isc_enable(bank);
+       }
+
+       if (!str9xpec_info->isc_enable) {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (offset & 0x7)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint32_t sec_start = bank->sectors[i].offset;
+               uint32_t sec_end = sec_start + bank->sectors[i].size;
+
+               /* check if destination falls within the current sector */
+               if ((check_address >= sec_start) && (check_address < sec_end))
+               {
+                       /* check if destination ends in the current sector */
+                       if (offset + count < sec_end)
+                               check_address = offset + count;
+                       else
+                               check_address = sec_end;
+               }
+
+               if ((offset >= sec_start) && (offset < sec_end)) {
+                       first_sector = i;
+               }
+
+               if ((offset + count >= sec_start) && (offset + count < sec_end)) {
+                       last_sector = i;
+               }
+       }
+
+       if (check_address != offset + count)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+
+       LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
+
+       scanbuf = calloc(DIV_ROUND_UP(64, 8), 1);
+
+       LOG_DEBUG("ISC_PROGRAM");
+
+       for (i = first_sector; i <= last_sector; i++)
+       {
+               str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);
+
+               dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);
+
+               while (dwords_remaining > 0)
+               {
+                       str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+                       field.tap = tap;
+                       field.num_bits = 64;
+                       field.out_value = (buffer + bytes_written);
+                       field.in_value = NULL;
+
+                       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+
+                       /* small delay before polling */
+                       jtag_add_sleep(50);
+
+                       str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+                       do {
+                               field.tap = tap;
+                               field.num_bits = 8;
+                               field.out_value = NULL;
+                               field.in_value = scanbuf;
+
+                               jtag_add_dr_scan(1, &field, jtag_get_end_state());
+                               jtag_execute_queue();
+
+                               status = buf_get_u32(scanbuf, 0, 8);
+
+                       } while (!(status & ISC_STATUS_BUSY));
+
+                       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+                               return ERROR_FLASH_OPERATION_FAILED;
+
+                       /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
+                               return ERROR_FLASH_OPERATION_FAILED; */
+
+                       dwords_remaining--;
+                       bytes_written += 8;
+               }
+       }
+
+       if (bytes_remaining)
+       {
+               uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+               int i = 0;
+
+               while (bytes_remaining > 0)
+               {
+                       last_dword[i++] = *(buffer + bytes_written);
+                       bytes_remaining--;
+                       bytes_written++;
+               }
+
+               str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+               field.tap = tap;
+               field.num_bits = 64;
+               field.out_value = last_dword;
+               field.in_value = NULL;
+
+               jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+
+               /* small delay before polling */
+               jtag_add_sleep(50);
+
+               str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+               do {
+                       field.tap = tap;
+                       field.num_bits = 8;
+                       field.out_value = NULL;
+                       field.in_value = scanbuf;
+
+                       jtag_add_dr_scan(1, &field, jtag_get_end_state());
+                       jtag_execute_queue();
+
+                       status = buf_get_u32(scanbuf, 0, 8);
+
+               } while (!(status & ISC_STATUS_BUSY));
+
+               if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
+                       return ERROR_FLASH_OPERATION_FAILED; */
+       }
+
+       free(scanbuf);
+
+       str9xpec_isc_disable(bank);
+
+       return ERROR_OK;
+}
+
+static int str9xpec_probe(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_part_id_command)
+{
+       struct scan_field field;
+       uint8_t *buffer = NULL;
+       struct jtag_tap *tap;
+       uint32_t idcode;
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+       tap = str9xpec_info->tap;
+
+       buffer = calloc(DIV_ROUND_UP(32, 8), 1);
+
+       str9xpec_set_instr(tap, ISC_IDCODE, TAP_IRPAUSE);
+
+       field.tap = tap;
+       field.num_bits = 32;
+       field.out_value = NULL;
+       field.in_value = buffer;
+
+       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+       jtag_execute_queue();
+
+       idcode = buf_get_u32(buffer, 0, 32);
+
+       command_print(CMD_CTX, "str9xpec part id: 0x%8.8" PRIx32 "", idcode);
+
+       free(buffer);
+
+       return ERROR_OK;
+}
+
+static int str9xpec_erase_check(struct flash_bank *bank)
+{
+       return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+static int str9xpec_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "str9xpec flash driver info");
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_read_command)
+{
+       uint8_t status;
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str9xpec options_read <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+
+       status = str9xpec_read_config(bank);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /* boot bank */
+       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))
+               command_print(CMD_CTX, "CS Map: bank1");
+       else
+               command_print(CMD_CTX, "CS Map: bank0");
+
+       /* OTP lock */
+       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))
+               command_print(CMD_CTX, "OTP Lock: OTP Locked");
+       else
+               command_print(CMD_CTX, "OTP Lock: OTP Unlocked");
+
+       /* LVD Threshold */
+       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))
+               command_print(CMD_CTX, "LVD Threshold: 2.7v");
+       else
+               command_print(CMD_CTX, "LVD Threshold: 2.4v");
+
+       /* LVD reset warning */
+       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))
+               command_print(CMD_CTX, "LVD Reset Warning: VDD or VDDQ Inputs");
+       else
+               command_print(CMD_CTX, "LVD Reset Warning: VDD Input Only");
+
+       /* LVD reset select */
+       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))
+               command_print(CMD_CTX, "LVD Reset Selection: VDD or VDDQ Inputs");
+       else
+               command_print(CMD_CTX, "LVD Reset Selection: VDD Input Only");
+
+       return ERROR_OK;
+}
+
+static int str9xpec_write_options(struct flash_bank *bank)
+{
+       struct scan_field field;
+       uint8_t status;
+       struct jtag_tap *tap;
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       str9xpec_info = bank->driver_priv;
+       tap = str9xpec_info->tap;
+
+       /* erase config options first */
+       status = str9xpec_erase_area(bank, 0xFE, 0xFE);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return status;
+
+       if (!str9xpec_info->isc_enable) {
+               str9xpec_isc_enable(bank);
+       }
+
+       if (!str9xpec_info->isc_enable) {
+               return ISC_STATUS_ERROR;
+       }
+
+       /* according to data 64th bit has to be set */
+       buf_set_u32(str9xpec_info->options, 63, 1, 1);
+
+       /* set option byte address */
+       str9xpec_set_address(bank, 0x50);
+
+       /* execute ISC_PROGRAM command */
+       str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+       field.tap = tap;
+       field.num_bits = 64;
+       field.out_value = str9xpec_info->options;
+       field.in_value = NULL;
+
+       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+
+       /* small delay before polling */
+       jtag_add_sleep(50);
+
+       str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+       do {
+               field.tap = tap;
+               field.num_bits = 8;
+               field.out_value = NULL;
+               field.in_value = &status;
+
+               jtag_add_dr_scan(1, &field, jtag_get_end_state());
+               jtag_execute_queue();
+
+       } while (!(status & ISC_STATUS_BUSY));
+
+       str9xpec_isc_disable(bank);
+
+       return status;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_write_command)
+{
+       uint8_t status;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str9xpec options_write <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       status = str9xpec_write_options(bank);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command)
+{
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 2)
+       {
+               command_print(CMD_CTX, "str9xpec options_cmap <bank> <bank0 | bank1>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+
+       if (strcmp(CMD_ARGV[1], "bank1") == 0)
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);
+       }
+       else
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_lvdthd_command)
+{
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 2)
+       {
+               command_print(CMD_CTX, "str9xpec options_lvdthd <bank> <2.4v | 2.7v>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+
+       if (strcmp(CMD_ARGV[1], "2.7v") == 0)
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);
+       }
+       else
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_lvdsel_command)
+{
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 2)
+       {
+               command_print(CMD_CTX, "str9xpec options_lvdsel <bank> <vdd | vdd_vddq>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+
+       if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0)
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);
+       }
+       else
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_lvdwarn_command)
+{
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 2)
+       {
+               command_print(CMD_CTX, "str9xpec options_lvdwarn <bank> <vdd | vdd_vddq>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+
+       if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0)
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);
+       }
+       else
+       {
+               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_lock_command)
+{
+       uint8_t status;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str9xpec lock <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       status = str9xpec_lock_device(bank);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_unlock_command)
+{
+       uint8_t status;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str9xpec unlock <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       status = str9xpec_unlock_device(bank);
+
+       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command)
+{
+       struct jtag_tap *tap0;
+       struct jtag_tap *tap1;
+       struct jtag_tap *tap2;
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str9xpec enable_turbo <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+
+       tap0 = str9xpec_info->tap;
+
+       /* remove arm core from chain - enter turbo mode */
+       tap1 = tap0->next_tap;
+       if (tap1 == NULL)
+       {
+               /* things are *WRONG* */
+               command_print(CMD_CTX,"**STR9FLASH** (tap1) invalid chain?");
+               return ERROR_OK;
+       }
+       tap2 = tap1->next_tap;
+       if (tap2 == NULL)
+       {
+               /* things are *WRONG* */
+               command_print(CMD_CTX,"**STR9FLASH** (tap2) invalid chain?");
+               return ERROR_OK;
+       }
+
+       /* enable turbo mode - TURBO-PROG-ENABLE */
+       str9xpec_set_instr(tap2, 0xD, TAP_IDLE);
+       if ((retval = jtag_execute_queue()) != ERROR_OK)
+               return retval;
+
+       /* modify scan chain - str9 core has been removed */
+       tap1->enabled = 0;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_disable_turbo_command)
+{
+       struct jtag_tap *tap;
+       struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+       if (CMD_ARGC < 1)
+       {
+               command_print(CMD_CTX, "str9xpec disable_turbo <bank>");
+               return ERROR_OK;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       str9xpec_info = bank->driver_priv;
+       tap = str9xpec_info->tap;
+
+       if (tap == NULL)
+               return ERROR_FAIL;
+
+       /* exit turbo mode via RESET */
+       str9xpec_set_instr(tap, ISC_NOOP, TAP_IDLE);
+       jtag_add_tlr();
+       jtag_execute_queue();
+
+       /* restore previous scan chain */
+       if (tap->next_tap) {
+               tap->next_tap->enabled = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration str9xpec_config_command_handlers[] = {
+       {
+               .name = "enable_turbo",
+               .handler = str9xpec_handle_flash_enable_turbo_command,
+               .mode = COMMAND_EXEC,
+               .help = "enable str9xpec turbo mode",
+       },
+       {
+               .name = "disable_turbo",
+               .handler = str9xpec_handle_flash_disable_turbo_command,
+               .mode = COMMAND_EXEC,
+               .help = "disable str9xpec turbo mode",
+       },
+       {
+               .name = "options_cmap",
+               .handler = str9xpec_handle_flash_options_cmap_command,
+               .mode = COMMAND_EXEC,
+               .help = "configure str9xpec boot sector",
+       },
+       {
+               .name = "options_lvdthd",
+               .handler = str9xpec_handle_flash_options_lvdthd_command,
+               .mode = COMMAND_EXEC,
+               .help = "configure str9xpec lvd threshold",
+       },
+       {
+               .name = "options_lvdsel",
+               .handler = str9xpec_handle_flash_options_lvdsel_command,
+               .mode = COMMAND_EXEC,
+               .help = "configure str9xpec lvd selection",
+       },
+       {
+               .name = "options_lvdwarn",
+               .handler = str9xpec_handle_flash_options_lvdwarn_command,
+               .mode = COMMAND_EXEC,
+               .help = "configure str9xpec lvd warning",
+       },
+       {
+               .name = "options_read",
+               .handler = str9xpec_handle_flash_options_read_command,
+               .mode = COMMAND_EXEC,
+               .help = "read str9xpec options",
+       },
+       {
+               .name = "options_write",
+               .handler = str9xpec_handle_flash_options_write_command,
+               .mode = COMMAND_EXEC,
+               .help = "write str9xpec options",
+       },
+       {
+               .name = "lock",
+               .handler = str9xpec_handle_flash_lock_command,
+               .mode = COMMAND_EXEC,
+               .help = "lock str9xpec device",
+       },
+       {
+               .name = "unlock",
+               .handler = str9xpec_handle_flash_unlock_command,
+               .mode = COMMAND_EXEC,
+               .help = "unlock str9xpec device",
+       },
+       {
+               .name = "part_id",
+               .handler = str9xpec_handle_part_id_command,
+               .mode = COMMAND_EXEC,
+               .help = "print part id of str9xpec flash bank <num>",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration str9xpec_command_handlers[] = {
+       {
+               .name = "str9xpec",
+               .mode = COMMAND_ANY,
+               .help = "str9xpec flash command group",
+               .chain = str9xpec_config_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver str9xpec_flash = {
+               .name = "str9xpec",
+               .commands = str9xpec_command_handlers,
+               .flash_bank_command = &str9xpec_flash_bank_command,
+               .erase = &str9xpec_erase,
+               .protect = &str9xpec_protect,
+               .write = &str9xpec_write,
+               .probe = &str9xpec_probe,
+               .auto_probe = &str9xpec_probe,
+               .erase_check = &str9xpec_erase_check,
+               .protect_check = &str9xpec_protect_check,
+               .info = &str9xpec_info,
+       };
diff --git a/src/flash/nor/str9xpec.h b/src/flash/nor/str9xpec.h
new file mode 100644 (file)
index 0000000..1c8d41b
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef STR9XPEC_H
+#define STR9XPEC_H
+
+#include "flash.h"
+#include "jtag.h"
+
+struct str9xpec_flash_controller
+{
+       struct jtag_tap *tap;
+       uint32_t *sector_bits;
+       int chain_pos;
+       int isc_enable;
+       uint8_t options[8];
+};
+
+enum str9xpec_status_codes
+{
+       STR9XPEC_INVALID_COMMAND = 1,
+       STR9XPEC_ISC_SUCCESS = 2,
+       STR9XPEC_ISC_DISABLED = 3,
+       STR9XPEC_ISC_INTFAIL = 32,
+};
+
+/* ISC commands */
+
+#define ISC_IDCODE                             0xFE
+#define ISC_MFG_READ                   0x4C
+#define ISC_CONFIGURATION              0x07
+#define ISC_ENABLE                             0x0C
+#define ISC_DISABLE                            0x0F
+#define ISC_NOOP                               0x10
+#define ISC_ADDRESS_SHIFT              0x11
+#define ISC_CLR_STATUS                 0x13
+#define ISC_PROGRAM                            0x20
+#define ISC_PROGRAM_SECURITY   0x22
+#define ISC_PROGRAM_UC                 0x23
+#define ISC_ERASE                              0x30
+#define ISC_READ                               0x50
+#define ISC_BLANK_CHECK                        0x60
+
+/* ISC_DEFAULT bit definitions */
+
+#define ISC_STATUS_SECURITY            0x40
+#define ISC_STATUS_INT_ERROR   0x30
+#define ISC_STATUS_MODE                        0x08
+#define ISC_STATUS_BUSY                        0x04
+#define ISC_STATUS_ERROR               0x03
+
+/* Option bytes definitions */
+
+#define STR9XPEC_OPT_CSMAPBIT          48
+#define STR9XPEC_OPT_LVDTHRESBIT       49
+#define STR9XPEC_OPT_LVDSELBIT         50
+#define STR9XPEC_OPT_LVDWARNBIT                51
+#define STR9XPEC_OPT_OTPBIT                    63
+
+#endif /* STR9XPEC_H */
diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c
new file mode 100644 (file)
index 0000000..5965934
--- /dev/null
@@ -0,0 +1,1271 @@
+/***************************************************************************
+ *   Copyright (C) 2007,2008 by Christopher Kilgour                        *
+ *   techie |_at_| whiterocker |_dot_| com                                 *
+ *                                                                         *
+ *   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 "tms470.h"
+
+
+/* ----------------------------------------------------------------------
+                      Internal Support, Helpers
+   ---------------------------------------------------------------------- */
+
+const struct flash_sector TMS470R1A256_SECTORS[] = {
+       {0x00000000, 0x00002000, -1, -1},
+       {0x00002000, 0x00002000, -1, -1},
+       {0x00004000, 0x00002000, -1, -1},
+       {0x00006000, 0x00002000, -1, -1},
+       {0x00008000, 0x00008000, -1, -1},
+       {0x00010000, 0x00008000, -1, -1},
+       {0x00018000, 0x00008000, -1, -1},
+       {0x00020000, 0x00008000, -1, -1},
+       {0x00028000, 0x00008000, -1, -1},
+       {0x00030000, 0x00008000, -1, -1},
+       {0x00038000, 0x00002000, -1, -1},
+       {0x0003A000, 0x00002000, -1, -1},
+       {0x0003C000, 0x00002000, -1, -1},
+       {0x0003E000, 0x00002000, -1, -1},
+};
+
+#define TMS470R1A256_NUM_SECTORS \
+       ARRAY_SIZE(TMS470R1A256_SECTORS)
+
+const struct flash_sector TMS470R1A288_BANK0_SECTORS[] = {
+       {0x00000000, 0x00002000, -1, -1},
+       {0x00002000, 0x00002000, -1, -1},
+       {0x00004000, 0x00002000, -1, -1},
+       {0x00006000, 0x00002000, -1, -1},
+};
+
+#define TMS470R1A288_BANK0_NUM_SECTORS \
+       ARRAY_SIZE(TMS470R1A288_BANK0_SECTORS)
+
+const struct flash_sector TMS470R1A288_BANK1_SECTORS[] = {
+       {0x00040000, 0x00010000, -1, -1},
+       {0x00050000, 0x00010000, -1, -1},
+       {0x00060000, 0x00010000, -1, -1},
+       {0x00070000, 0x00010000, -1, -1},
+};
+
+#define TMS470R1A288_BANK1_NUM_SECTORS \
+       ARRAY_SIZE(TMS470R1A288_BANK1_SECTORS)
+
+const struct flash_sector TMS470R1A384_BANK0_SECTORS[] = {
+       {0x00000000, 0x00002000, -1, -1},
+       {0x00002000, 0x00002000, -1, -1},
+       {0x00004000, 0x00004000, -1, -1},
+       {0x00008000, 0x00004000, -1, -1},
+       {0x0000C000, 0x00004000, -1, -1},
+       {0x00010000, 0x00004000, -1, -1},
+       {0x00014000, 0x00004000, -1, -1},
+       {0x00018000, 0x00002000, -1, -1},
+       {0x0001C000, 0x00002000, -1, -1},
+       {0x0001E000, 0x00002000, -1, -1},
+};
+
+#define TMS470R1A384_BANK0_NUM_SECTORS \
+       ARRAY_SIZE(TMS470R1A384_BANK0_SECTORS)
+
+const struct flash_sector TMS470R1A384_BANK1_SECTORS[] = {
+       {0x00020000, 0x00008000, -1, -1},
+       {0x00028000, 0x00008000, -1, -1},
+       {0x00030000, 0x00008000, -1, -1},
+       {0x00038000, 0x00008000, -1, -1},
+};
+
+#define TMS470R1A384_BANK1_NUM_SECTORS \
+       ARRAY_SIZE(TMS470R1A384_BANK1_SECTORS)
+
+const struct flash_sector TMS470R1A384_BANK2_SECTORS[] = {
+       {0x00040000, 0x00008000, -1, -1},
+       {0x00048000, 0x00008000, -1, -1},
+       {0x00050000, 0x00008000, -1, -1},
+       {0x00058000, 0x00008000, -1, -1},
+};
+
+#define TMS470R1A384_BANK2_NUM_SECTORS \
+       ARRAY_SIZE(TMS470R1A384_BANK2_SECTORS)
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_read_part_info(struct flash_bank *bank)
+{
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t device_ident_reg;
+       uint32_t silicon_version;
+       uint32_t technology_family;
+       uint32_t rom_flash;
+       uint32_t part_number;
+       char *part_name;
+
+       /* we shall not rely on the caller in this test, this function allocates memory,
+          thus and executing the code more than once may cause memory leak */
+       if (tms470_info->device_ident_reg)
+         return ERROR_OK;
+
+       /* read and parse the device identification register */
+       target_read_u32(target, 0xFFFFFFF0, &device_ident_reg);
+
+       LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg);
+
+       if ((device_ident_reg & 7) == 0)
+       {
+               LOG_WARNING("Cannot identify target as a TMS470 family.");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       silicon_version = (device_ident_reg >> 12) & 0xF;
+       technology_family = (device_ident_reg >> 11) & 1;
+       rom_flash = (device_ident_reg >> 10) & 1;
+       part_number = (device_ident_reg >> 3) & 0x7f;
+
+       /*
+        * If the part number is known, determine if the flash bank is valid
+        * based on the base address being within the known flash bank
+        * ranges.  Then fixup/complete the remaining fields of the flash
+        * bank structure.
+        */
+       switch (part_number)
+       {
+       case 0x0a:
+               part_name = "TMS470R1A256";
+
+               if (bank->base >= 0x00040000)
+               {
+                       LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               tms470_info->ordinal = 0;
+               bank->base = 0x00000000;
+               bank->size = 256 * 1024;
+               bank->num_sectors = TMS470R1A256_NUM_SECTORS;
+               bank->sectors = malloc(sizeof(TMS470R1A256_SECTORS));
+               if (!bank->sectors)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               (void)memcpy(bank->sectors, TMS470R1A256_SECTORS, sizeof(TMS470R1A256_SECTORS));
+               break;
+
+       case 0x2b:
+               part_name = "TMS470R1A288";
+
+               if (bank->base < 0x00008000)
+               {
+                       tms470_info->ordinal = 0;
+                       bank->base = 0x00000000;
+                       bank->size = 32 * 1024;
+                       bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS;
+                       bank->sectors = malloc(sizeof(TMS470R1A288_BANK0_SECTORS));
+                       if (!bank->sectors)
+                       {
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+                       (void)memcpy(bank->sectors, TMS470R1A288_BANK0_SECTORS, sizeof(TMS470R1A288_BANK0_SECTORS));
+               }
+               else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000))
+               {
+                       tms470_info->ordinal = 1;
+                       bank->base = 0x00040000;
+                       bank->size = 256 * 1024;
+                       bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS;
+                       bank->sectors = malloc(sizeof(TMS470R1A288_BANK1_SECTORS));
+                       if (!bank->sectors)
+                       {
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+                       (void)memcpy(bank->sectors, TMS470R1A288_BANK1_SECTORS, sizeof(TMS470R1A288_BANK1_SECTORS));
+               }
+               else
+               {
+                       LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               break;
+
+       case 0x2d:
+               part_name = "TMS470R1A384";
+
+               if (bank->base < 0x00020000)
+               {
+                       tms470_info->ordinal = 0;
+                       bank->base = 0x00000000;
+                       bank->size = 128 * 1024;
+                       bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS;
+                       bank->sectors = malloc(sizeof(TMS470R1A384_BANK0_SECTORS));
+                       if (!bank->sectors)
+                       {
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+                       (void)memcpy(bank->sectors, TMS470R1A384_BANK0_SECTORS, sizeof(TMS470R1A384_BANK0_SECTORS));
+               }
+               else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000))
+               {
+                       tms470_info->ordinal = 1;
+                       bank->base = 0x00020000;
+                       bank->size = 128 * 1024;
+                       bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS;
+                       bank->sectors = malloc(sizeof(TMS470R1A384_BANK1_SECTORS));
+                       if (!bank->sectors)
+                       {
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+                       (void)memcpy(bank->sectors, TMS470R1A384_BANK1_SECTORS, sizeof(TMS470R1A384_BANK1_SECTORS));
+               }
+               else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000))
+               {
+                       tms470_info->ordinal = 2;
+                       bank->base = 0x00040000;
+                       bank->size = 128 * 1024;
+                       bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS;
+                       bank->sectors = malloc(sizeof(TMS470R1A384_BANK2_SECTORS));
+                       if (!bank->sectors)
+                       {
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+                       (void)memcpy(bank->sectors, TMS470R1A384_BANK2_SECTORS, sizeof(TMS470R1A384_BANK2_SECTORS));
+               }
+               else
+               {
+                       LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               break;
+
+       default:
+               LOG_WARNING("Could not identify part 0x%02x as a member of the TMS470 family.", (unsigned)part_number);
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       /* turn off memory selects */
+       target_write_u32(target, 0xFFFFFFE4, 0x00000000);
+       target_write_u32(target, 0xFFFFFFE0, 0x00000000);
+
+       bank->chip_width = 32;
+       bank->bus_width = 32;
+
+       LOG_INFO("Identified %s, ver=%d, core=%s, nvmem=%s.",
+                part_name,
+                (int)(silicon_version),
+                (technology_family ? "1.8v" : "3.3v"),
+                (rom_flash ? "rom" : "flash"));
+
+       tms470_info->device_ident_reg = device_ident_reg;
+       tms470_info->silicon_version = silicon_version;
+       tms470_info->technology_family = technology_family;
+       tms470_info->rom_flash = rom_flash;
+       tms470_info->part_number = part_number;
+       tms470_info->part_name = part_name;
+
+       /*
+        * Disable reset on address access violation.
+        */
+       target_write_u32(target, 0xFFFFFFE0, 0x00004007);
+
+       return ERROR_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static uint32_t keysSet = 0;
+static uint32_t flashKeys[4];
+
+COMMAND_HANDLER(tms470_handle_flash_keyset_command)
+{
+       if (CMD_ARGC > 4)
+       {
+               command_print(CMD_CTX, "tms470 flash_keyset <key0> <key1> <key2> <key3>");
+               return ERROR_INVALID_ARGUMENTS;
+       }
+       else if (CMD_ARGC == 4)
+       {
+               int i;
+
+               for (i = 0; i < 4; i++)
+               {
+                       int start = (0 == strncmp(CMD_ARGV[i], "0x", 2)) ? 2 : 0;
+
+                       if (1 != sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flashKeys[i]))
+                       {
+                               command_print(CMD_CTX, "could not process flash key %s", CMD_ARGV[i]);
+                               LOG_ERROR("could not process flash key %s", CMD_ARGV[i]);
+                               return ERROR_INVALID_ARGUMENTS;
+                       }
+               }
+
+               keysSet = 1;
+       }
+       else if (CMD_ARGC != 0)
+       {
+               command_print(CMD_CTX, "tms470 flash_keyset <key0> <key1> <key2> <key3>");
+               return ERROR_INVALID_ARGUMENTS;
+       }
+
+       if (keysSet)
+       {
+               command_print(CMD_CTX, "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "",
+                             flashKeys[0], flashKeys[1], flashKeys[2], flashKeys[3]);
+       }
+       else
+       {
+               command_print(CMD_CTX, "flash keys not set");
+       }
+
+       return ERROR_OK;
+}
+
+static const uint32_t FLASH_KEYS_ALL_ONES[] = { 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF,
+};
+
+static const uint32_t FLASH_KEYS_ALL_ZEROS[] = { 0x00000000, 0x00000000,
+       0x00000000, 0x00000000,
+};
+
+static const uint32_t FLASH_KEYS_MIX1[] = { 0xf0fff0ff, 0xf0fff0ff,
+       0xf0fff0ff, 0xf0fff0ff
+};
+
+static const uint32_t FLASH_KEYS_MIX2[] = { 0x0000ffff, 0x0000ffff,
+       0x0000ffff, 0x0000ffff
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int oscMHz = 12;
+
+COMMAND_HANDLER(tms470_handle_osc_megahertz_command)
+{
+       if (CMD_ARGC > 1)
+       {
+               command_print(CMD_CTX, "tms470 osc_megahertz <MHz>");
+               return ERROR_INVALID_ARGUMENTS;
+       }
+       else if (CMD_ARGC == 1)
+       {
+               sscanf(CMD_ARGV[0], "%d", &oscMHz);
+       }
+
+       if (oscMHz <= 0)
+       {
+               LOG_ERROR("osc_megahertz must be positive and non-zero!");
+               command_print(CMD_CTX, "osc_megahertz must be positive and non-zero!");
+               oscMHz = 12;
+               return ERROR_INVALID_ARGUMENTS;
+       }
+
+       command_print(CMD_CTX, "osc_megahertz=%d", oscMHz);
+
+       return ERROR_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int plldis = 0;
+
+COMMAND_HANDLER(tms470_handle_plldis_command)
+{
+       if (CMD_ARGC > 1)
+       {
+               command_print(CMD_CTX, "tms470 plldis <0 | 1>");
+               return ERROR_INVALID_ARGUMENTS;
+       }
+       else if (CMD_ARGC == 1)
+       {
+               sscanf(CMD_ARGV[0], "%d", &plldis);
+               plldis = plldis ? 1 : 0;
+       }
+
+       command_print(CMD_CTX, "plldis=%d", plldis);
+
+       return ERROR_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_check_flash_unlocked(struct target * target)
+{
+       uint32_t fmbbusy;
+
+       target_read_u32(target, 0xFFE89C08, &fmbbusy);
+       LOG_INFO("tms470 fmbbusy = 0x%08" PRIx32 " -> %s", fmbbusy, fmbbusy & 0x8000 ? "unlocked" : "LOCKED");
+       return fmbbusy & 0x8000 ? ERROR_OK : ERROR_FLASH_OPERATION_FAILED;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_try_flash_keys(struct target * target, const uint32_t * key_set)
+{
+       uint32_t glbctrl, fmmstat;
+       int retval = ERROR_FLASH_OPERATION_FAILED;
+
+       /* set GLBCTRL.4  */
+       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
+
+       /* only perform the key match when 3VSTAT is clear */
+       target_read_u32(target, 0xFFE8BC0C, &fmmstat);
+       if (!(fmmstat & 0x08))
+       {
+               unsigned i;
+               uint32_t fmbptr, fmbac2, orig_fmregopt;
+
+               target_write_u32(target, 0xFFE8BC04, fmmstat & ~0x07);
+
+               /* wait for pump ready */
+               do
+               {
+                       target_read_u32(target, 0xFFE8A814, &fmbptr);
+                       alive_sleep(1);
+               }
+               while (!(fmbptr & 0x0200));
+
+               /* force max wait states */
+               target_read_u32(target, 0xFFE88004, &fmbac2);
+               target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
+
+               /* save current access mode, force normal read mode */
+               target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
+               target_write_u32(target, 0xFFE89C00, 0x00);
+
+               for (i = 0; i < 4; i++)
+               {
+                       uint32_t tmp;
+
+                       /* There is no point displaying the value of tmp, it is
+                        * filtered by the chip.  The purpose of this read is to
+                        * prime the unlocking logic rather than read out the value.
+                        */
+                       target_read_u32(target, 0x00001FF0 + 4 * i, &tmp);
+
+                       LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]);
+                       target_write_u32(target, 0xFFE89C0C, key_set[i]);
+               }
+
+               if (ERROR_OK == tms470_check_flash_unlocked(target))
+               {
+                       /*
+                        * There seems to be a side-effect of reading the FMPKEY
+                        * register in that it re-enables the protection.  So we
+                        * re-enable it.
+                        */
+                       for (i = 0; i < 4; i++)
+                       {
+                               uint32_t tmp;
+
+                               target_read_u32(target, 0x00001FF0 + 4 * i, &tmp);
+                               target_write_u32(target, 0xFFE89C0C, key_set[i]);
+                       }
+                       retval = ERROR_OK;
+               }
+
+               /* restore settings */
+               target_write_u32(target, 0xFFE89C00, orig_fmregopt);
+               target_write_u32(target, 0xFFE88004, fmbac2);
+       }
+
+       /* clear config bit */
+       target_write_u32(target, 0xFFFFFFDC, glbctrl);
+
+       return retval;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_unlock_flash(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       const uint32_t *p_key_sets[5];
+       unsigned i, key_set_count;
+
+       if (keysSet)
+       {
+               key_set_count = 5;
+               p_key_sets[0] = flashKeys;
+               p_key_sets[1] = FLASH_KEYS_ALL_ONES;
+               p_key_sets[2] = FLASH_KEYS_ALL_ZEROS;
+               p_key_sets[3] = FLASH_KEYS_MIX1;
+               p_key_sets[4] = FLASH_KEYS_MIX2;
+       }
+       else
+       {
+               key_set_count = 4;
+               p_key_sets[0] = FLASH_KEYS_ALL_ONES;
+               p_key_sets[1] = FLASH_KEYS_ALL_ZEROS;
+               p_key_sets[2] = FLASH_KEYS_MIX1;
+               p_key_sets[3] = FLASH_KEYS_MIX2;
+       }
+
+       for (i = 0; i < key_set_count; i++)
+       {
+               if (tms470_try_flash_keys(target, p_key_sets[i]) == ERROR_OK)
+               {
+                       LOG_INFO("tms470 flash is unlocked");
+                       return ERROR_OK;
+               }
+       }
+
+       LOG_WARNING("tms470 could not unlock flash memory protection level 2");
+       return ERROR_FLASH_OPERATION_FAILED;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_flash_initialize_internal_state_machine(struct flash_bank *bank)
+{
+       uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk;
+       struct target *target = bank->target;
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+       int result = ERROR_OK;
+
+       /*
+        * Select the desired bank to be programmed by writing BANK[2:0] of
+        * FMMAC2.
+        */
+       target_read_u32(target, 0xFFE8BC04, &fmmac2);
+       fmmac2 &= ~0x0007;
+       fmmac2 |= (tms470_info->ordinal & 7);
+       target_write_u32(target, 0xFFE8BC04, fmmac2);
+       LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2);
+
+       /*
+        * Disable level 1 sector protection by setting bit 15 of FMMAC1.
+        */
+       target_read_u32(target, 0xFFE8BC00, &fmmac1);
+       fmmac1 |= 0x8000;
+       target_write_u32(target, 0xFFE8BC00, fmmac1);
+       LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1);
+
+       /*
+        * FMTCREG = 0x2fc0;
+        */
+       target_write_u32(target, 0xFFE8BC10, 0x2fc0);
+       LOG_DEBUG("set fmtcreg = 0x2fc0");
+
+       /*
+        * MAXPP = 50
+        */
+       target_write_u32(target, 0xFFE8A07C, 50);
+       LOG_DEBUG("set fmmaxpp = 50");
+
+       /*
+        * MAXCP = 0xf000 + 2000
+        */
+       target_write_u32(target, 0xFFE8A084, 0xf000 + 2000);
+       LOG_DEBUG("set fmmaxcp = 0x%04x", 0xf000 + 2000);
+
+       /*
+        * configure VHV
+        */
+       target_read_u32(target, 0xFFE8A080, &fmmaxep);
+       if (fmmaxep == 0xf000)
+       {
+               fmmaxep = 0xf000 + 4095;
+               target_write_u32(target, 0xFFE8A80C, 0x9964);
+               LOG_DEBUG("set fmptr3 = 0x9964");
+       }
+       else
+       {
+               fmmaxep = 0xa000 + 4095;
+               target_write_u32(target, 0xFFE8A80C, 0x9b64);
+               LOG_DEBUG("set fmptr3 = 0x9b64");
+       }
+       target_write_u32(target, 0xFFE8A080, fmmaxep);
+       LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep);
+
+       /*
+        * FMPTR4 = 0xa000
+        */
+       target_write_u32(target, 0xFFE8A810, 0xa000);
+       LOG_DEBUG("set fmptr4 = 0xa000");
+
+       /*
+        * FMPESETUP, delay parameter selected based on clock frequency.
+        *
+        * According to the TI App Note SPNU257 and flashing code, delay is
+        * int((sysclk(MHz) + 1) / 2), with a minimum of 5.  The system
+        * clock is usually derived from the ZPLL module, and selected by
+        * the plldis global.
+        */
+       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
+       sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * oscMHz / (1 + (glbctrl & 7));
+       delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5;
+       target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8));
+       LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8));
+
+       /*
+        * FMPVEVACCESS, based on delay.
+        */
+       k = delay | (delay << 8);
+       target_write_u32(target, 0xFFE8A05C, k);
+       LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k);
+
+       /*
+        * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay.
+        */
+       k <<= 1;
+       target_write_u32(target, 0xFFE8A034, k);
+       LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k);
+       target_write_u32(target, 0xFFE8A040, k);
+       LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k);
+       target_write_u32(target, 0xFFE8A024, k);
+       LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k);
+
+       /*
+        * FMCVACCESS, based on delay.
+        */
+       k = delay * 16;
+       target_write_u32(target, 0xFFE8A060, k);
+       LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k);
+
+       /*
+        * FMCSETUP, based on delay.
+        */
+       k = 0x3000 | delay * 20;
+       target_write_u32(target, 0xFFE8A020, k);
+       LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k);
+
+       /*
+        * FMEHOLD, based on delay.
+        */
+       k = (delay * 20) << 2;
+       target_write_u32(target, 0xFFE8A038, k);
+       LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k);
+
+       /*
+        * PWIDTH, CWIDTH, EWIDTH, based on delay.
+        */
+       target_write_u32(target, 0xFFE8A050, delay * 8);
+       LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8);
+       target_write_u32(target, 0xFFE8A058, delay * 1000);
+       LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000);
+       target_write_u32(target, 0xFFE8A054, delay * 5400);
+       LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400);
+
+       return result;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int tms470_flash_status(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       int result = ERROR_OK;
+       uint32_t fmmstat;
+
+       target_read_u32(target, 0xFFE8BC0C, &fmmstat);
+       LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat);
+
+       if (fmmstat & 0x0080)
+       {
+               LOG_WARNING("tms470 flash command: erase still active after busy clear.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (fmmstat & 0x0040)
+       {
+               LOG_WARNING("tms470 flash command: program still active after busy clear.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (fmmstat & 0x0020)
+       {
+               LOG_WARNING("tms470 flash command: invalid data command.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (fmmstat & 0x0010)
+       {
+               LOG_WARNING("tms470 flash command: program, erase or validate sector failed.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (fmmstat & 0x0008)
+       {
+               LOG_WARNING("tms470 flash command: voltage instability detected.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (fmmstat & 0x0006)
+       {
+               LOG_WARNING("tms470 flash command: command suspend detected.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if (fmmstat & 0x0001)
+       {
+               LOG_WARNING("tms470 flash command: sector was locked.");
+               result = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return result;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_erase_sector(struct flash_bank *bank, int sector)
+{
+       uint32_t glbctrl, orig_fmregopt, fmbsea, fmbseb, fmmstat;
+       struct target *target = bank->target;
+       uint32_t flashAddr = bank->base + bank->sectors[sector].offset;
+       int result = ERROR_OK;
+
+       /*
+        * Set the bit GLBCTRL4 of the GLBCTRL register (in the System
+        * module) to enable writing to the flash registers }.
+        */
+       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
+       LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10);
+
+       /* Force normal read mode. */
+       target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
+       target_write_u32(target, 0xFFE89C00, 0);
+       LOG_DEBUG("set fmregopt = 0x%08x", 0);
+
+       (void)tms470_flash_initialize_internal_state_machine(bank);
+
+       /*
+        * Select one or more bits in FMBSEA or FMBSEB to disable Level 1
+        * protection for the particular sector to be erased/written.
+        */
+       if (sector < 16)
+       {
+               target_read_u32(target, 0xFFE88008, &fmbsea);
+               target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector));
+               LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector));
+       }
+       else
+       {
+               target_read_u32(target, 0xFFE8800C, &fmbseb);
+               target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16)));
+               LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16)));
+       }
+       bank->sectors[sector].is_protected = 0;
+
+       /*
+        * clear status regiser, sent erase command, kickoff erase
+        */
+       target_write_u16(target, flashAddr, 0x0040);
+       LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flashAddr);
+       target_write_u16(target, flashAddr, 0x0020);
+       LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flashAddr);
+       target_write_u16(target, flashAddr, 0xffff);
+       LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flashAddr);
+
+       /*
+        * Monitor FMMSTAT, busy until clear, then check and other flags for
+        * ultimate result of the operation.
+        */
+       do
+       {
+               target_read_u32(target, 0xFFE8BC0C, &fmmstat);
+               if (fmmstat & 0x0100)
+               {
+                       alive_sleep(1);
+               }
+       }
+       while (fmmstat & 0x0100);
+
+       result = tms470_flash_status(bank);
+
+       if (sector < 16)
+       {
+               target_write_u32(target, 0xFFE88008, fmbsea);
+               LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea);
+               bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1;
+       }
+       else
+       {
+               target_write_u32(target, 0xFFE8800C, fmbseb);
+               LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb);
+               bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1;
+       }
+       target_write_u32(target, 0xFFE89C00, orig_fmregopt);
+       LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl);
+       LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl);
+
+       if (result == ERROR_OK)
+       {
+               bank->sectors[sector].is_erased = 1;
+       }
+
+       return result;
+}
+
+/* ----------------------------------------------------------------------
+              Implementation of Flash Driver Interfaces
+   ---------------------------------------------------------------------- */
+
+static const struct command_registration tms470_any_command_handlers[] = {
+       {
+               .name = "flash_keyset",
+               .handler = &tms470_handle_flash_keyset_command,
+               .mode = COMMAND_ANY,
+               .help = "tms470 flash_keyset <key0> <key1> <key2> <key3>",
+       },
+       {
+               .name = "osc_megahertz",
+               .handler = &tms470_handle_osc_megahertz_command,
+               .mode = COMMAND_ANY,
+               .help = "tms470 osc_megahertz <MHz>",
+       },
+       {
+               .name = "plldis",
+               .handler = &tms470_handle_plldis_command,
+               .mode = COMMAND_ANY,
+               .help = "tms470 plldis <0/1>",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration tms470_command_handlers[] = {
+       {
+               .name = "tms470",
+               .mode = COMMAND_ANY,
+               .help = "TI tms470 flash command group",
+               .chain = tms470_any_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_erase(struct flash_bank *bank, int first, int last)
+{
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+       int sector, result = ERROR_OK;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       tms470_read_part_info(bank);
+
+       if ((first < 0) || (first >= bank->num_sectors) || (last < 0) || (last >= bank->num_sectors) || (first > last))
+       {
+               LOG_ERROR("Sector range %d to %d invalid.", first, last);
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       result = tms470_unlock_flash(bank);
+       if (result != ERROR_OK)
+       {
+               return result;
+       }
+
+       for (sector = first; sector <= last; sector++)
+       {
+               LOG_INFO("Erasing tms470 bank %d sector %d...", tms470_info->ordinal, sector);
+
+               result = tms470_erase_sector(bank, sector);
+
+               if (result != ERROR_OK)
+               {
+                       LOG_ERROR("tms470 could not erase flash sector.");
+                       break;
+               }
+               else
+               {
+                       LOG_INFO("sector erased successfully.");
+               }
+       }
+
+       return result;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t fmmac2, fmbsea, fmbseb;
+       int sector;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       tms470_read_part_info(bank);
+
+       if ((first < 0) || (first >= bank->num_sectors) || (last < 0) || (last >= bank->num_sectors) || (first > last))
+       {
+               LOG_ERROR("Sector range %d to %d invalid.", first, last);
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* enable the appropriate bank */
+       target_read_u32(target, 0xFFE8BC04, &fmmac2);
+       target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
+
+       /* get the original sector proection flags for this bank */
+       target_read_u32(target, 0xFFE88008, &fmbsea);
+       target_read_u32(target, 0xFFE8800C, &fmbseb);
+
+       for (sector = 0; sector < bank->num_sectors; sector++)
+       {
+               if (sector < 16)
+               {
+                       fmbsea = set ? fmbsea & ~(1 << sector) : fmbsea | (1 << sector);
+                       bank->sectors[sector].is_protected = set ? 1 : 0;
+               }
+               else
+               {
+                       fmbseb = set ? fmbseb & ~(1 << (sector - 16)) : fmbseb | (1 << (sector - 16));
+                       bank->sectors[sector].is_protected = set ? 1 : 0;
+               }
+       }
+
+       /* update the protection bits */
+       target_write_u32(target, 0xFFE88008, fmbsea);
+       target_write_u32(target, 0xFFE8800C, fmbseb);
+
+       return ERROR_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_write(struct flash_bank *bank, uint8_t * buffer, uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       uint32_t glbctrl, fmbac2, orig_fmregopt, fmbsea, fmbseb, fmmaxpp, fmmstat;
+       int result = ERROR_OK;
+       uint32_t i;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       tms470_read_part_info(bank);
+
+       LOG_INFO("Writing %" PRId32 " bytes starting at 0x%08" PRIx32 "", count, bank->base + offset);
+
+       /* set GLBCTRL.4  */
+       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
+
+       (void)tms470_flash_initialize_internal_state_machine(bank);
+
+       /* force max wait states */
+       target_read_u32(target, 0xFFE88004, &fmbac2);
+       target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
+
+       /* save current access mode, force normal read mode */
+       target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
+       target_write_u32(target, 0xFFE89C00, 0x00);
+
+       /*
+        * Disable Level 1 protection for all sectors to be erased/written.
+        */
+       target_read_u32(target, 0xFFE88008, &fmbsea);
+       target_write_u32(target, 0xFFE88008, 0xffff);
+       target_read_u32(target, 0xFFE8800C, &fmbseb);
+       target_write_u32(target, 0xFFE8800C, 0xffff);
+
+       /* read MAXPP */
+       target_read_u32(target, 0xFFE8A07C, &fmmaxpp);
+
+       for (i = 0; i < count; i += 2)
+       {
+               uint32_t addr = bank->base + offset + i;
+               uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1];
+
+               if (word != 0xffff)
+               {
+                       LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr);
+
+                       /* clear status register */
+                       target_write_u16(target, addr, 0x0040);
+                       /* program flash command */
+                       target_write_u16(target, addr, 0x0010);
+                       /* burn the 16-bit word (big-endian) */
+                       target_write_u16(target, addr, word);
+
+                       /*
+                        * Monitor FMMSTAT, busy until clear, then check and other flags
+                        * for ultimate result of the operation.
+                        */
+                       do
+                       {
+                               target_read_u32(target, 0xFFE8BC0C, &fmmstat);
+                               if (fmmstat & 0x0100)
+                               {
+                                       alive_sleep(1);
+                               }
+                       }
+                       while (fmmstat & 0x0100);
+
+                       if (fmmstat & 0x3ff)
+                       {
+                               LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat);
+                               LOG_ERROR("Could not program word 0x%04x at address 0x%08" PRIx32 ".", word, addr);
+                               result = ERROR_FLASH_OPERATION_FAILED;
+                               break;
+                       }
+               }
+               else
+               {
+                       LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr);
+               }
+       }
+
+       /* restore */
+       target_write_u32(target, 0xFFE88008, fmbsea);
+       target_write_u32(target, 0xFFE8800C, fmbseb);
+       target_write_u32(target, 0xFFE88004, fmbac2);
+       target_write_u32(target, 0xFFE89C00, orig_fmregopt);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl);
+
+       return result;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_probe(struct flash_bank *bank)
+{
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_WARNING("Cannot communicate... target not halted.");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       return tms470_read_part_info(bank);
+}
+
+static int tms470_auto_probe(struct flash_bank *bank)
+{
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+
+       if (tms470_info->device_ident_reg)
+               return ERROR_OK;
+       return tms470_probe(bank);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_erase_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+       int sector, result = ERROR_OK;
+       uint32_t fmmac2, fmbac2, glbctrl, orig_fmregopt;
+       static uint8_t buffer[64 * 1024];
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!tms470_info->device_ident_reg)
+       {
+               tms470_read_part_info(bank);
+       }
+
+       /* set GLBCTRL.4  */
+       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
+
+       /* save current access mode, force normal read mode */
+       target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
+       target_write_u32(target, 0xFFE89C00, 0x00);
+
+       /* enable the appropriate bank */
+       target_read_u32(target, 0xFFE8BC04, &fmmac2);
+       target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
+
+       /* TCR = 0 */
+       target_write_u32(target, 0xFFE8BC10, 0x2fc0);
+
+       /* clear TEZ in fmbrdy */
+       target_write_u32(target, 0xFFE88010, 0x0b);
+
+       /* save current wait states, force max */
+       target_read_u32(target, 0xFFE88004, &fmbac2);
+       target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
+
+       /*
+        * The TI primitives inspect the flash memory by reading one 32-bit
+        * word at a time.  Here we read an entire sector and inspect it in
+        * an attempt to reduce the JTAG overhead.
+        */
+       for (sector = 0; sector < bank->num_sectors; sector++)
+       {
+               if (bank->sectors[sector].is_erased != 1)
+               {
+                       uint32_t i, addr = bank->base + bank->sectors[sector].offset;
+
+                       LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
+
+                       target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
+
+                       bank->sectors[sector].is_erased = 1;
+                       for (i = 0; i < bank->sectors[sector].size; i++)
+                       {
+                               if (buffer[i] != 0xff)
+                               {
+                                       LOG_WARNING("tms470 bank %d, sector %d, not erased.", tms470_info->ordinal, sector);
+                                       LOG_WARNING("at location 0x%08" PRIx32 ": flash data is 0x%02x.", addr + i, buffer[i]);
+
+                                       bank->sectors[sector].is_erased = 0;
+                                       break;
+                               }
+                       }
+               }
+               if (bank->sectors[sector].is_erased != 1)
+               {
+                       result = ERROR_FLASH_SECTOR_NOT_ERASED;
+                       break;
+               }
+               else
+               {
+                       LOG_INFO("sector erased");
+               }
+       }
+
+       /* reset TEZ, wait states, read mode, GLBCTRL.4 */
+       target_write_u32(target, 0xFFE88010, 0x0f);
+       target_write_u32(target, 0xFFE88004, fmbac2);
+       target_write_u32(target, 0xFFE89C00, orig_fmregopt);
+       target_write_u32(target, 0xFFFFFFDC, glbctrl);
+
+       return result;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_protect_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+       int sector, result = ERROR_OK;
+       uint32_t fmmac2, fmbsea, fmbseb;
+
+       if (target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!tms470_info->device_ident_reg)
+       {
+               tms470_read_part_info(bank);
+       }
+
+       /* enable the appropriate bank */
+       target_read_u32(target, 0xFFE8BC04, &fmmac2);
+       target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
+
+       target_read_u32(target, 0xFFE88008, &fmbsea);
+       target_read_u32(target, 0xFFE8800C, &fmbseb);
+
+       for (sector = 0; sector < bank->num_sectors; sector++)
+       {
+               int protected;
+
+               if (sector < 16)
+               {
+                       protected = fmbsea & (1 << sector) ? 0 : 1;
+                       bank->sectors[sector].is_protected = protected;
+               }
+               else
+               {
+                       protected = fmbseb & (1 << (sector - 16)) ? 0 : 1;
+                       bank->sectors[sector].is_protected = protected;
+               }
+
+               LOG_DEBUG("bank %d sector %d is %s", tms470_info->ordinal, sector, protected ? "protected" : "not protected");
+       }
+
+       return result;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tms470_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       int used = 0;
+       struct tms470_flash_bank *tms470_info = bank->driver_priv;
+
+       if (!tms470_info->device_ident_reg)
+       {
+               tms470_read_part_info(bank);
+       }
+
+       if (!tms470_info->device_ident_reg)
+       {
+               (void)snprintf(buf, buf_size, "Cannot identify target as a TMS470\n");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       used += snprintf(buf, buf_size, "\ntms470 information: Chip is %s\n", tms470_info->part_name);
+       buf += used;
+       buf_size -= used;
+
+       used += snprintf(buf, buf_size, "Flash protection level 2 is %s\n", tms470_check_flash_unlocked(bank->target) == ERROR_OK ? "disabled" : "enabled");
+       buf += used;
+       buf_size -= used;
+
+       return ERROR_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * flash bank tms470 <base> <size> <chip_width> <bus_width> <target>
+ * [options...]
+ */
+
+FLASH_BANK_COMMAND_HANDLER(tms470_flash_bank_command)
+{
+       bank->driver_priv = malloc(sizeof(struct tms470_flash_bank));
+
+       if (!bank->driver_priv)
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       (void)memset(bank->driver_priv, 0, sizeof(struct tms470_flash_bank));
+
+       return ERROR_OK;
+}
+
+struct flash_driver tms470_flash = {
+               .name = "tms470",
+               .commands = tms470_command_handlers,
+               .flash_bank_command = &tms470_flash_bank_command,
+               .erase = &tms470_erase,
+               .protect = &tms470_protect,
+               .write = &tms470_write,
+               .probe = &tms470_probe,
+               .auto_probe = &tms470_auto_probe,
+               .erase_check = &tms470_erase_check,
+               .protect_check = &tms470_protect_check,
+               .info = &tms470_info,
+       };
diff --git a/src/flash/nor/tms470.h b/src/flash/nor/tms470.h
new file mode 100644 (file)
index 0000000..f275e51
--- /dev/null
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *   Copyright (C) 2007,2008 by Christopher Kilgour                        *
+ *   techie |_at_| whiterocker |_dot_| com                                 *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef TMS470_DOT_H
+#define TMS470_DOT_H
+
+#include "flash.h"
+
+struct tms470_flash_bank
+{
+       unsigned ordinal;
+
+       /* device identification register */
+       uint32_t device_ident_reg;
+       uint32_t silicon_version;
+       uint32_t technology_family;
+       uint32_t rom_flash;
+       uint32_t part_number;
+       char * part_name;
+
+};
+
+#endif /* TMS470_DOT_H */
diff --git a/src/flash/ocl.c b/src/flash/ocl.c
deleted file mode 100644 (file)
index 388395f..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007 by Pavel Chromy                                    *
- *   chromy@asix.cz                                                        *
- *                                                                         *
- *   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 "ocl.h"
-#include "flash.h"
-#include "embeddedice.h"
-
-
-struct ocl_priv
-{
-       struct arm_jtag *jtag_info;
-       unsigned int buflen;
-       unsigned int bufalign;
-};
-
-static int ocl_erase_check(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-static int ocl_protect_check(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-/* flash_bank ocl 0 0 0 0 <target#> */
-FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
-{
-       struct arm7_9_common *arm7_9;
-       struct ocl_priv *ocl;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank ocl configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       arm7_9 = target_to_arm7_9(bank->target);
-       if (!is_arm7_9(arm7_9))
-               return ERROR_TARGET_INVALID;
-
-       ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv));
-       ocl->jtag_info = &arm7_9->jtag_info;
-       ocl->buflen = 0;
-       ocl->bufalign = 1;
-
-       return ERROR_OK;
-}
-
-static int ocl_erase(struct flash_bank *bank, int first, int last)
-{
-       struct ocl_priv *ocl = bank->driver_priv;
-       int retval;
-       uint32_t dcc_buffer[3];
-
-       /* check preconditions */
-       if (bank->num_sectors == 0)
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       if (bank->target->state != TARGET_RUNNING)
-       {
-               LOG_ERROR("target has to be running to communicate with the loader");
-               return ERROR_TARGET_NOT_RUNNING;
-       }
-
-       if ((first == 0) && (last == bank->num_sectors - 1))
-       {
-               dcc_buffer[0] = OCL_ERASE_ALL;
-               if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-                       return retval;
-       }
-       else
-       {
-               dcc_buffer[0] = OCL_ERASE_BLOCK;
-               dcc_buffer[1] = first;
-               dcc_buffer[2] = last;
-               if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3) != ERROR_OK))
-                       return retval;
-       }
-
-       /* wait for response, fixed timeout of 1 s */
-       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
-       {
-               if (retval == ERROR_TARGET_TIMEOUT)
-                       LOG_ERROR("loader not responding");
-               return retval;
-       }
-
-       /* receive response */
-       if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1) != ERROR_OK))
-               return retval;
-
-       if (dcc_buffer[1] != OCL_CMD_DONE)
-       {
-               if (dcc_buffer[0] == OCL_ERASE_ALL)
-                       LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
-               else
-                       LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       return ERROR_OK;
-}
-
-static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct ocl_priv *ocl = bank->driver_priv;
-       int retval;
-       uint32_t *dcc_buffer;
-       uint32_t *dcc_bufptr;
-       int byteofs;
-       int runlen;
-       uint32_t chksum;
-
-       int i;
-
-       /* check preconditions */
-       if (ocl->buflen == 0 || ocl->bufalign == 0)
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       if (bank->target->state != TARGET_RUNNING)
-       {
-               LOG_ERROR("target has to be running to communicate with the loader");
-               return ERROR_TARGET_NOT_RUNNING;
-       }
-
-       /* allocate buffer for max. ocl buffer + overhead */
-       dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
-
-       while (count)
-       {
-               if (count + (offset % ocl->bufalign) > ocl->buflen)
-                       runlen = ocl->buflen - (offset % ocl->bufalign);
-               else
-                       runlen = count;
-
-               dcc_buffer[0] = OCL_FLASH_BLOCK | runlen;
-               dcc_buffer[1] = offset;
-               dcc_bufptr = &dcc_buffer[2];
-
-               *dcc_bufptr = 0xffffffff;
-               byteofs = (offset % ocl->bufalign) % 4;
-               chksum = OCL_CHKS_INIT;
-
-               /* copy data to DCC buffer in proper byte order and properly aligned */
-               for (i = 0; i < runlen; i++)
-               {
-                       switch (byteofs++)
-                       {
-                               case 0:
-                                       *dcc_bufptr &= *(buffer++) | 0xffffff00;
-                                       break;
-                               case 1:
-                                       *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff;
-                                       break;
-                               case 2:
-                                       *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff;
-                                       break;
-                               case 3:
-                                       *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff;
-                                       chksum ^= *(dcc_bufptr++);
-                                       *dcc_bufptr = 0xffffffff;
-                                       byteofs = 0;
-                                       break;
-                       }
-               }
-
-               /* add the remaining word to checksum */
-               if (byteofs)
-                       chksum ^= *(dcc_bufptr++);
-
-               *(dcc_bufptr++) = chksum;
-
-               /* send the data */
-               if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer)) != ERROR_OK)
-               {
-                       free(dcc_buffer);
-                 return retval;
-               }
-
-               /* wait for response, fixed timeout of 1 s */
-               if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
-               {
-                       if (retval == ERROR_TARGET_TIMEOUT)
-                               LOG_ERROR("loader not responding");
-                       free(dcc_buffer);
-                       return retval;
-               }
-
-               /* receive response */
-               if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               {
-                       free(dcc_buffer);
-                       return retval;
-               }
-
-               if (dcc_buffer[0] != OCL_CMD_DONE)
-               {
-                       LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
-                       free(dcc_buffer);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               count -= runlen;
-               offset += runlen;
-       }
-
-       free(dcc_buffer);
-       return ERROR_OK;
-}
-
-static int ocl_probe(struct flash_bank *bank)
-{
-       struct ocl_priv *ocl = bank->driver_priv;
-       int retval;
-       uint32_t dcc_buffer[1];
-       int sectsize;
-       int i;
-
-       /* purge pending data in DCC */
-       embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
-
-       dcc_buffer[0] = OCL_PROBE;
-       if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               return retval;
-
-       /* wait for response, fixed timeout of 1 s */
-       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
-       {
-               if (retval == ERROR_TARGET_TIMEOUT)
-                       LOG_ERROR("loader not responding");
-               return retval;
-       }
-
-       /* receive response */
-       if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               return retval;
-
-       if (dcc_buffer[0] != OCL_CMD_DONE)
-       {
-               LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* receive and fill in parameters, detection of loader is important, receive it one by one */
-       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
-               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               return retval;
-       bank->base = dcc_buffer[0];
-
-       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
-               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               return retval;
-       bank->size = dcc_buffer[0];
-
-       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
-               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               return retval;
-       bank->num_sectors = dcc_buffer[0];
-
-       if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
-               || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
-               return retval;
-       ocl->buflen = dcc_buffer[0] & 0xffff;
-       ocl->bufalign = dcc_buffer[0] >> 16;
-
-       bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
-       if (bank->num_sectors == 0)
-       {
-               LOG_ERROR("number of sectors shall be non zero value");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-       if (bank->size % bank->num_sectors) {
-               LOG_ERROR("bank size not divisible by number of sectors");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-       sectsize = bank->size / bank->num_sectors;
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               bank->sectors[i].offset = i * sectsize;
-               bank->sectors[i].size = sectsize;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = -1;
-       }
-
-       if (ocl->bufalign == 0)
-               ocl->bufalign = 1;
-
-       if (ocl->buflen == 0)
-       {
-               LOG_ERROR("buflen shall be non zero value");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign))
-       {
-               LOG_ERROR("buflen is not multiple of bufalign");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       if (ocl->buflen % 4)
-       {
-               LOG_ERROR("buflen shall be divisible by 4");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       return ERROR_OK;
-}
-
-static int ocl_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       return ERROR_OK;
-}
-
-static int ocl_auto_probe(struct flash_bank *bank)
-{
-       struct ocl_priv *ocl = bank->driver_priv;
-
-       if (ocl->buflen == 0 || ocl->bufalign == 0)
-               return ERROR_FLASH_BANK_NOT_PROBED;
-
-       return ERROR_OK;
-}
-
-struct flash_driver ocl_flash = {
-               .name = "ocl",
-               .flash_bank_command = &ocl_flash_bank_command,
-               .erase = &ocl_erase,
-               .protect = &ocl_protect,
-               .write = &ocl_write,
-               .probe = &ocl_probe,
-               .erase_check = &ocl_erase_check,
-               .protect_check = &ocl_protect_check,
-               .info = &ocl_info,
-               .auto_probe = &ocl_auto_probe,
-       };
diff --git a/src/flash/ocl.h b/src/flash/ocl.h
deleted file mode 100644 (file)
index d5c430b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007 by Pavel Chromy                                    *
- *   chromy@asix.cz                                                        *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef OCL_H
-#define OCL_H
-
-/* command/response mask */
-#define OCL_CMD_MASK 0xFFFF0000L
-
-/* commads */
-#define OCL_FLASH_BLOCK 0x0CFB0000L
-#define OCL_ERASE_BLOCK 0x0CEB0000L
-#define OCL_ERASE_ALL 0x0CEA0000L
-#define OCL_PROBE 0x0CBE0000L
-
-/* responses */
-#define OCL_CMD_DONE 0x0ACD0000L
-#define OCL_CMD_ERR 0x0ACE0000L
-#define OCL_CHKS_FAIL 0x0ACF0000L
-#define OCL_BUFF_OVER 0x0AB00000L
-
-#define OCL_CHKS_INIT 0xC100CD0CL
-
-#endif /* OCL_H */
diff --git a/src/flash/pic32mx.c b/src/flash/pic32mx.c
deleted file mode 100644 (file)
index 9bb6c97..0000000
+++ /dev/null
@@ -1,922 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   Copyright (C) 2008 by John McCarthy                                   *
- *   jgmcc@magma.ca                                                        *
- *                                                                         *
- *   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 "pic32mx.h"
-#include "mips32.h"
-
-
-static
-struct pic32mx_devs_s {
-       uint8_t devid;
-       char    *name;
-       uint32_t        pfm_size;
-} pic32mx_devs[] = {
-       { 0x78, "460F512L USB", 512 },
-       { 0x74, "460F256L USB", 256 },
-       { 0x6D, "440F128L USB", 128 },
-       { 0x56, "440F512H USB", 512 },
-       { 0x52, "440F256H USB", 256 },
-       { 0x4D, "440F128H USB", 128 },
-       { 0x42, "420F032H USB",  32 },
-       { 0x38, "360F512L",     512 },
-       { 0x34, "360F256L",     256 },
-       { 0x2D, "340F128L",     128 },
-       { 0x2A, "320F128L",     128 },
-       { 0x16, "340F512H",     512 },
-       { 0x12, "340F256H",     256 },
-       { 0x0D, "340F128H",     128 },
-       { 0x0A, "320F128H",     128 },
-       { 0x06, "320F064H",      64 },
-       { 0x02, "320F032H",      32 },
-       { 0x00, NULL, 0 }
-};
-
-static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr);
-static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word);
-
-/* flash bank pic32mx <base> <size> 0 0 <target#>
- */
-FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command)
-{
-       struct pic32mx_flash_bank *pic32mx_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank pic32mx configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank));
-       bank->driver_priv = pic32mx_info;
-
-       pic32mx_info->write_algorithm = NULL;
-       pic32mx_info->probed = 0;
-
-       return ERROR_OK;
-}
-
-static uint32_t pic32mx_get_flash_status(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint32_t status;
-
-       target_read_u32(target, PIC32MX_NVMCON, &status);
-
-       return status;
-}
-
-static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout)
-{
-       uint32_t status;
-
-       /* wait for busy to clear */
-       while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0))
-       {
-               LOG_DEBUG("status: 0x%" PRIx32, status);
-               alive_sleep(1);
-       }
-       if (timeout <= 0)
-               LOG_DEBUG("timeout: status: 0x%" PRIx32, status);
-
-       return status;
-}
-
-static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout)
-{
-       struct target *target = bank->target;
-       uint32_t status;
-
-       target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
-
-       /* unlock flash registers */
-       target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1);
-       target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2);
-
-       /* start operation */
-       target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR);
-
-       status = pic32mx_wait_status_busy(bank, timeout);
-
-       /* lock flash registers */
-       target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN);
-
-       return status;
-}
-
-static int pic32mx_protect_check(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-
-       uint32_t devcfg0;
-       int s;
-       int num_pages;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       target_read_u32(target, PIC32MX_DEVCFG0, &devcfg0);
-       if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */
-               num_pages = 0xffff;  /* All pages protected */
-       else if (bank->base == PIC32MX_KSEG1_BOOT_FLASH)
-       {
-               if (devcfg0 & (1 << 24))
-                       num_pages = 0;       /* All pages unprotected */
-               else
-                       num_pages = 0xffff;  /* All pages protected */
-       }
-       else /* pgm flash */
-               num_pages = (~devcfg0 >> 12) & 0xff;
-       for (s = 0; s < bank->num_sectors && s < num_pages; s++)
-               bank->sectors[s].is_protected = 1;
-       for (; s < bank->num_sectors; s++)
-               bank->sectors[s].is_protected = 0;
-
-       return ERROR_OK;
-}
-
-static int pic32mx_erase(struct flash_bank *bank, int first, int last)
-{
-       struct target *target = bank->target;
-       int i;
-       uint32_t status;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first == 0) && (last == (bank->num_sectors - 1)) && (bank->base == PIC32MX_KSEG0_PGM_FLASH || bank->base == PIC32MX_KSEG1_PGM_FLASH))
-       {
-               LOG_DEBUG("Erasing entire program flash");
-               status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);
-               if (status & NVMCON_NVMERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               if (status & NVMCON_LVDERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               return ERROR_OK;
-       }
-
-       for (i = first; i <= last; i++)
-       {
-               if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
-                       target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(bank->base + bank->sectors[i].offset));
-               else
-                       target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(bank->base + bank->sectors[i].offset));
-
-               status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);
-
-               if (status & NVMCON_NVMERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               if (status & NVMCON_LVDERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               bank->sectors[i].is_erased = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       struct pic32mx_flash_bank *pic32mx_info = NULL;
-       struct target *target = bank->target;
-#if 0
-       uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
-       int i, reg, bit;
-       int status;
-       uint32_t protection;
-#endif
-
-       pic32mx_info = bank->driver_priv;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-#if 0
-       if ((first && (first % pic32mx_info->ppage_size)) || ((last + 1) && (last + 1) % pic32mx_info->ppage_size))
-       {
-               LOG_WARNING("sector start/end incorrect - stm32 has %dK sector protection", pic32mx_info->ppage_size);
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* medium density - each bit refers to a 4bank protection
-        * high density - each bit refers to a 2bank protection */
-       target_read_u32(target, PIC32MX_FLASH_WRPR, &protection);
-
-       prot_reg[0] = (uint16_t)protection;
-       prot_reg[1] = (uint16_t)(protection >> 8);
-       prot_reg[2] = (uint16_t)(protection >> 16);
-       prot_reg[3] = (uint16_t)(protection >> 24);
-
-       if (pic32mx_info->ppage_size == 2)
-       {
-               /* high density flash */
-
-               /* bit 7 controls sector 62 - 255 protection */
-               if (last > 61)
-               {
-                       if (set)
-                               prot_reg[3] &= ~(1 << 7);
-                       else
-                               prot_reg[3] |= (1 << 7);
-               }
-
-               if (first > 61)
-                       first = 62;
-               if (last > 61)
-                       last = 61;
-
-               for (i = first; i <= last; i++)
-               {
-                       reg = (i / pic32mx_info->ppage_size) / 8;
-                       bit = (i / pic32mx_info->ppage_size) - (reg * 8);
-
-                       if (set)
-                               prot_reg[reg] &= ~(1 << bit);
-                       else
-                               prot_reg[reg] |= (1 << bit);
-               }
-       }
-       else
-       {
-               /* medium density flash */
-               for (i = first; i <= last; i++)
-               {
-                       reg = (i / pic32mx_info->ppage_size) / 8;
-                       bit = (i / pic32mx_info->ppage_size) - (reg * 8);
-
-                       if (set)
-                               prot_reg[reg] &= ~(1 << bit);
-                       else
-                               prot_reg[reg] |= (1 << bit);
-               }
-       }
-
-       if ((status = pic32mx_erase_options(bank)) != ERROR_OK)
-               return status;
-
-       pic32mx_info->option_bytes.protection[0] = prot_reg[0];
-       pic32mx_info->option_bytes.protection[1] = prot_reg[1];
-       pic32mx_info->option_bytes.protection[2] = prot_reg[2];
-       pic32mx_info->option_bytes.protection[3] = prot_reg[3];
-
-       return pic32mx_write_options(bank);
-#else
-       return ERROR_OK;
-#endif
-}
-
-static int pic32mx_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct target *target = bank->target;
-       uint32_t buffer_size = 512;
-       struct working_area *source;
-       uint32_t address = bank->base + offset;
-       int retval = ERROR_OK;
-#if 0
-       struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
-       struct armv7m_algorithm armv7m_info;
-
-       uint8_t pic32mx_flash_write_code[] = {
-                                                                       /* write: */
-               0xDF, 0xF8, 0x24, 0x40,         /* ldr  r4, PIC32MX_FLASH_CR */
-               0x09, 0x4D,                                     /* ldr  r5, PIC32MX_FLASH_SR */
-               0x4F, 0xF0, 0x01, 0x03,         /* mov  r3, #1 */
-               0x23, 0x60,                                     /* str  r3, [r4, #0] */
-               0x30, 0xF8, 0x02, 0x3B,         /* ldrh r3, [r0], #2 */
-               0x21, 0xF8, 0x02, 0x3B,         /* strh r3, [r1], #2 */
-                                                                       /* busy: */
-               0x2B, 0x68,                                     /* ldr  r3, [r5, #0] */
-               0x13, 0xF0, 0x01, 0x0F,         /* tst  r3, #0x01 */
-               0xFB, 0xD0,                                     /* beq  busy */
-               0x13, 0xF0, 0x14, 0x0F,         /* tst  r3, #0x14 */
-               0x01, 0xD1,                                     /* bne  exit */
-               0x01, 0x3A,                                     /* subs r2, r2, #1 */
-               0xED, 0xD1,                                     /* bne  write */
-                                                                       /* exit: */
-               0xFE, 0xE7,                                     /* b exit */
-               0x10, 0x20, 0x02, 0x40,         /* PIC32MX_FLASH_CR:    .word 0x40022010 */
-               0x0C, 0x20, 0x02, 0x40          /* PIC32MX_FLASH_SR:    .word 0x4002200C */
-       };
-
-       /* flash write code */
-       if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code), &pic32mx_info->write_algorithm) != ERROR_OK)
-       {
-               LOG_WARNING("no working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
-
-       if ((retval = target_write_buffer(target, pic32mx_info->write_algorithm->address, sizeof(pic32mx_flash_write_code), pic32mx_flash_write_code)) != ERROR_OK)
-               return retval;
-#endif
-
-       /* memory buffer */
-       if (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
-       {
-#if 0
-               /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
-               if (pic32mx_info->write_algorithm)
-                       target_free_working_area(target, pic32mx_info->write_algorithm);
-#endif
-
-               LOG_WARNING("no large enough working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       }
-
-       while (count >= buffer_size/4)
-       {
-               uint32_t status;
-
-               if ((retval = target_write_buffer(target, source->address, buffer_size, buffer)) != ERROR_OK) {
-                       LOG_ERROR("Failed to write row buffer (%d words) to RAM", (int)(buffer_size/4));
-                       break;
-               }
-
-#if 0
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, buffer_size/4);
-
-               if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, pic32mx_info->write_algorithm->address, \
-                               pic32mx_info->write_algorithm->address + (sizeof(pic32mx_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
-               {
-                       LOG_ERROR("error executing pic32mx flash write algorithm");
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)
-               {
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-#endif
-               status = pic32mx_write_row(bank, address, source->address);
-               if (status & NVMCON_NVMERR) {
-                       LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-               if (status & NVMCON_LVDERR) {
-                       LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer  += buffer_size;
-               address += buffer_size;
-               count   -= buffer_size/4;
-       }
-
-       target_free_working_area(target, source);
-
-       while (count > 0)
-       {
-               uint32_t value;
-               memcpy(&value, buffer, sizeof(uint32_t));
-
-               uint32_t status = pic32mx_write_word(bank, address, value);
-               if (status & NVMCON_NVMERR) {
-                       LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-               if (status & NVMCON_LVDERR) {
-                       LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer  += 4;
-               address += 4;
-               count--;
-       }
-
-       return retval;
-}
-
-static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
-{
-       struct target *target = bank->target;
-
-       if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
-               target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(address));
-       else
-               target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(address));
-       target_write_u32(target, PIC32MX_NVMDATA, word);
-
-       return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);
-}
-
-/*
- * Write a 128 word (512 byte) row to flash address from RAM srcaddr.
- */
-static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr)
-{
-       struct target *target = bank->target;
-
-       LOG_DEBUG("addr: 0x%08" PRIx32 " srcaddr: 0x%08" PRIx32 "", address, srcaddr);
-
-       if (address >= PIC32MX_KSEG1_PGM_FLASH)
-               target_write_u32(target, PIC32MX_NVMADDR,    KS1Virt2Phys(address));
-       else
-               target_write_u32(target, PIC32MX_NVMADDR,    KS0Virt2Phys(address));
-       if (srcaddr >= PIC32MX_KSEG1_RAM)
-               target_write_u32(target, PIC32MX_NVMSRCADDR, KS1Virt2Phys(srcaddr));
-       else
-               target_write_u32(target, PIC32MX_NVMSRCADDR, KS0Virt2Phys(srcaddr));
-
-       return pic32mx_nvm_exec(bank, NVMCON_OP_ROW_PROG, 100);
-}
-
-static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       uint32_t words_remaining = (count / 4);
-       uint32_t bytes_remaining = (count & 0x00000003);
-       uint32_t address = bank->base + offset;
-       uint32_t bytes_written = 0;
-       uint32_t status;
-       int retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset & 0x3)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       /* multiple words (4-byte) to be programmed? */
-       if (words_remaining > 0)
-       {
-               /* try using a block write */
-               if ((retval = pic32mx_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
-               {
-                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                       {
-                               /* if block write failed (no sufficient working area),
-                                * we use normal (slow) single dword accesses */
-                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
-                       }
-                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
-                       {
-                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-               }
-               else
-               {
-                       buffer += words_remaining * 4;
-                       address += words_remaining * 4;
-                       words_remaining = 0;
-               }
-       }
-
-       while (words_remaining > 0)
-       {
-               uint32_t value;
-               memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
-
-               status = pic32mx_write_word(bank, address, value);
-               if (status & NVMCON_NVMERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               if (status & NVMCON_LVDERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-
-               bytes_written += 4;
-               words_remaining--;
-               address += 4;
-       }
-
-       if (bytes_remaining)
-       {
-               uint32_t value = 0xffffffff;
-               memcpy(&value, buffer + bytes_written, bytes_remaining);
-
-               status = pic32mx_write_word(bank, address, value);
-               if (status & NVMCON_NVMERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               if (status & NVMCON_LVDERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int pic32mx_probe(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
-       struct mips32_common *mips32 = target->arch_info;
-       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
-       int i;
-       uint16_t num_pages = 0;
-       uint32_t device_id;
-       int page_size;
-
-       pic32mx_info->probed = 0;
-
-       device_id = ejtag_info->idcode;
-       LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%02x, ver 0x%03x)",
-                         device_id,
-                         (unsigned)((device_id >> 1)&0x7ff),
-                         (unsigned)((device_id >> 12)&0xff),
-                         (unsigned)((device_id >> 20)&0xfff));
-
-       if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
-               LOG_WARNING("Cannot identify target as a PIC32MX family.");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       page_size = 4096;
-       if (bank->base == PIC32MX_KSEG1_BOOT_FLASH || bank->base == 1) {
-               /* 0xBFC00000: Boot flash size fixed at 12k */
-               num_pages = 12;
-       } else {
-               /* 0xBD000000: Program flash size varies with device */
-               for (i = 0; pic32mx_devs[i].name != NULL; i++)
-                       if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
-                               num_pages = pic32mx_devs[i].pfm_size;
-                               break;
-                       }
-               if (pic32mx_devs[i].name == NULL) {
-                       LOG_WARNING("Cannot identify target as a PIC32MX family.");
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-       }
-
-#if 0
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* get flash size from target */
-       if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)
-       {
-               /* failed reading flash size, default to max target family */
-               num_pages = 0xffff;
-       }
-#endif
-
-       LOG_INFO("flash size = %dkbytes", num_pages);
-
-       /* calculate numbers of pages */
-       num_pages /= (page_size / 1024);
-
-       if (bank->base == 0) bank->base = PIC32MX_KSEG1_PGM_FLASH;
-       if (bank->base == 1) bank->base = PIC32MX_KSEG1_BOOT_FLASH;
-       bank->size = (num_pages * page_size);
-       bank->num_sectors = num_pages;
-       bank->chip_width = 4;
-       bank->bus_width  = 4;
-       bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
-
-       for (i = 0; i < num_pages; i++)
-       {
-               bank->sectors[i].offset = i * page_size;
-               bank->sectors[i].size = page_size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 1;
-       }
-
-       pic32mx_info->probed = 1;
-
-       return ERROR_OK;
-}
-
-static int pic32mx_auto_probe(struct flash_bank *bank)
-{
-       struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
-       if (pic32mx_info->probed)
-               return ERROR_OK;
-       return pic32mx_probe(bank);
-}
-
-#if 0
-COMMAND_HANDLER(pic32mx_handle_part_id_command)
-{
-       return ERROR_OK;
-}
-#endif
-
-static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       struct target *target = bank->target;
-       struct mips32_common *mips32 = target->arch_info;
-       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
-       uint32_t device_id;
-       int printed = 0, i;
-
-       device_id = ejtag_info->idcode;
-
-       if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
-               snprintf(buf, buf_size,
-                                "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n",
-                                (unsigned)((device_id >> 1)&0x7ff),
-                                PIC32MX_MANUF_ID);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       for (i = 0; pic32mx_devs[i].name != NULL; i++)
-               if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
-                       printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
-                       break;
-               }
-       if (pic32mx_devs[i].name == NULL) {
-               snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family\n");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       buf += printed;
-       buf_size -= printed;
-       printed = snprintf(buf, buf_size, "  Ver: 0x%03x",
-                                          (unsigned)((device_id >> 20)&0xfff));
-
-       return ERROR_OK;
-}
-
-#if 0
-COMMAND_HANDLER(pic32mx_handle_lock_command)
-{
-       struct target *target = NULL;
-       struct pic32mx_flash_bank *pic32mx_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "pic32mx lock <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       pic32mx_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (pic32mx_erase_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "pic32mx failed to erase options");
-               return ERROR_OK;
-       }
-
-       /* set readout protection */
-       pic32mx_info->option_bytes.RDP = 0;
-
-       if (pic32mx_write_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "pic32mx failed to lock device");
-               return ERROR_OK;
-       }
-
-       command_print(CMD_CTX, "pic32mx locked");
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(pic32mx_handle_unlock_command)
-{
-       struct target *target = NULL;
-       struct pic32mx_flash_bank *pic32mx_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "pic32mx unlock <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       pic32mx_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (pic32mx_erase_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "pic32mx failed to unlock device");
-               return ERROR_OK;
-       }
-
-       if (pic32mx_write_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "pic32mx failed to lock device");
-               return ERROR_OK;
-       }
-
-       command_print(CMD_CTX, "pic32mx unlocked");
-
-       return ERROR_OK;
-}
-#endif
-
-#if 0
-static int pic32mx_chip_erase(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-#if 0
-       uint32_t status;
-#endif
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       LOG_INFO("PIC32MX chip erase called");
-
-#if 0
-       /* unlock option flash registers */
-       target_write_u32(target, PIC32MX_FLASH_KEYR, KEY1);
-       target_write_u32(target, PIC32MX_FLASH_KEYR, KEY2);
-
-       /* chip erase flash memory */
-       target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER);
-       target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER | FLASH_STRT);
-
-       status = pic32mx_wait_status_busy(bank, 10);
-
-       target_write_u32(target, PIC32MX_FLASH_CR, FLASH_LOCK);
-
-       if (status & FLASH_WRPRTERR)
-       {
-               LOG_ERROR("pic32mx device protected");
-               return ERROR_OK;
-       }
-
-       if (status & FLASH_PGERR)
-       {
-               LOG_ERROR("pic32mx device programming failed");
-               return ERROR_OK;
-       }
-#endif
-
-       return ERROR_OK;
-}
-#endif
-
-COMMAND_HANDLER(pic32mx_handle_chip_erase_command)
-{
-#if 0
-       int i;
-
-       if (CMD_ARGC != 0)
-       {
-               command_print(CMD_CTX, "pic32mx chip_erase");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if (pic32mx_chip_erase(bank) == ERROR_OK)
-       {
-               /* set all sectors as erased */
-               for (i = 0; i < bank->num_sectors; i++)
-               {
-                       bank->sectors[i].is_erased = 1;
-               }
-
-               command_print(CMD_CTX, "pic32mx chip erase complete");
-       }
-       else
-       {
-               command_print(CMD_CTX, "pic32mx chip erase failed");
-       }
-#endif
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
-{
-       uint32_t address, value;
-       int status, res;
-
-       if (CMD_ARGC != 3)
-       {
-               command_print(CMD_CTX, "pic32mx pgm_word <addr> <value> <bank>");
-               return ERROR_OK;
-       }
-
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if (address < bank->base || address >= (bank->base + bank->size))
-       {
-               command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
-               return ERROR_OK;
-       }
-
-       res = ERROR_OK;
-       status = pic32mx_write_word(bank, address, value);
-       if (status & NVMCON_NVMERR)
-               res = ERROR_FLASH_OPERATION_FAILED;
-       if (status & NVMCON_LVDERR)
-               res = ERROR_FLASH_OPERATION_FAILED;
-
-       if (res == ERROR_OK)
-               command_print(CMD_CTX, "pic32mx pgm word complete");
-       else
-               command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
-
-       return ERROR_OK;
-}
-static const struct command_registration pic32mx_exec_command_handlers[] = {
-       {
-               .name = "chip_erase",
-               .handler = &pic32mx_handle_chip_erase_command,
-               .mode = COMMAND_EXEC,
-               .help = "erase device",
-       },
-       {
-               .name = "pgm_word",
-               .handler = &pic32mx_handle_pgm_word_command,
-               .mode = COMMAND_EXEC,
-               .help = "program a word",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration pic32mx_command_handlers[] = {
-       {
-               .name = "pic32mx",
-               .mode = COMMAND_ANY,
-               .help = "pic32mx flash command group",
-               .chain = pic32mx_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver pic32mx_flash = {
-               .name = "pic32mx",
-               .commands = pic32mx_command_handlers,
-               .flash_bank_command = &pic32mx_flash_bank_command,
-               .erase = &pic32mx_erase,
-               .protect = &pic32mx_protect,
-               .write = &pic32mx_write,
-               .probe = &pic32mx_probe,
-               .auto_probe = &pic32mx_auto_probe,
-               .erase_check = &default_flash_mem_blank_check,
-               .protect_check = &pic32mx_protect_check,
-               .info = &pic32mx_info,
-       };
diff --git a/src/flash/pic32mx.h b/src/flash/pic32mx.h
deleted file mode 100644 (file)
index 92f40c2..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   Copyright (C) 2008 by John McCarthy                                   *
- *   jgmcc@magma.ca                                                        *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef PIC32MX_H
-#define PIC32MX_H
-
-#include "flash.h"
-
-struct pic32mx_flash_bank
-{
-       struct working_area *write_algorithm;
-       int devid;
-       int ppage_size;
-       int probed;
-};
-
-#define PIC32MX_MANUF_ID       0x029
-
-/* pic32mx memory locations */
-
-#define PIC32MX_KUSEG_PGM_FLASH                0x7D000000
-#define PIC32MX_KUSEG_RAM                      0x7F000000
-
-#define PIC32MX_KSEG0_RAM                      0x80000000
-#define PIC32MX_KSEG0_PGM_FLASH                0x9D000000
-#define PIC32MX_KSEG0_BOOT_FLASH       0x9FC00000
-
-#define PIC32MX_KSEG1_RAM                      0xA0000000
-#define PIC32MX_KSEG1_PGM_FLASH                0xBD000000
-#define PIC32MX_KSEG1_PERIPHERAL       0xBF800000
-#define PIC32MX_KSEG1_BOOT_FLASH       0xBFC00000
-
-#define PIC32MX_PHYS_RAM                       0x00000000
-#define PIC32MX_PHYS_PGM_FLASH         0x1D000000
-#define PIC32MX_PHYS_PERIPHERALS       0x1F800000
-#define PIC32MX_PHYS_BOOT_FLASH                0x1FC00000
-
-/*
- * Translate Virtual and Physical addresses.
- * Note: These macros only work for KSEG0/KSEG1 addresses.
- */
-#define KS1Virt2Phys(vaddr)                    ((vaddr)-0xA0000000)
-#define Phys2KS1Virt(paddr)                    ((paddr) + 0xA0000000)
-#define KS0Virt2Phys(vaddr)                    ((vaddr)-0x80000000)
-#define Phys2KS0Virt(paddr)                    ((paddr) + 0x80000000)
-
-/* pic32mx configuration register locations */
-
-#define PIC32MX_DEVCFG0                0xBFC02FFC
-#define PIC32MX_DEVCFG1                0xBFC02FF8
-#define PIC32MX_DEVCFG2                0xBFC02FF4
-#define PIC32MX_DEVCFG3                0XBFC02FF0
-#define PIC32MX_DEVID          0xBF80F220
-
-/* pic32mx flash controller register locations */
-
-#define PIC32MX_NVMCON         0xBF80F400
-#define PIC32MX_NVMCONCLR      0xBF80F404
-#define PIC32MX_NVMCONSET      0xBF80F408
-#define PIC32MX_NVMCONINV      0xBF80F40C
-#define NVMCON_NVMWR           (1 << 15)
-#define NVMCON_NVMWREN         (1 << 14)
-#define NVMCON_NVMERR          (1 << 13)
-#define NVMCON_LVDERR          (1 << 12)
-#define NVMCON_LVDSTAT         (1 << 11)
-#define NVMCON_OP_PFM_ERASE            0x5
-#define NVMCON_OP_PAGE_ERASE   0x4
-#define NVMCON_OP_ROW_PROG             0x3
-#define NVMCON_OP_WORD_PROG            0x1
-#define NVMCON_OP_NOP                  0x0
-
-#define PIC32MX_NVMKEY         0xBF80F410
-#define PIC32MX_NVMADDR                0xBF80F420
-#define PIC32MX_NVMADDRCLR     0xBF80F424
-#define PIC32MX_NVMADDRSET     0xBF80F428
-#define PIC32MX_NVMADDRINV     0xBF80F42C
-#define PIC32MX_NVMDATA                0xBF80F430
-#define PIC32MX_NVMSRCADDR     0xBF80F440
-
-/* flash unlock keys */
-
-#define NVMKEY1                        0xAA996655
-#define NVMKEY2                        0x556699AA
-
-struct pic32mx_mem_layout {
-       uint32_t sector_start;
-       uint32_t sector_size;
-};
-
-#endif /* PIC32MX_H */
-
diff --git a/src/flash/stellaris.c b/src/flash/stellaris.c
deleted file mode 100644 (file)
index 771f0a7..0000000
+++ /dev/null
@@ -1,1195 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2006 by Magnus Lundin                                   *
- *   lundin@mlu.mine.nu                                                    *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-
-/***************************************************************************
-* STELLARIS is tested on LM3S811, LM3S6965
-***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "stellaris.h"
-#include "armv7m.h"
-#include "binarybuffer.h"
-#include "algorithm.h"
-
-
-#define DID0_VER(did0) ((did0 >> 28)&0x07)
-
-static int stellaris_read_part_info(struct flash_bank *bank);
-static uint32_t stellaris_get_flash_status(struct flash_bank *bank);
-static void stellaris_set_flash_mode(struct flash_bank *bank,int mode);
-//static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
-
-static int stellaris_mass_erase(struct flash_bank *bank);
-
-static struct {
-       uint32_t partno;
-       char *partname;
-}      StellarisParts[] =
-{
-       {0x01,"LM3S101"},
-       {0x02,"LM3S102"},
-       {0x03,"LM3S1625"},
-       {0x04,"LM3S1626"},
-       {0x05,"LM3S1627"},
-       {0x06,"LM3S1607"},
-       {0x10,"LM3S1776"},
-       {0x19,"LM3S300"},
-       {0x11,"LM3S301"},
-       {0x12,"LM3S310"},
-       {0x1A,"LM3S308"},
-       {0x13,"LM3S315"},
-       {0x14,"LM3S316"},
-       {0x17,"LM3S317"},
-       {0x18,"LM3S318"},
-       {0x15,"LM3S328"},
-       {0x2A,"LM3S600"},
-       {0x21,"LM3S601"},
-       {0x2B,"LM3S608"},
-       {0x22,"LM3S610"},
-       {0x23,"LM3S611"},
-       {0x24,"LM3S612"},
-       {0x25,"LM3S613"},
-       {0x26,"LM3S615"},
-       {0x28,"LM3S617"},
-       {0x29,"LM3S618"},
-       {0x27,"LM3S628"},
-       {0x38,"LM3S800"},
-       {0x31,"LM3S801"},
-       {0x39,"LM3S808"},
-       {0x32,"LM3S811"},
-       {0x33,"LM3S812"},
-       /*{0x33,"LM3S2616"},*/
-       {0x34,"LM3S815"},
-       {0x36,"LM3S817"},
-       {0x37,"LM3S818"},
-       {0x35,"LM3S828"},
-       {0x39,"LM3S2276"},
-       {0x3A,"LM3S2776"},
-       {0x43,"LM3S3651"},
-       {0x44,"LM3S3739"},
-       {0x45,"LM3S3749"},
-       {0x46,"LM3S3759"},
-       {0x48,"LM3S3768"},
-       {0x49,"LM3S3748"},
-       {0x50,"LM3S2678"},
-       {0x51,"LM3S2110"},
-       {0x52,"LM3S2739"},
-       {0x53,"LM3S2651"},
-       {0x54,"LM3S2939"},
-       {0x55,"LM3S2965"},
-       {0x56,"LM3S2432"},
-       {0x57,"LM3S2620"},
-       {0x58,"LM3S2950"},
-       {0x59,"LM3S2412"},
-       {0x5A,"LM3S2533"},
-       {0x61,"LM3S8630"},
-       {0x62,"LM3S8970"},
-       {0x63,"LM3S8730"},
-       {0x64,"LM3S8530"},
-       {0x65,"LM3S8930"},
-       {0x71,"LM3S6610"},
-       {0x72,"LM3S6950"},
-       {0x73,"LM3S6965"},
-       {0x74,"LM3S6110"},
-       {0x75,"LM3S6432"},
-       {0x76,"LM3S6537"},
-       {0x77,"LM3S6753"},
-       {0x78,"LM3S6952"},
-       {0x80,"LM3S2671"},
-       {0x81,"LM3S5632"},
-       {0x82,"LM3S6422"},
-       {0x83,"LM3S6633"},
-       {0x84,"LM3S2139"},
-       {0x85,"LM3S2637"},
-       {0x86,"LM3S8738"},
-       {0x88,"LM3S8938"},
-       {0x89,"LM3S6938"},
-       {0x8A,"LM3S5652"},
-       {0x8B,"LM3S6637"},
-       {0x8C,"LM3S8933"},
-       {0x8D,"LM3S8733"},
-       {0x8E,"LM3S8538"},
-       {0x8F,"LM3S2948"},
-       {0x91,"LM3S5662"},
-       {0x96,"LM3S5732"},
-       {0x97,"LM3S5737"},
-       {0x99,"LM3S5747"},
-       {0x9A,"LM3S5752"},
-       {0x9B,"LM3S5757"},
-       {0x9C,"LM3S5762"},
-       {0x9D,"LM3S5767"},
-       {0xA0,"LM3S5739"},
-       {0xA1,"LM3S6100"},
-       {0xA2,"LM3S2410"},
-       {0xA3,"LM3S6730"},
-       {0xA4,"LM3S2730"},
-       {0xA5,"LM3S6420"},
-       {0xA6,"LM3S8962"},
-       {0xA7,"LM3S5749"},
-       {0xA8,"LM3S5769"},
-       {0xA9,"LM3S5768"},
-       {0xB3,"LM3S1635"},
-       {0xB4,"LM3S1850"},
-       {0xB5,"LM3S1960"},
-       {0xB7,"LM3S1937"},
-       {0xB8,"LM3S1968"},
-       {0xB9,"LM3S1751"},
-       {0xBA,"LM3S1439"},
-       {0xBB,"LM3S1512"},
-       {0xBC,"LM3S1435"},
-       {0xBD,"LM3S1637"},
-       {0xBE,"LM3S1958"},
-       {0xBF,"LM3S1110"},
-       {0xC0,"LM3S1620"},
-       {0xC1,"LM3S1150"},
-       {0xC2,"LM3S1165"},
-       {0xC3,"LM3S1133"},
-       {0xC4,"LM3S1162"},
-       {0xC5,"LM3S1138"},
-       {0xC6,"LM3S1332"},
-       {0xC7,"LM3S1538"},
-       {0xD0,"LM3S6815"},
-       {0xD1,"LM3S6816"},
-       {0xD2,"LM3S6915"},
-       {0xD3,"LM3S6916"},
-       {0xD4,"LM3S2016"},
-       {0xD5,"LM3S1615"},
-       {0xD6,"LM3S1616"},
-       {0xD7,"LM3S8971"},
-       {0xD8,"LM3S1108"},
-       {0xD9,"LM3S1101"},
-       {0xDA,"LM3S1608"},
-       {0xDB,"LM3S1601"},
-       {0xDC,"LM3S1918"},
-       {0xDD,"LM3S1911"},
-       {0xDE,"LM3S2108"},
-       {0xDF,"LM3S2101"},
-       {0xE0,"LM3S2608"},
-       {0xE1,"LM3S2601"},
-       {0xE2,"LM3S2918"},
-       {0xE3,"LM3S2911"},
-       {0xE4,"LM3S6118"},
-       {0xE5,"LM3S6111"},
-       {0xE6,"LM3S6618"},
-       {0xE7,"LM3S6611"},
-       {0xE8,"LM3S6918"},
-       {0xE9,"LM3S6911"},
-       {0,"Unknown part"}
-};
-
-static char * StellarisClassname[5] =
-{
-       "Sandstorm",
-       "Fury",
-       "Unknown",
-       "DustDevil",
-       "Tempest"
-};
-
-/***************************************************************************
-*      openocd command interface                                              *
-***************************************************************************/
-
-/* flash_bank stellaris <base> <size> 0 0 <target#>
- */
-FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command)
-{
-       struct stellaris_flash_bank *stellaris_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank stellaris configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1);
-       bank->base = 0x0;
-       bank->driver_priv = stellaris_info;
-
-       stellaris_info->target_name = "Unknown target";
-
-       /* part wasn't probed for info yet */
-       stellaris_info->did1 = 0;
-
-       /* TODO Specify the main crystal speed in kHz using an optional
-        * argument; ditto, the speed of an external oscillator used
-        * instead of a crystal.  Avoid programming flash using IOSC.
-        */
-       return ERROR_OK;
-}
-
-static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       int printed, device_class;
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-
-       stellaris_read_part_info(bank);
-
-       if (stellaris_info->did1 == 0)
-       {
-               printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");
-               buf += printed;
-               buf_size -= printed;
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (DID0_VER(stellaris_info->did0) > 0)
-       {
-               device_class = (stellaris_info->did0 >> 16) & 0xFF;
-       }
-       else
-       {
-               device_class = 0;
-       }
-       printed = snprintf(buf,
-                          buf_size,
-                          "\nTI/LMI Stellaris information: Chip is "
-                          "class %i (%s) %s rev %c%i\n",
-                          device_class,
-                          StellarisClassname[device_class],
-                          stellaris_info->target_name,
-                          (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)),
-                          (int)((stellaris_info->did0) & 0xFF));
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf,
-                          buf_size,
-                          "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32
-                          ", eproc: %s, ramsize: %ik, flashsize: %ik\n",
-                          stellaris_info->did1,
-                          stellaris_info->did1,
-                          "ARMv7M",
-                          (int)((1 + ((stellaris_info->dc0 >> 16) & 0xFFFF))/4),
-                          (int)((1 + (stellaris_info->dc0 & 0xFFFF))*2));
-       buf += printed;
-       buf_size -= printed;
-
-       printed = snprintf(buf,
-                          buf_size,
-                          "master clock: %ikHz%s, "
-                          "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n",
-                          (int)(stellaris_info->mck_freq / 1000),
-                          stellaris_info->mck_desc,
-                          stellaris_info->rcc,
-                          stellaris_info->rcc2);
-       buf += printed;
-       buf_size -= printed;
-
-       if (stellaris_info->num_lockbits > 0)
-       {
-               printed = snprintf(buf,
-                                  buf_size,
-                                  "pagesize: %" PRIi32 ", lockbits: %i 0x%4.4" PRIx32 ", pages in lock region: %i \n",
-                                  stellaris_info->pagesize,
-                                  stellaris_info->num_lockbits,
-                                  stellaris_info->lockbits,
-                                  (int)(stellaris_info->num_pages/stellaris_info->num_lockbits));
-               buf += printed;
-               buf_size -= printed;
-       }
-       return ERROR_OK;
-}
-
-/***************************************************************************
-*      chip identification and status                                         *
-***************************************************************************/
-
-static uint32_t stellaris_get_flash_status(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint32_t fmc;
-
-       target_read_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, &fmc);
-
-       return fmc;
-}
-
-/** Read clock configuration and set stellaris_info->usec_clocks*/
-
-static const unsigned rcc_xtal[32] = {
-       [0x00] = 1000000,               /* no pll */
-       [0x01] = 1843200,               /* no pll */
-       [0x02] = 2000000,               /* no pll */
-       [0x03] = 2457600,               /* no pll */
-
-       [0x04] = 3579545,
-       [0x05] = 3686400,
-       [0x06] = 4000000,               /* usb */
-       [0x07] = 4096000,
-
-       [0x08] = 4915200,
-       [0x09] = 5000000,               /* usb */
-       [0x0a] = 5120000,
-       [0x0b] = 6000000,               /* (reset) usb */
-
-       [0x0c] = 6144000,
-       [0x0d] = 7372800,
-       [0x0e] = 8000000,               /* usb */
-       [0x0f] = 8192000,
-
-       /* parts before DustDevil use just 4 bits for xtal spec */
-
-       [0x10] = 10000000,              /* usb */
-       [0x11] = 12000000,              /* usb */
-       [0x12] = 12288000,
-       [0x13] = 13560000,
-
-       [0x14] = 14318180,
-       [0x15] = 16000000,              /* usb */
-       [0x16] = 16384000,
-};
-
-static void stellaris_read_clock_info(struct flash_bank *bank)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
-       unsigned xtal;
-       unsigned long mainfreq;
-
-       target_read_u32(target, SCB_BASE | RCC, &rcc);
-       LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc);
-
-       target_read_u32(target, SCB_BASE | RCC2, &rcc2);
-       LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc);
-
-       target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg);
-       LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg);
-
-       stellaris_info->rcc = rcc;
-       stellaris_info->rcc = rcc2;
-
-       sysdiv = (rcc >> 23) & 0xF;
-       usesysdiv = (rcc >> 22) & 0x1;
-       bypass = (rcc >> 11) & 0x1;
-       oscsrc = (rcc >> 4) & 0x3;
-       xtal = (rcc >> 6) & stellaris_info->xtal_mask;
-
-       /* NOTE: post-Sandstorm parts have RCC2 which may override
-        * parts of RCC ... with more sysdiv options, option for
-        * 32768 Hz mainfreq, PLL controls.  On Sandstorm it reads
-        * as zero, so the "use RCC2" flag is always clear.
-        */
-       if (rcc2 & (1 << 31)) {
-               sysdiv = (rcc2 >> 23) & 0x3F;
-               bypass = (rcc2 >> 11) & 0x1;
-               oscsrc = (rcc2 >> 4) & 0x7;
-
-               /* FIXME Tempest parts have an additional lsb for
-                * fractional sysdiv (200 MHz / 2.5 == 80 MHz)
-                */
-       }
-
-       stellaris_info->mck_desc = "";
-
-       switch (oscsrc)
-       {
-               case 0:                         /* MOSC */
-                       mainfreq = rcc_xtal[xtal];
-                       break;
-               case 1:                         /* IOSC */
-                       mainfreq = stellaris_info->iosc_freq;
-                       stellaris_info->mck_desc = stellaris_info->iosc_desc;
-                       break;
-               case 2:                         /* IOSC/4 */
-                       mainfreq = stellaris_info->iosc_freq / 4;
-                       stellaris_info->mck_desc = stellaris_info->iosc_desc;
-                       break;
-               case 3:                         /* lowspeed */
-                       /* Sandstorm doesn't have this 30K +/- 30% osc */
-                       mainfreq = 30000;
-                       stellaris_info->mck_desc = " (±30%)";
-                       break;
-               case 8:                         /* hibernation osc */
-                       /* not all parts support hibernation */
-                       mainfreq = 32768;
-                       break;
-
-               default: /* NOTREACHED */
-                       mainfreq = 0;
-                       break;
-       }
-
-       /* PLL is used if it's not bypassed; its output is 200 MHz
-        * even when it runs at 400 MHz (adds divide-by-two stage).
-        */
-       if (!bypass)
-               mainfreq = 200000000;
-
-       if (usesysdiv)
-               stellaris_info->mck_freq = mainfreq/(1 + sysdiv);
-       else
-               stellaris_info->mck_freq = mainfreq;
-
-       /* Forget old flash timing */
-       stellaris_set_flash_mode(bank, 0);
-}
-
-/* Setup the timimg registers */
-static void stellaris_set_flash_mode(struct flash_bank *bank,int mode)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1);
-       LOG_DEBUG("usecrl = %i",(int)(usecrl));
-       target_write_u32(target, SCB_BASE | USECRL, usecrl);
-}
-
-#if 0
-static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
-{
-       uint32_t status;
-
-       /* Stellaris waits for cmdbit to clear */
-       while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
-       {
-               LOG_DEBUG("status: 0x%x", status);
-               alive_sleep(1);
-       }
-
-       /* Flash errors are reflected in the FLASH_CRIS register */
-
-       return status;
-}
-
-/* Send one command to the flash controller */
-static int stellaris_flash_command(struct flash_bank *bank,uint8_t cmd,uint16_t pagen)
-{
-       uint32_t fmc;
-       struct target *target = bank->target;
-
-       fmc = FMC_WRKEY | cmd;
-       target_write_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, fmc);
-       LOG_DEBUG("Flash command: 0x%x", fmc);
-
-       if (stellaris_wait_status_busy(bank, cmd, 100))
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-#endif
-
-/* Read device id register, main clock frequency register and fill in driver info structure */
-static int stellaris_read_part_info(struct flash_bank *bank)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t did0, did1, ver, fam, status;
-       int i;
-
-       /* Read and parse chip identification register */
-       target_read_u32(target, SCB_BASE | DID0, &did0);
-       target_read_u32(target, SCB_BASE | DID1, &did1);
-       target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0);
-       target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1);
-       LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "",
-                 did0, did1, stellaris_info->dc0, stellaris_info->dc1);
-
-       ver = did0 >> 28;
-       if ((ver != 0) && (ver != 1))
-       {
-               LOG_WARNING("Unknown did0 version, cannot identify target");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as a Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       ver = did1 >> 28;
-       fam = (did1 >> 24) & 0xF;
-       if (((ver != 0) && (ver != 1)) || (fam != 0))
-       {
-               LOG_WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
-       }
-
-       /* For Sandstorm, Fury, DustDevil:  current data sheets say IOSC
-        * is 12 MHz, but some older parts have 15 MHz.  A few data sheets
-        * even give _both_ numbers!  We'll use current numbers; IOSC is
-        * always approximate.
-        *
-        * For Tempest:  IOSC is calibrated, 16 MHz
-        */
-       stellaris_info->iosc_freq = 12000000;
-       stellaris_info->iosc_desc = " (±30%)";
-       stellaris_info->xtal_mask = 0x0f;
-
-       switch ((did0 >> 28) & 0x7) {
-       case 0:                         /* Sandstorm */
-               /*
-                * Current (2009-August) parts seem to be rev C2 and use 12 MHz.
-                * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz
-                * (LM3S618), but some other C0 parts are 12 MHz (LM3S811).
-                */
-               if (((did0 >> 8) & 0xff) < 2) {
-                       stellaris_info->iosc_freq = 15000000;
-                       stellaris_info->iosc_desc = " (±50%)";
-               }
-               break;
-       case 1:
-               switch ((did0 >> 16) & 0xff) {
-               case 1:                 /* Fury */
-                       break;
-               case 4:                 /* Tempest */
-                       stellaris_info->iosc_freq = 16000000;   /* +/- 1% */
-                       stellaris_info->iosc_desc = " (±1%)";
-                       /* FALL THROUGH */
-               case 3:                 /* DustDevil */
-                       stellaris_info->xtal_mask = 0x1f;
-                       break;
-               default:
-                       LOG_WARNING("Unknown did0 class");
-               }
-       default:
-               break;
-               LOG_WARNING("Unknown did0 version");
-       }
-
-       for (i = 0; StellarisParts[i].partno; i++)
-       {
-               if (StellarisParts[i].partno == ((did1 >> 16) & 0xFF))
-                       break;
-       }
-
-       stellaris_info->target_name = StellarisParts[i].partname;
-
-       stellaris_info->did0 = did0;
-       stellaris_info->did1 = did1;
-
-       stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
-       stellaris_info->num_pages = 2 *(1 + (stellaris_info->dc0 & 0xFFFF));
-       stellaris_info->pagesize = 1024;
-       bank->size = 1024 * stellaris_info->num_pages;
-       stellaris_info->pages_in_lockregion = 2;
-       target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
-
-       /* provide this for the benefit of the higher flash driver layers */
-       bank->num_sectors = stellaris_info->num_pages;
-       bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               bank->sectors[i].offset = i * stellaris_info->pagesize;
-               bank->sectors[i].size = stellaris_info->pagesize;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = -1;
-       }
-
-       /* Read main and master clock freqency register */
-       stellaris_read_clock_info(bank);
-
-       status = stellaris_get_flash_status(bank);
-
-       return ERROR_OK;
-}
-
-/***************************************************************************
-*      flash operations                                                       *
-***************************************************************************/
-
-static int stellaris_protect_check(struct flash_bank *bank)
-{
-       uint32_t status;
-
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       status = stellaris_get_flash_status(bank);
-       stellaris_info->lockbits = status >> 16;
-
-       return ERROR_OK;
-}
-
-static int stellaris_erase(struct flash_bank *bank, int first, int last)
-{
-       int banknr;
-       uint32_t flash_fmc, flash_cris;
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       if ((first == 0) && (last == ((int)stellaris_info->num_pages-1)))
-       {
-               return stellaris_mass_erase(bank);
-       }
-
-       /* Configure the flash controller timing */
-       stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank,0);
-
-       /* Clear and disable flash programming interrupts */
-       target_write_u32(target, FLASH_CIM, 0);
-       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
-
-       for (banknr = first; banknr <= last; banknr++)
-       {
-               /* Address is first word in page */
-               target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize);
-               /* Write erase command */
-               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);
-               /* Wait until erase complete */
-               do
-               {
-                       target_read_u32(target, FLASH_FMC, &flash_fmc);
-               }
-               while (flash_fmc & FMC_ERASE);
-
-               /* Check acess violations */
-               target_read_u32(target, FLASH_CRIS, &flash_cris);
-               if (flash_cris & (AMASK))
-               {
-                       LOG_WARNING("Error erasing flash page %i,  flash_cris 0x%" PRIx32 "", banknr, flash_cris);
-                       target_write_u32(target, FLASH_CRIS, 0);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               bank->sectors[banknr].is_erased = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static int stellaris_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       uint32_t fmppe, flash_fmc, flash_cris;
-       int lockregion;
-
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first < 0) || (last < first) || (last >= stellaris_info->num_lockbits))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as an Stellaris MCU");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Configure the flash controller timing */
-       stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank, 0);
-
-       fmppe = stellaris_info->lockbits;
-       for (lockregion = first; lockregion <= last; lockregion++)
-       {
-               if (set)
-                       fmppe &= ~(1 << lockregion);
-               else
-                       fmppe |= (1 << lockregion);
-       }
-
-       /* Clear and disable flash programming interrupts */
-       target_write_u32(target, FLASH_CIM, 0);
-       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
-
-       LOG_DEBUG("fmppe 0x%" PRIx32 "",fmppe);
-       target_write_u32(target, SCB_BASE | FMPPE, fmppe);
-       /* Commit FMPPE */
-       target_write_u32(target, FLASH_FMA, 1);
-       /* Write commit command */
-       /* TODO safety check, sice this cannot be undone */
-       LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
-       /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
-       /* Wait until erase complete */
-       do
-       {
-               target_read_u32(target, FLASH_FMC, &flash_fmc);
-       }
-       while (flash_fmc & FMC_COMT);
-
-       /* Check acess violations */
-       target_read_u32(target, FLASH_CRIS, &flash_cris);
-       if (flash_cris & (AMASK))
-       {
-               LOG_WARNING("Error setting flash page protection,  flash_cris 0x%" PRIx32 "", flash_cris);
-               target_write_u32(target, FLASH_CRIS, 0);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
-
-       return ERROR_OK;
-}
-
-static uint8_t stellaris_write_code[] =
-{
-/*
-       Call with :
-       r0 = buffer address
-       r1 = destination address
-       r2 = bytecount (in) - endaddr (work)
-
-       Used registers:
-       r3 = pFLASH_CTRL_BASE
-       r4 = FLASHWRITECMD
-       r5 = #1
-       r6 = bytes written
-       r7 = temp reg
-*/
-       0x07,0x4B,                      /* ldr r3,pFLASH_CTRL_BASE */
-       0x08,0x4C,                      /* ldr r4,FLASHWRITECMD */
-       0x01,0x25,                      /* movs r5, 1 */
-       0x00,0x26,                      /* movs r6, #0 */
-/* mainloop: */
-       0x19,0x60,                      /* str  r1, [r3, #0] */
-       0x87,0x59,                      /* ldr  r7, [r0, r6] */
-       0x5F,0x60,                      /* str  r7, [r3, #4] */
-       0x9C,0x60,                      /* str  r4, [r3, #8] */
-/* waitloop: */
-       0x9F,0x68,                      /* ldr  r7, [r3, #8] */
-       0x2F,0x42,                      /* tst  r7, r5 */
-       0xFC,0xD1,                      /* bne  waitloop */
-       0x04,0x31,                      /* adds r1, r1, #4 */
-       0x04,0x36,                      /* adds r6, r6, #4 */
-       0x96,0x42,                      /* cmp  r6, r2 */
-       0xF4,0xD1,                      /* bne  mainloop */
-                                               /* exit: */
-       0xFE,0xE7,                      /* b exit */
-/* pFLASH_CTRL_BASE: */
-       0x00,0xD0,0x0F,0x40,    /* .word        0x400FD000 */
-/* FLASHWRITECMD: */
-       0x01,0x00,0x42,0xA4     /* .word        0xA4420001 */
-};
-
-static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t wcount)
-{
-       struct target *target = bank->target;
-       uint32_t buffer_size = 8192;
-       struct working_area *source;
-       struct working_area *write_algorithm;
-       uint32_t address = bank->base + offset;
-       struct reg_param reg_params[3];
-       struct armv7m_algorithm armv7m_info;
-       int retval = ERROR_OK;
-
-       LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
-                       bank, buffer, offset, wcount);
-
-       /* flash write code */
-       if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
-       {
-               LOG_WARNING("no working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
-
-       target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), stellaris_write_code);
-
-       /* memory buffer */
-       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
-       {
-               LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
-                               target, buffer_size, source);
-               buffer_size /= 2;
-               if (buffer_size <= 256)
-               {
-                       /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
-                       if (write_algorithm)
-                               target_free_working_area(target, write_algorithm);
-
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-       };
-
-       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
-       armv7m_info.core_mode = ARMV7M_MODE_ANY;
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-
-       while (wcount > 0)
-       {
-               uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
-
-               target_write_buffer(target, source->address, thisrun_count * 4, buffer);
-
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
-               LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
-               LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
-               if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
-               {
-                       LOG_ERROR("error executing stellaris flash write algorithm");
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer += thisrun_count * 4;
-               address += thisrun_count * 4;
-               wcount -= thisrun_count;
-       }
-
-       target_free_working_area(target, write_algorithm);
-       target_free_working_area(target, source);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-
-       return retval;
-}
-
-static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t address = offset;
-       uint32_t flash_cris, flash_fmc;
-       uint32_t words_remaining = (count / 4);
-       uint32_t bytes_remaining = (count & 0x00000003);
-       uint32_t bytes_written = 0;
-       int retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "",
-                       bank, buffer, offset, count);
-
-       if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as a Stellaris processor");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (offset & 0x3)
-       {
-               LOG_WARNING("offset size must be word aligned");
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       if (offset + count > bank->size)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       /* Configure the flash controller timing */
-       stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank, 0);
-
-       /* Clear and disable flash programming interrupts */
-       target_write_u32(target, FLASH_CIM, 0);
-       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
-
-       /* multiple words to be programmed? */
-       if (words_remaining > 0)
-       {
-               /* try using a block write */
-               if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
-               {
-                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                       {
-                               /* if block write failed (no sufficient working area),
-                                * we use normal (slow) single dword accesses */
-                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
-                       }
-                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
-                       {
-                               /* if an error occured, we examine the reason, and quit */
-                               target_read_u32(target, FLASH_CRIS, &flash_cris);
-
-                               LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-               }
-               else
-               {
-                       buffer += words_remaining * 4;
-                       address += words_remaining * 4;
-                       words_remaining = 0;
-               }
-       }
-
-       while (words_remaining > 0)
-       {
-               if (!(address & 0xff))
-                       LOG_DEBUG("0x%" PRIx32 "", address);
-
-               /* Program one word */
-               target_write_u32(target, FLASH_FMA, address);
-               target_write_buffer(target, FLASH_FMD, 4, buffer);
-               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
-               /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
-               /* Wait until write complete */
-               do
-               {
-                       target_read_u32(target, FLASH_FMC, &flash_fmc);
-               } while (flash_fmc & FMC_WRITE);
-
-               buffer += 4;
-               address += 4;
-               words_remaining--;
-       }
-
-       if (bytes_remaining)
-       {
-               uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
-               int i = 0;
-
-               while (bytes_remaining > 0)
-               {
-                       last_word[i++] = *(buffer + bytes_written);
-                       bytes_remaining--;
-                       bytes_written++;
-               }
-
-               if (!(address & 0xff))
-                       LOG_DEBUG("0x%" PRIx32 "", address);
-
-               /* Program one word */
-               target_write_u32(target, FLASH_FMA, address);
-               target_write_buffer(target, FLASH_FMD, 4, last_word);
-               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
-               /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
-               /* Wait until write complete */
-               do
-               {
-                       target_read_u32(target, FLASH_FMC, &flash_fmc);
-               } while (flash_fmc & FMC_WRITE);
-       }
-
-       /* Check access violations */
-       target_read_u32(target, FLASH_CRIS, &flash_cris);
-       if (flash_cris & (AMASK))
-       {
-               LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-       return ERROR_OK;
-}
-
-static int stellaris_probe(struct flash_bank *bank)
-{
-       /* we can't probe on an stellaris
-        * if this is an stellaris, it has the configured flash
-        */
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* stellaris_read_part_info() already takes care about error checking and reporting */
-       return stellaris_read_part_info(bank);
-}
-
-static int stellaris_auto_probe(struct flash_bank *bank)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       if (stellaris_info->did1)
-               return ERROR_OK;
-       return stellaris_probe(bank);
-}
-
-static int stellaris_mass_erase(struct flash_bank *bank)
-{
-       struct target *target = NULL;
-       struct stellaris_flash_bank *stellaris_info = NULL;
-       uint32_t flash_fmc;
-
-       stellaris_info = bank->driver_priv;
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* Configure the flash controller timing */
-       stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank, 0);
-
-       /* Clear and disable flash programming interrupts */
-       target_write_u32(target, FLASH_CIM, 0);
-       target_write_u32(target, FLASH_MISC, PMISC | AMISC);
-
-       target_write_u32(target, FLASH_FMA, 0);
-       target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
-       /* Wait until erase complete */
-       do
-       {
-               target_read_u32(target, FLASH_FMC, &flash_fmc);
-       }
-       while (flash_fmc & FMC_MERASE);
-
-       /* if device has > 128k, then second erase cycle is needed
-        * this is only valid for older devices, but will not hurt */
-       if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
-       {
-               target_write_u32(target, FLASH_FMA, 0x20000);
-               target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
-               /* Wait until erase complete */
-               do
-               {
-                       target_read_u32(target, FLASH_FMC, &flash_fmc);
-               }
-               while (flash_fmc & FMC_MERASE);
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(stellaris_handle_mass_erase_command)
-{
-       int i;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "stellaris mass_erase <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if (stellaris_mass_erase(bank) == ERROR_OK)
-       {
-               /* set all sectors as erased */
-               for (i = 0; i < bank->num_sectors; i++)
-               {
-                       bank->sectors[i].is_erased = 1;
-               }
-
-               command_print(CMD_CTX, "stellaris mass erase complete");
-       }
-       else
-       {
-               command_print(CMD_CTX, "stellaris mass erase failed");
-       }
-
-       return ERROR_OK;
-}
-
-static const struct command_registration stellaris_exec_command_handlers[] = {
-       {
-               .name = "mass_erase",
-               .handler = &stellaris_handle_mass_erase_command,
-               .mode = COMMAND_EXEC,
-               .help = "erase entire device",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration stellaris_command_handlers[] = {
-       {
-               .name = "stellaris",
-               .mode = COMMAND_ANY,
-               .help = "Stellaris flash command group",
-               .chain = stellaris_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver stellaris_flash = {
-               .name = "stellaris",
-               .commands = stellaris_command_handlers,
-               .flash_bank_command = &stellaris_flash_bank_command,
-               .erase = &stellaris_erase,
-               .protect = &stellaris_protect,
-               .write = &stellaris_write,
-               .probe = &stellaris_probe,
-               .auto_probe = &stellaris_auto_probe,
-               .erase_check = &default_flash_mem_blank_check,
-               .protect_check = &stellaris_protect_check,
-               .info = &stellaris_info,
-       };
diff --git a/src/flash/stellaris.h b/src/flash/stellaris.h
deleted file mode 100644 (file)
index 949a346..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2006 by Magnus Lundin                                   *
- *   lundin@mlu.mine.nu                                                    *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef STELLARIS_FLASH_H
-#define STELLARIS_FLASH_H
-
-#include "flash.h"
-
-struct stellaris_flash_bank
-{
-       /* chip id register */
-       uint32_t did0;
-       uint32_t did1;
-       uint32_t dc0;
-       uint32_t dc1;
-
-       char * target_name;
-
-       uint32_t sramsiz;
-       uint32_t flshsz;
-       /* flash geometry */
-       uint32_t num_pages;
-       uint32_t pagesize;
-       uint32_t pages_in_lockregion;
-
-       /* nv memory bits */
-       uint16_t num_lockbits;
-       uint32_t lockbits;
-
-       /* main clock status */
-       uint32_t rcc;
-       uint32_t rcc2;
-       uint8_t  mck_valid;
-       uint8_t  xtal_mask;
-       uint32_t iosc_freq;
-       uint32_t mck_freq;
-       const char *iosc_desc;
-       const char *mck_desc;
-};
-
-/* STELLARIS control registers */
-#define SCB_BASE       0x400FE000
-#define        DID0            0x000
-#define        DID1            0x004
-#define        DC0                     0x008
-#define        DC1                     0x010
-#define        DC2                     0x014
-#define        DC3                     0x018
-#define        DC4                     0x01C
-
-#define        RIS                     0x050
-#define        RCC                     0x060
-#define        PLLCFG          0x064
-#define        RCC2            0x070
-
-#define FMPRE          0x130
-#define FMPPE          0x134
-#define USECRL         0x140
-
-#define FLASH_CONTROL_BASE     0x400FD000
-#define FLASH_FMA      (FLASH_CONTROL_BASE | 0x000)
-#define FLASH_FMD      (FLASH_CONTROL_BASE | 0x004)
-#define FLASH_FMC      (FLASH_CONTROL_BASE | 0x008)
-#define FLASH_CRIS     (FLASH_CONTROL_BASE | 0x00C)
-#define FLASH_CIM      (FLASH_CONTROL_BASE | 0x010)
-#define FLASH_MISC     (FLASH_CONTROL_BASE | 0x014)
-
-#define AMISC  1
-#define PMISC  2
-
-#define AMASK  1
-#define PMASK  2
-
-/* Flash Controller Command bits */
-#define FMC_WRKEY      (0xA442 << 16)
-#define FMC_COMT       (1 << 3)
-#define FMC_MERASE     (1 << 2)
-#define FMC_ERASE      (1 << 1)
-#define FMC_WRITE      (1 << 0)
-
-/* STELLARIS constants */
-
-#endif /* STELLARIS_H */
diff --git a/src/flash/stm32x.c b/src/flash/stm32x.c
deleted file mode 100644 (file)
index 2f51aa5..0000000
+++ /dev/null
@@ -1,1240 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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 "stm32x.h"
-#include "armv7m.h"
-#include "binarybuffer.h"
-#include "algorithm.h"
-
-
-static int stm32x_mass_erase(struct flash_bank *bank);
-
-/* flash bank stm32x <base> <size> 0 0 <target#>
- */
-FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
-{
-       struct stm32x_flash_bank *stm32x_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank stm32x configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
-       bank->driver_priv = stm32x_info;
-
-       stm32x_info->write_algorithm = NULL;
-       stm32x_info->probed = 0;
-
-       return ERROR_OK;
-}
-
-static uint32_t stm32x_get_flash_status(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint32_t status;
-
-       target_read_u32(target, STM32_FLASH_SR, &status);
-
-       return status;
-}
-
-static uint32_t stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
-{
-       struct target *target = bank->target;
-       uint32_t status;
-
-       /* wait for busy to clear */
-       while (((status = stm32x_get_flash_status(bank)) & FLASH_BSY) && (timeout-- > 0))
-       {
-               LOG_DEBUG("status: 0x%" PRIx32 "", status);
-               alive_sleep(1);
-       }
-       /* Clear but report errors */
-       if (status & (FLASH_WRPRTERR | FLASH_PGERR))
-       {
-               target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR);
-       }
-       return status;
-}
-
-static int stm32x_read_options(struct flash_bank *bank)
-{
-       uint32_t optiondata;
-       struct stm32x_flash_bank *stm32x_info = NULL;
-       struct target *target = bank->target;
-
-       stm32x_info = bank->driver_priv;
-
-       /* read current option bytes */
-       target_read_u32(target, STM32_FLASH_OBR, &optiondata);
-
-       stm32x_info->option_bytes.user_options = (uint16_t)0xFFF8 | ((optiondata >> 2) & 0x07);
-       stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
-
-       if (optiondata & (1 << OPT_READOUT))
-               LOG_INFO("Device Security Bit Set");
-
-       /* each bit refers to a 4bank protection */
-       target_read_u32(target, STM32_FLASH_WRPR, &optiondata);
-
-       stm32x_info->option_bytes.protection[0] = (uint16_t)optiondata;
-       stm32x_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8);
-       stm32x_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16);
-       stm32x_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24);
-
-       return ERROR_OK;
-}
-
-static int stm32x_erase_options(struct flash_bank *bank)
-{
-       struct stm32x_flash_bank *stm32x_info = NULL;
-       struct target *target = bank->target;
-       uint32_t status;
-
-       stm32x_info = bank->driver_priv;
-
-       /* read current options */
-       stm32x_read_options(bank);
-
-       /* unlock flash registers */
-       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
-       /* unlock option flash registers */
-       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
-
-       /* erase option bytes */
-       target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE);
-       target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* clear readout protection and complementary option bytes
-        * this will also force a device unlock if set */
-       stm32x_info->option_bytes.RDP = 0x5AA5;
-
-       return ERROR_OK;
-}
-
-static int stm32x_write_options(struct flash_bank *bank)
-{
-       struct stm32x_flash_bank *stm32x_info = NULL;
-       struct target *target = bank->target;
-       uint32_t status;
-
-       stm32x_info = bank->driver_priv;
-
-       /* unlock flash registers */
-       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
-       /* unlock option flash registers */
-       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
-
-       /* program option bytes */
-       target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE);
-
-       /* write user option byte */
-       target_write_u16(target, STM32_OB_USER, stm32x_info->option_bytes.user_options);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* write protection byte 1 */
-       target_write_u16(target, STM32_OB_WRP0, stm32x_info->option_bytes.protection[0]);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* write protection byte 2 */
-       target_write_u16(target, STM32_OB_WRP1, stm32x_info->option_bytes.protection[1]);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* write protection byte 3 */
-       target_write_u16(target, STM32_OB_WRP2, stm32x_info->option_bytes.protection[2]);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* write protection byte 4 */
-       target_write_u16(target, STM32_OB_WRP3, stm32x_info->option_bytes.protection[3]);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* write readout protection bit */
-       target_write_u16(target, STM32_OB_RDP, stm32x_info->option_bytes.RDP);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       if (status & FLASH_WRPRTERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-       if (status & FLASH_PGERR)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
-       return ERROR_OK;
-}
-
-static int stm32x_protect_check(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
-
-       uint32_t protection;
-       int i, s;
-       int num_bits;
-       int set;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* medium density - each bit refers to a 4bank protection
-        * high density - each bit refers to a 2bank protection */
-       target_read_u32(target, STM32_FLASH_WRPR, &protection);
-
-       /* medium density - each protection bit is for 4 * 1K pages
-        * high density - each protection bit is for 2 * 2K pages */
-       num_bits = (bank->num_sectors / stm32x_info->ppage_size);
-
-       if (stm32x_info->ppage_size == 2)
-       {
-               /* high density flash/connectivity line protection */
-
-               set = 1;
-
-               if (protection & (1 << 31))
-                       set = 0;
-
-               /* bit 31 controls sector 62 - 255 protection for high density
-                * bit 31 controls sector 62 - 127 protection for connectivity line */
-               for (s = 62; s < bank->num_sectors; s++)
-               {
-                       bank->sectors[s].is_protected = set;
-               }
-
-               if (bank->num_sectors > 61)
-                       num_bits = 31;
-
-               for (i = 0; i < num_bits; i++)
-               {
-                       set = 1;
-
-                       if (protection & (1 << i))
-                               set = 0;
-
-                       for (s = 0; s < stm32x_info->ppage_size; s++)
-                               bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set;
-               }
-       }
-       else
-       {
-               /* low/medium density flash protection */
-               for (i = 0; i < num_bits; i++)
-               {
-                       set = 1;
-
-                       if (protection & (1 << i))
-                               set = 0;
-
-                       for (s = 0; s < stm32x_info->ppage_size; s++)
-                               bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set;
-               }
-       }
-
-       return ERROR_OK;
-}
-
-static int stm32x_erase(struct flash_bank *bank, int first, int last)
-{
-       struct target *target = bank->target;
-       int i;
-       uint32_t status;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first == 0) && (last == (bank->num_sectors - 1)))
-       {
-               return stm32x_mass_erase(bank);
-       }
-
-       /* unlock flash registers */
-       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
-       for (i = first; i <= last; i++)
-       {
-               target_write_u32(target, STM32_FLASH_CR, FLASH_PER);
-               target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset);
-               target_write_u32(target, STM32_FLASH_CR, FLASH_PER | FLASH_STRT);
-
-               status = stm32x_wait_status_busy(bank, 10);
-
-               if (status & FLASH_WRPRTERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               if (status & FLASH_PGERR)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               bank->sectors[i].is_erased = 1;
-       }
-
-       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
-       return ERROR_OK;
-}
-
-static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       struct stm32x_flash_bank *stm32x_info = NULL;
-       struct target *target = bank->target;
-       uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
-       int i, reg, bit;
-       int status;
-       uint32_t protection;
-
-       stm32x_info = bank->driver_priv;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if ((first && (first % stm32x_info->ppage_size)) || ((last + 1) && (last + 1) % stm32x_info->ppage_size))
-       {
-               LOG_WARNING("Error: start and end sectors must be on a %d sector boundary", stm32x_info->ppage_size);
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* medium density - each bit refers to a 4bank protection
-        * high density - each bit refers to a 2bank protection */
-       target_read_u32(target, STM32_FLASH_WRPR, &protection);
-
-       prot_reg[0] = (uint16_t)protection;
-       prot_reg[1] = (uint16_t)(protection >> 8);
-       prot_reg[2] = (uint16_t)(protection >> 16);
-       prot_reg[3] = (uint16_t)(protection >> 24);
-
-       if (stm32x_info->ppage_size == 2)
-       {
-               /* high density flash */
-
-               /* bit 7 controls sector 62 - 255 protection */
-               if (last > 61)
-               {
-                       if (set)
-                               prot_reg[3] &= ~(1 << 7);
-                       else
-                               prot_reg[3] |= (1 << 7);
-               }
-
-               if (first > 61)
-                       first = 62;
-               if (last > 61)
-                       last = 61;
-
-               for (i = first; i <= last; i++)
-               {
-                       reg = (i / stm32x_info->ppage_size) / 8;
-                       bit = (i / stm32x_info->ppage_size) - (reg * 8);
-
-                       if (set)
-                               prot_reg[reg] &= ~(1 << bit);
-                       else
-                               prot_reg[reg] |= (1 << bit);
-               }
-       }
-       else
-       {
-               /* medium density flash */
-               for (i = first; i <= last; i++)
-               {
-                       reg = (i / stm32x_info->ppage_size) / 8;
-                       bit = (i / stm32x_info->ppage_size) - (reg * 8);
-
-                       if (set)
-                               prot_reg[reg] &= ~(1 << bit);
-                       else
-                               prot_reg[reg] |= (1 << bit);
-               }
-       }
-
-       if ((status = stm32x_erase_options(bank)) != ERROR_OK)
-               return status;
-
-       stm32x_info->option_bytes.protection[0] = prot_reg[0];
-       stm32x_info->option_bytes.protection[1] = prot_reg[1];
-       stm32x_info->option_bytes.protection[2] = prot_reg[2];
-       stm32x_info->option_bytes.protection[3] = prot_reg[3];
-
-       return stm32x_write_options(bank);
-}
-
-static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t buffer_size = 16384;
-       struct working_area *source;
-       uint32_t address = bank->base + offset;
-       struct reg_param reg_params[4];
-       struct armv7m_algorithm armv7m_info;
-       int retval = ERROR_OK;
-
-       uint8_t stm32x_flash_write_code[] = {
-                                                                       /* write: */
-               0xDF, 0xF8, 0x24, 0x40,         /* ldr  r4, STM32_FLASH_CR */
-               0x09, 0x4D,                                     /* ldr  r5, STM32_FLASH_SR */
-               0x4F, 0xF0, 0x01, 0x03,         /* mov  r3, #1 */
-               0x23, 0x60,                                     /* str  r3, [r4, #0] */
-               0x30, 0xF8, 0x02, 0x3B,         /* ldrh r3, [r0], #2 */
-               0x21, 0xF8, 0x02, 0x3B,         /* strh r3, [r1], #2 */
-                                                                       /* busy: */
-               0x2B, 0x68,                                     /* ldr  r3, [r5, #0] */
-               0x13, 0xF0, 0x01, 0x0F,         /* tst  r3, #0x01 */
-               0xFB, 0xD0,                                     /* beq  busy */
-               0x13, 0xF0, 0x14, 0x0F,         /* tst  r3, #0x14 */
-               0x01, 0xD1,                                     /* bne  exit */
-               0x01, 0x3A,                                     /* subs r2, r2, #1 */
-               0xED, 0xD1,                                     /* bne  write */
-                                                                       /* exit: */
-               0xFE, 0xE7,                                     /* b exit */
-               0x10, 0x20, 0x02, 0x40,         /* STM32_FLASH_CR:      .word 0x40022010 */
-               0x0C, 0x20, 0x02, 0x40          /* STM32_FLASH_SR:      .word 0x4002200C */
-       };
-
-       /* flash write code */
-       if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)
-       {
-               LOG_WARNING("no working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
-
-       if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code)) != 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 (stm32x_info->write_algorithm)
-                               target_free_working_area(target, stm32x_info->write_algorithm);
-
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-       };
-
-       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
-       armv7m_info.core_mode = ARMV7M_MODE_ANY;
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
-
-       while (count > 0)
-       {
-               uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
-
-               if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK)
-                       break;
-
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
-
-               if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
-                               stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
-               {
-                       LOG_ERROR("error executing stm32x flash write algorithm");
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR)
-               {
-                       LOG_ERROR("flash memory not erased before writing");
-                       /* Clear but report errors */
-                       target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR)
-               {
-                       LOG_ERROR("flash memory write protected");
-                       /* Clear but report errors */
-                       target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR);
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer += thisrun_count * 2;
-               address += thisrun_count * 2;
-               count -= thisrun_count;
-       }
-
-       target_free_working_area(target, source);
-       target_free_working_area(target, stm32x_info->write_algorithm);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-
-       return retval;
-}
-
-static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct target *target = bank->target;
-       uint32_t words_remaining = (count / 2);
-       uint32_t bytes_remaining = (count & 0x00000001);
-       uint32_t address = bank->base + offset;
-       uint32_t bytes_written = 0;
-       uint8_t status;
-       int retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset & 0x1)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       /* unlock flash registers */
-       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
-       /* multiple half words (2-byte) to be programmed? */
-       if (words_remaining > 0)
-       {
-               /* try using a block write */
-               if ((retval = stm32x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
-               {
-                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                       {
-                               /* if block write failed (no sufficient working area),
-                                * we use normal (slow) single dword accesses */
-                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
-                       }
-                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
-                       {
-                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-               }
-               else
-               {
-                       buffer += words_remaining * 2;
-                       address += words_remaining * 2;
-                       words_remaining = 0;
-               }
-       }
-
-       while (words_remaining > 0)
-       {
-               uint16_t value;
-               memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
-
-               target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
-               target_write_u16(target, address, value);
-
-               status = stm32x_wait_status_busy(bank, 5);
-
-               if (status & FLASH_WRPRTERR)
-               {
-                       LOG_ERROR("flash memory not erased before writing");
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               if (status & FLASH_PGERR)
-               {
-                       LOG_ERROR("flash memory write protected");
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               bytes_written += 2;
-               words_remaining--;
-               address += 2;
-       }
-
-       if (bytes_remaining)
-       {
-               uint16_t value = 0xffff;
-               memcpy(&value, buffer + bytes_written, bytes_remaining);
-
-               target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
-               target_write_u16(target, address, value);
-
-               status = stm32x_wait_status_busy(bank, 5);
-
-               if (status & FLASH_WRPRTERR)
-               {
-                       LOG_ERROR("flash memory not erased before writing");
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               if (status & FLASH_PGERR)
-               {
-                       LOG_ERROR("flash memory write protected");
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-       }
-
-       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
-       return ERROR_OK;
-}
-
-static int stm32x_probe(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
-       int i;
-       uint16_t num_pages;
-       uint32_t device_id;
-       int page_size;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       stm32x_info->probed = 0;
-
-       /* read stm32 device id register */
-       target_read_u32(target, 0xE0042000, &device_id);
-       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
-
-       /* get flash size from target */
-       if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)
-       {
-               /* failed reading flash size, default to max target family */
-               num_pages = 0xffff;
-       }
-
-       if ((device_id & 0x7ff) == 0x410)
-       {
-               /* medium density - we have 1k pages
-                * 4 pages for a protection area */
-               page_size = 1024;
-               stm32x_info->ppage_size = 4;
-
-               /* check for early silicon */
-               if (num_pages == 0xffff)
-               {
-                       /* number of sectors incorrect on revA */
-                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 128k flash");
-                       num_pages = 128;
-               }
-       }
-       else if ((device_id & 0x7ff) == 0x412)
-       {
-               /* low density - we have 1k pages
-                * 4 pages for a protection area */
-               page_size = 1024;
-               stm32x_info->ppage_size = 4;
-
-               /* check for early silicon */
-               if (num_pages == 0xffff)
-               {
-                       /* number of sectors incorrect on revA */
-                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 32k flash");
-                       num_pages = 32;
-               }
-       }
-       else if ((device_id & 0x7ff) == 0x414)
-       {
-               /* high density - we have 2k pages
-                * 2 pages for a protection area */
-               page_size = 2048;
-               stm32x_info->ppage_size = 2;
-
-               /* check for early silicon */
-               if (num_pages == 0xffff)
-               {
-                       /* number of sectors incorrect on revZ */
-                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 512k flash");
-                       num_pages = 512;
-               }
-       }
-       else if ((device_id & 0x7ff) == 0x418)
-       {
-               /* connectivity line density - we have 2k pages
-                * 2 pages for a protection area */
-               page_size = 2048;
-               stm32x_info->ppage_size = 2;
-
-               /* check for early silicon */
-               if (num_pages == 0xffff)
-               {
-                       /* number of sectors incorrect on revZ */
-                       LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 256k flash");
-                       num_pages = 256;
-               }
-       }
-       else
-       {
-               LOG_WARNING("Cannot identify target as a STM32 family.");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       LOG_INFO("flash size = %dkbytes", num_pages);
-
-       /* calculate numbers of pages */
-       num_pages /= (page_size / 1024);
-
-       bank->base = 0x08000000;
-       bank->size = (num_pages * page_size);
-       bank->num_sectors = num_pages;
-       bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
-
-       for (i = 0; i < num_pages; i++)
-       {
-               bank->sectors[i].offset = i * page_size;
-               bank->sectors[i].size = page_size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 1;
-       }
-
-       stm32x_info->probed = 1;
-
-       return ERROR_OK;
-}
-
-static int stm32x_auto_probe(struct flash_bank *bank)
-{
-       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
-       if (stm32x_info->probed)
-               return ERROR_OK;
-       return stm32x_probe(bank);
-}
-
-#if 0
-COMMAND_HANDLER(stm32x_handle_part_id_command)
-{
-       return ERROR_OK;
-}
-#endif
-
-static int stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       struct target *target = bank->target;
-       uint32_t device_id;
-       int printed;
-
-       /* read stm32 device id register */
-       target_read_u32(target, 0xE0042000, &device_id);
-
-       if ((device_id & 0x7ff) == 0x410)
-       {
-               printed = snprintf(buf, buf_size, "stm32x (Medium Density) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16)
-               {
-                       case 0x0000:
-                               snprintf(buf, buf_size, "A");
-                               break;
-
-                       case 0x2000:
-                               snprintf(buf, buf_size, "B");
-                               break;
-
-                       case 0x2001:
-                               snprintf(buf, buf_size, "Z");
-                               break;
-
-                       case 0x2003:
-                               snprintf(buf, buf_size, "Y");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
-               }
-       }
-       else if ((device_id & 0x7ff) == 0x412)
-       {
-               printed = snprintf(buf, buf_size, "stm32x (Low Density) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16)
-               {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "A");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
-               }
-       }
-       else if ((device_id & 0x7ff) == 0x414)
-       {
-               printed = snprintf(buf, buf_size, "stm32x (High Density) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16)
-               {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "A");
-                               break;
-
-                       case 0x1001:
-                               snprintf(buf, buf_size, "Z");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
-               }
-       }
-       else if ((device_id & 0x7ff) == 0x418)
-       {
-               printed = snprintf(buf, buf_size, "stm32x (Connectivity) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16)
-               {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "A");
-                               break;
-
-                       case 0x1001:
-                               snprintf(buf, buf_size, "Z");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
-               }
-       }
-       else
-       {
-               snprintf(buf, buf_size, "Cannot identify target as a stm32x\n");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(stm32x_handle_lock_command)
-{
-       struct target *target = NULL;
-       struct stm32x_flash_bank *stm32x_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "stm32x lock <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       stm32x_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (stm32x_erase_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "stm32x failed to erase options");
-               return ERROR_OK;
-       }
-
-       /* set readout protection */
-       stm32x_info->option_bytes.RDP = 0;
-
-       if (stm32x_write_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "stm32x failed to lock device");
-               return ERROR_OK;
-       }
-
-       command_print(CMD_CTX, "stm32x locked");
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(stm32x_handle_unlock_command)
-{
-       struct target *target = NULL;
-       struct stm32x_flash_bank *stm32x_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "stm32x unlock <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       stm32x_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (stm32x_erase_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "stm32x failed to unlock device");
-               return ERROR_OK;
-       }
-
-       if (stm32x_write_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "stm32x failed to lock device");
-               return ERROR_OK;
-       }
-
-       command_print(CMD_CTX, "stm32x unlocked");
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(stm32x_handle_options_read_command)
-{
-       uint32_t optionbyte;
-       struct target *target = NULL;
-       struct stm32x_flash_bank *stm32x_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "stm32x options_read <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       stm32x_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       target_read_u32(target, STM32_FLASH_OBR, &optionbyte);
-       command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte);
-
-       if (buf_get_u32((uint8_t*)&optionbyte, OPT_ERROR, 1))
-               command_print(CMD_CTX, "Option Byte Complement Error");
-
-       if (buf_get_u32((uint8_t*)&optionbyte, OPT_READOUT, 1))
-               command_print(CMD_CTX, "Readout Protection On");
-       else
-               command_print(CMD_CTX, "Readout Protection Off");
-
-       if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDWDGSW, 1))
-               command_print(CMD_CTX, "Software Watchdog");
-       else
-               command_print(CMD_CTX, "Hardware Watchdog");
-
-       if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTOP, 1))
-               command_print(CMD_CTX, "Stop: No reset generated");
-       else
-               command_print(CMD_CTX, "Stop: Reset generated");
-
-       if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTDBY, 1))
-               command_print(CMD_CTX, "Standby: No reset generated");
-       else
-               command_print(CMD_CTX, "Standby: Reset generated");
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(stm32x_handle_options_write_command)
-{
-       struct target *target = NULL;
-       struct stm32x_flash_bank *stm32x_info = NULL;
-       uint16_t optionbyte = 0xF8;
-
-       if (CMD_ARGC < 4)
-       {
-               command_print(CMD_CTX, "stm32x options_write <bank> <SWWDG | HWWDG> <RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       stm32x_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (strcmp(CMD_ARGV[1], "SWWDG") == 0)
-       {
-               optionbyte |= (1 << 0);
-       }
-       else
-       {
-               optionbyte &= ~(1 << 0);
-       }
-
-       if (strcmp(CMD_ARGV[2], "NORSTSTNDBY") == 0)
-       {
-               optionbyte |= (1 << 1);
-       }
-       else
-       {
-               optionbyte &= ~(1 << 1);
-       }
-
-       if (strcmp(CMD_ARGV[3], "NORSTSTOP") == 0)
-       {
-               optionbyte |= (1 << 2);
-       }
-       else
-       {
-               optionbyte &= ~(1 << 2);
-       }
-
-       if (stm32x_erase_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "stm32x failed to erase options");
-               return ERROR_OK;
-       }
-
-       stm32x_info->option_bytes.user_options = optionbyte;
-
-       if (stm32x_write_options(bank) != ERROR_OK)
-       {
-               command_print(CMD_CTX, "stm32x failed to write options");
-               return ERROR_OK;
-       }
-
-       command_print(CMD_CTX, "stm32x write options complete");
-
-       return ERROR_OK;
-}
-
-static int stm32x_mass_erase(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint32_t status;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* unlock option flash registers */
-       target_write_u32(target, STM32_FLASH_KEYR, KEY1);
-       target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
-       /* mass erase flash memory */
-       target_write_u32(target, STM32_FLASH_CR, FLASH_MER);
-       target_write_u32(target, STM32_FLASH_CR, FLASH_MER | FLASH_STRT);
-
-       status = stm32x_wait_status_busy(bank, 10);
-
-       target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
-       if (status & FLASH_WRPRTERR)
-       {
-               LOG_ERROR("stm32x device protected");
-               return ERROR_OK;
-       }
-
-       if (status & FLASH_PGERR)
-       {
-               LOG_ERROR("stm32x device programming failed");
-               return ERROR_OK;
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(stm32x_handle_mass_erase_command)
-{
-       int i;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "stm32x mass_erase <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       if (stm32x_mass_erase(bank) == ERROR_OK)
-       {
-               /* set all sectors as erased */
-               for (i = 0; i < bank->num_sectors; i++)
-               {
-                       bank->sectors[i].is_erased = 1;
-               }
-
-               command_print(CMD_CTX, "stm32x mass erase complete");
-       }
-       else
-       {
-               command_print(CMD_CTX, "stm32x mass erase failed");
-       }
-
-       return ERROR_OK;
-}
-
-static const struct command_registration stm32x_exec_command_handlers[] = {
-       {
-               .name = "lock",
-               .handler = &stm32x_handle_lock_command,
-               .mode = COMMAND_EXEC,
-               .help = "lock device",
-       },
-       {
-               .name = "unlock",
-               .handler = &stm32x_handle_unlock_command,
-               .mode = COMMAND_EXEC,
-               .help = "unlock protected device",
-       },
-       {
-               .name = "mass_erase",
-               .handler = &stm32x_handle_mass_erase_command,
-               .mode = COMMAND_EXEC,
-               .help = "mass erase device",
-       },
-       {
-               .name = "options_read",
-               .handler = &stm32x_handle_options_read_command,
-               .mode = COMMAND_EXEC,
-               .help = "read device option bytes",
-       },
-       {
-               .name = "options_write",
-               .handler = &stm32x_handle_options_write_command,
-               .mode = COMMAND_EXEC,
-               .help = "write device option bytes",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration stm32x_command_handlers[] = {
-       {
-               .name = "stm32x",
-               .mode = COMMAND_ANY,
-               .help = "stm32x flash command group",
-               .chain = stm32x_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver stm32x_flash = {
-               .name = "stm32x",
-               .commands = stm32x_command_handlers,
-               .flash_bank_command = &stm32x_flash_bank_command,
-               .erase = &stm32x_erase,
-               .protect = &stm32x_protect,
-               .write = &stm32x_write,
-               .probe = &stm32x_probe,
-               .auto_probe = &stm32x_auto_probe,
-               .erase_check = &default_flash_mem_blank_check,
-               .protect_check = &stm32x_protect_check,
-               .info = &stm32x_info,
-       };
diff --git a/src/flash/stm32x.h b/src/flash/stm32x.h
deleted file mode 100644 (file)
index 6cd047e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef STM32X_H
-#define STM32X_H
-
-#include "flash.h"
-
-struct stm32x_options
-{
-       uint16_t RDP;
-       uint16_t user_options;
-       uint16_t protection[4];
-};
-
-struct stm32x_flash_bank
-{
-       struct stm32x_options option_bytes;
-       struct working_area *write_algorithm;
-       int ppage_size;
-       int probed;
-};
-
-/* stm32x register locations */
-
-#define STM32_FLASH_ACR                0x40022000
-#define STM32_FLASH_KEYR       0x40022004
-#define STM32_FLASH_OPTKEYR    0x40022008
-#define STM32_FLASH_SR         0x4002200C
-#define STM32_FLASH_CR         0x40022010
-#define STM32_FLASH_AR         0x40022014
-#define STM32_FLASH_OBR                0x4002201C
-#define STM32_FLASH_WRPR       0x40022020
-
-/* option byte location */
-
-#define STM32_OB_RDP           0x1FFFF800
-#define STM32_OB_USER          0x1FFFF802
-#define STM32_OB_DATA0         0x1FFFF804
-#define STM32_OB_DATA1         0x1FFFF806
-#define STM32_OB_WRP0          0x1FFFF808
-#define STM32_OB_WRP1          0x1FFFF80A
-#define STM32_OB_WRP2          0x1FFFF80C
-#define STM32_OB_WRP3          0x1FFFF80E
-
-/* FLASH_CR register bits */
-
-#define FLASH_PG               (1 << 0)
-#define FLASH_PER              (1 << 1)
-#define FLASH_MER              (1 << 2)
-#define FLASH_OPTPG            (1 << 4)
-#define FLASH_OPTER            (1 << 5)
-#define FLASH_STRT             (1 << 6)
-#define FLASH_LOCK             (1 << 7)
-#define FLASH_OPTWRE   (1 << 9)
-
-/* FLASH_SR register bits */
-
-#define FLASH_BSY              (1 << 0)
-#define FLASH_PGERR            (1 << 2)
-#define FLASH_WRPRTERR (1 << 4)
-#define FLASH_EOP              (1 << 5)
-
-/* STM32_FLASH_OBR bit definitions (reading) */
-
-#define OPT_ERROR              0
-#define OPT_READOUT            1
-#define OPT_RDWDGSW            2
-#define OPT_RDRSTSTOP  3
-#define OPT_RDRSTSTDBY 4
-
-/* register unlock keys */
-
-#define KEY1                   0x45670123
-#define KEY2                   0xCDEF89AB
-
-struct stm32x_mem_layout {
-       uint32_t sector_start;
-       uint32_t sector_size;
-};
-
-#endif /* STM32X_H */
diff --git a/src/flash/str7x.c b/src/flash/str7x.c
deleted file mode 100644 (file)
index 7edffac..0000000
+++ /dev/null
@@ -1,706 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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 "str7x.h"
-#include "armv4_5.h"
-#include "binarybuffer.h"
-#include "algorithm.h"
-
-
-struct str7x_mem_layout mem_layout_str7bank0[] = {
-       {0x00000000, 0x02000, 0x01},
-       {0x00002000, 0x02000, 0x02},
-       {0x00004000, 0x02000, 0x04},
-       {0x00006000, 0x02000, 0x08},
-       {0x00008000, 0x08000, 0x10},
-       {0x00010000, 0x10000, 0x20},
-       {0x00020000, 0x10000, 0x40},
-       {0x00030000, 0x10000, 0x80}
-};
-
-struct str7x_mem_layout mem_layout_str7bank1[] = {
-       {0x00000000, 0x02000, 0x10000},
-       {0x00002000, 0x02000, 0x20000}
-};
-
-static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg)
-{
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-       return (str7x_info->register_base | reg);
-}
-
-static int str7x_build_block_list(struct flash_bank *bank)
-{
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-
-       int i;
-       int num_sectors;
-       int b0_sectors = 0, b1_sectors = 0;
-
-       switch (bank->size)
-       {
-               case 16 * 1024:
-                       b1_sectors = 2;
-                       break;
-               case 64 * 1024:
-                       b0_sectors = 5;
-                       break;
-               case 128 * 1024:
-                       b0_sectors = 6;
-                       break;
-               case 256 * 1024:
-                       b0_sectors = 8;
-                       break;
-               default:
-                       LOG_ERROR("BUG: unknown bank->size encountered");
-                       exit(-1);
-       }
-
-       num_sectors = b0_sectors + b1_sectors;
-
-       bank->num_sectors = num_sectors;
-       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
-       str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
-
-       num_sectors = 0;
-
-       for (i = 0; i < b0_sectors; i++)
-       {
-               bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start;
-               bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size;
-               bank->sectors[num_sectors].is_erased = -1;
-               bank->sectors[num_sectors].is_protected = 1;
-               str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit;
-       }
-
-       for (i = 0; i < b1_sectors; i++)
-       {
-               bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start;
-               bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size;
-               bank->sectors[num_sectors].is_erased = -1;
-               bank->sectors[num_sectors].is_protected = 1;
-               str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit;
-       }
-
-       return ERROR_OK;
-}
-
-/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
- */
-FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command)
-{
-       struct str7x_flash_bank *str7x_info;
-
-       if (CMD_ARGC < 7)
-       {
-               LOG_WARNING("incomplete flash_bank str7x configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       str7x_info = malloc(sizeof(struct str7x_flash_bank));
-       bank->driver_priv = str7x_info;
-
-       /* set default bits for str71x flash */
-       str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
-       str7x_info->disable_bit = (1 << 1);
-
-       if (strcmp(CMD_ARGV[6], "STR71x") == 0)
-       {
-               str7x_info->register_base = 0x40100000;
-       }
-       else if (strcmp(CMD_ARGV[6], "STR73x") == 0)
-       {
-               str7x_info->register_base = 0x80100000;
-               str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
-       }
-       else if (strcmp(CMD_ARGV[6], "STR75x") == 0)
-       {
-               str7x_info->register_base = 0x20100000;
-               str7x_info->disable_bit = (1 << 0);
-       }
-       else
-       {
-               LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]);
-               free(str7x_info);
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       str7x_build_block_list(bank);
-
-       str7x_info->write_algorithm = NULL;
-
-       return ERROR_OK;
-}
-
-static uint32_t str7x_status(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint32_t retval;
-
-       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
-
-       return retval;
-}
-
-static uint32_t str7x_result(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       uint32_t retval;
-
-       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
-
-       return retval;
-}
-
-static int str7x_protect_check(struct flash_bank *bank)
-{
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       int i;
-       uint32_t retval;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &retval);
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               if (retval & str7x_info->sector_bits[i])
-                       bank->sectors[i].is_protected = 0;
-               else
-                       bank->sectors[i].is_protected = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static int str7x_erase(struct flash_bank *bank, int first, int last)
-{
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       int i;
-       uint32_t cmd;
-       uint32_t retval;
-       uint32_t sectors = 0;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       for (i = first; i <= last; i++)
-       {
-               sectors |= str7x_info->sector_bits[i];
-       }
-
-       LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors);
-
-       /* clear FLASH_ER register */
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
-       cmd = FLASH_SER;
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-       cmd = sectors;
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
-
-       cmd = FLASH_SER | FLASH_WMS;
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-       while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
-               alive_sleep(1);
-       }
-
-       retval = str7x_result(bank);
-
-       if (retval)
-       {
-               LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32 "", retval);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       for (i = first; i <= last; i++)
-               bank->sectors[i].is_erased = 1;
-
-       return ERROR_OK;
-}
-
-static int str7x_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-       struct target *target = bank->target;
-       int i;
-       uint32_t cmd;
-       uint32_t retval;
-       uint32_t protect_blocks;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       protect_blocks = 0xFFFFFFFF;
-
-       if (set)
-       {
-               for (i = first; i <= last; i++)
-                       protect_blocks &= ~(str7x_info->sector_bits[i]);
-       }
-
-       /* clear FLASH_ER register */
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
-       cmd = FLASH_SPR;
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-       cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
-
-       cmd = protect_blocks;
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
-
-       cmd = FLASH_SPR | FLASH_WMS;
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-       while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
-               alive_sleep(1);
-       }
-
-       retval = str7x_result(bank);
-
-       LOG_DEBUG("retval: 0x%8.8" PRIx32 "", retval);
-
-       if (retval & FLASH_ERER)
-               return ERROR_FLASH_SECTOR_NOT_ERASED;
-       else if (retval & FLASH_WPF)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       return ERROR_OK;
-}
-
-static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t buffer_size = 8192;
-       struct working_area *source;
-       uint32_t address = bank->base + offset;
-       struct reg_param reg_params[6];
-       struct armv4_5_algorithm armv4_5_info;
-       int retval = ERROR_OK;
-
-       uint32_t str7x_flash_write_code[] = {
-                                       /* write:                               */
-               0xe3a04201, /*  mov r4, #0x10000000     */
-               0xe5824000, /*  str r4, [r2, #0x0]      */
-               0xe5821010, /*  str r1, [r2, #0x10]     */
-               0xe4904004, /*  ldr r4, [r0], #4        */
-               0xe5824008, /*  str r4, [r2, #0x8]      */
-               0xe4904004, /*  ldr r4, [r0], #4        */
-               0xe582400c, /*  str r4, [r2, #0xc]      */
-               0xe3a04209, /*  mov r4, #0x90000000     */
-               0xe5824000, /*  str r4, [r2, #0x0]      */
-                           /* busy:                            */
-               0xe5924000, /*  ldr r4, [r2, #0x0]      */
-               0xe1140005,     /*      tst r4, r5                      */
-               0x1afffffc, /*  bne busy                        */
-               0xe5924014, /*  ldr r4, [r2, #0x14]     */
-               0xe31400ff, /*  tst r4, #0xff           */
-               0x03140c01, /*  tsteq r4, #0x100        */
-               0x1a000002, /*  bne exit                        */
-               0xe2811008, /*  add r1, r1, #0x8        */
-               0xe2533001, /*  subs r3, r3, #1         */
-               0x1affffec, /*  bne write                       */
-                                       /* exit:                                */
-               0xeafffffe, /*  b exit                          */
-       };
-
-       /* flash write code */
-       if (target_alloc_working_area(target, 4 * 20, &str7x_info->write_algorithm) != ERROR_OK)
-       {
-               LOG_WARNING("no working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
-
-       target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (uint8_t*)str7x_flash_write_code);
-
-       /* 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 (str7x_info->write_algorithm)
-                               target_free_working_area(target, str7x_info->write_algorithm);
-
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-       }
-
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
-       init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
-       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
-
-       while (count > 0)
-       {
-               uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
-
-               target_write_buffer(target, source->address, thisrun_count * 8, buffer);
-
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
-               buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
-               buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
-
-               if ((retval = target_run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
-               {
-                       LOG_ERROR("error executing str7x flash write algorithm");
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
-               {
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer += thisrun_count * 8;
-               address += thisrun_count * 8;
-               count -= thisrun_count;
-       }
-
-       target_free_working_area(target, source);
-       target_free_working_area(target, str7x_info->write_algorithm);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-       destroy_reg_param(&reg_params[4]);
-       destroy_reg_param(&reg_params[5]);
-
-       return retval;
-}
-
-static int str7x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct target *target = bank->target;
-       struct str7x_flash_bank *str7x_info = bank->driver_priv;
-       uint32_t dwords_remaining = (count / 8);
-       uint32_t bytes_remaining = (count & 0x00000007);
-       uint32_t address = bank->base + offset;
-       uint32_t bytes_written = 0;
-       uint32_t cmd;
-       int retval;
-       uint32_t check_address = offset;
-       int i;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset & 0x7)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               uint32_t sec_start = bank->sectors[i].offset;
-               uint32_t sec_end = sec_start + bank->sectors[i].size;
-
-               /* check if destination falls within the current sector */
-               if ((check_address >= sec_start) && (check_address < sec_end))
-               {
-                       /* check if destination ends in the current sector */
-                       if (offset + count < sec_end)
-                               check_address = offset + count;
-                       else
-                               check_address = sec_end;
-               }
-       }
-
-       if (check_address != offset + count)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       /* clear FLASH_ER register */
-       target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
-       /* multiple dwords (8-byte) to be programmed? */
-       if (dwords_remaining > 0)
-       {
-               /* try using a block write */
-               if ((retval = str7x_write_block(bank, buffer, offset, dwords_remaining)) != ERROR_OK)
-               {
-                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                       {
-                               /* if block write failed (no sufficient working area),
-                                * we use normal (slow) single dword accesses */
-                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
-                       }
-                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
-                       {
-                               /* if an error occured, we examine the reason, and quit */
-                               retval = str7x_result(bank);
-
-                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-               }
-               else
-               {
-                       buffer += dwords_remaining * 8;
-                       address += dwords_remaining * 8;
-                       dwords_remaining = 0;
-               }
-       }
-
-       while (dwords_remaining > 0)
-       {
-               /* command */
-               cmd = FLASH_DWPG;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-               /* address */
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
-
-               /* data word 1 */
-               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
-               bytes_written += 4;
-
-               /* data word 2 */
-               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
-               bytes_written += 4;
-
-               /* start programming cycle */
-               cmd = FLASH_DWPG | FLASH_WMS;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-               while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
-               {
-                       alive_sleep(1);
-               }
-
-               retval = str7x_result(bank);
-
-               if (retval & FLASH_PGER)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               else if (retval & FLASH_WPF)
-                       return ERROR_FLASH_OPERATION_FAILED;
-
-               dwords_remaining--;
-               address += 8;
-       }
-
-       if (bytes_remaining)
-       {
-               uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-               int i = 0;
-
-               while (bytes_remaining > 0)
-               {
-                       last_dword[i++] = *(buffer + bytes_written);
-                       bytes_remaining--;
-                       bytes_written++;
-               }
-
-               /* command */
-               cmd = FLASH_DWPG;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-               /* address */
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
-
-               /* data word 1 */
-               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
-               bytes_written += 4;
-
-               /* data word 2 */
-               target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
-               bytes_written += 4;
-
-               /* start programming cycle */
-               cmd = FLASH_DWPG | FLASH_WMS;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
-               while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
-               {
-                       alive_sleep(1);
-               }
-
-               retval = str7x_result(bank);
-
-               if (retval & FLASH_PGER)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               else if (retval & FLASH_WPF)
-                       return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int str7x_probe(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-#if 0
-COMMAND_HANDLER(str7x_handle_part_id_command)
-{
-       return ERROR_OK;
-}
-#endif
-
-static int str7x_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "str7x flash driver info");
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str7x_handle_disable_jtag_command)
-{
-       struct target *target = NULL;
-       struct str7x_flash_bank *str7x_info = NULL;
-
-       uint32_t flash_cmd;
-       uint16_t ProtectionLevel = 0;
-       uint16_t ProtectionRegs;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str7x disable_jtag <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str7x_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* first we get protection status */
-       uint32_t reg;
-       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &reg);
-
-       if (!(reg & str7x_info->disable_bit))
-       {
-               ProtectionLevel = 1;
-       }
-
-       target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &reg);
-       ProtectionRegs = ~(reg >> 16);
-
-       while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))
-       {
-               ProtectionRegs >>= 1;
-               ProtectionLevel++;
-       }
-
-       if (ProtectionLevel == 0)
-       {
-               flash_cmd = FLASH_SPR;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);
-               flash_cmd = FLASH_SPR | FLASH_WMS;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
-       }
-       else
-       {
-               flash_cmd = FLASH_SPR;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1 << (15 + ProtectionLevel)));
-               flash_cmd = FLASH_SPR | FLASH_WMS;
-               target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
-       }
-
-       return ERROR_OK;
-}
-
-static const struct command_registration str7x_exec_command_handlers[] = {
-       {
-               .name = "disable_jtag",
-               .handler = &str7x_handle_disable_jtag_command,
-               .mode = COMMAND_EXEC,
-               .help = "disable jtag access",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration str7x_command_handlers[] = {
-       {
-               .name = "str7x",
-               .mode = COMMAND_ANY,
-               .help = "str7x flash command group",
-               .chain = str7x_exec_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver str7x_flash = {
-               .name = "str7x",
-               .commands = str7x_command_handlers,
-               .flash_bank_command = &str7x_flash_bank_command,
-               .erase = &str7x_erase,
-               .protect = &str7x_protect,
-               .write = &str7x_write,
-               .probe = &str7x_probe,
-               .auto_probe = &str7x_probe,
-               .erase_check = &default_flash_blank_check,
-               .protect_check = &str7x_protect_check,
-               .info = &str7x_info,
-       };
diff --git a/src/flash/str7x.h b/src/flash/str7x.h
deleted file mode 100644 (file)
index 81af0f1..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef STR7X_H
-#define STR7X_H
-
-#include "flash.h"
-
-struct str7x_flash_bank
-{
-       uint32_t *sector_bits;
-       uint32_t disable_bit;
-       uint32_t busy_bits;
-       uint32_t register_base;
-       struct working_area *write_algorithm;
-};
-
-enum str7x_status_codes
-{
-       STR7X_CMD_SUCCESS = 0,
-       STR7X_INVALID_COMMAND = 1,
-       STR7X_SRC_ADDR_ERROR = 2,
-       STR7X_DST_ADDR_ERROR = 3,
-       STR7X_SRC_ADDR_NOT_MAPPED = 4,
-       STR7X_DST_ADDR_NOT_MAPPED = 5,
-       STR7X_COUNT_ERROR = 6,
-       STR7X_INVALID_SECTOR = 7,
-       STR7X_SECTOR_NOT_BLANK = 8,
-       STR7X_SECTOR_NOT_PREPARED = 9,
-       STR7X_COMPARE_ERROR = 10,
-       STR7X_BUSY = 11
-};
-
-/*  Flash registers */
-
-#define FLASH_CR0              0x00000000
-#define FLASH_CR1              0x00000004
-#define FLASH_DR0              0x00000008
-#define FLASH_DR1              0x0000000C
-#define FLASH_AR               0x00000010
-#define FLASH_ER               0x00000014
-#define FLASH_NVWPAR   0x0000DFB0
-#define FLASH_NVAPR0   0x0000DFB8
-#define FLASH_NVAPR1   0x0000DFBC
-
-/* FLASH_CR0 register bits */
-
-#define FLASH_WMS              0x80000000
-#define FLASH_SUSP             0x40000000
-#define FLASH_WPG              0x20000000
-#define FLASH_DWPG             0x10000000
-#define FLASH_SER              0x08000000
-#define FLASH_SPR              0x01000000
-#define FLASH_BER              0x04000000
-#define FLASH_MER              0x02000000
-#define FLASH_LOCK             0x00000010
-#define FLASH_BSYA1            0x00000004
-#define FLASH_BSYA0            0x00000002
-
-/* FLASH_CR1 register bits */
-
-#define FLASH_B1S              0x02000000
-#define FLASH_B0S              0x01000000
-#define FLASH_B1F1             0x00020000
-#define FLASH_B1F0             0x00010000
-#define FLASH_B0F7             0x00000080
-#define FLASH_B0F6             0x00000040
-#define FLASH_B0F5             0x00000020
-#define FLASH_B0F4             0x00000010
-#define FLASH_B0F3             0x00000008
-#define FLASH_B0F2             0x00000004
-#define FLASH_B0F1             0x00000002
-#define FLASH_B0F0             0x00000001
-
-/* FLASH_ER register bits */
-
-#define FLASH_WPF              0x00000100
-#define FLASH_RESER            0x00000080
-#define FLASH_SEQER            0x00000040
-#define FLASH_10ER             0x00000008
-#define FLASH_PGER             0x00000004
-#define FLASH_ERER             0x00000002
-#define FLASH_ERR              0x00000001
-
-struct str7x_mem_layout {
-       uint32_t sector_start;
-       uint32_t sector_size;
-       uint32_t sector_bit;
-};
-
-#endif /* STR7X_H */
diff --git a/src/flash/str9x.c b/src/flash/str9x.c
deleted file mode 100644 (file)
index 98f15e7..0000000
+++ /dev/null
@@ -1,711 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *
- *   Copyright (C) 2008 by Oyvind Harboe                                   *
- *   oyvind.harboe@zylin.com                                               *
- *                                                                         *
- *   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 "str9x.h"
-#include "arm966e.h"
-#include "algorithm.h"
-
-
-static uint32_t bank1start = 0x00080000;
-
-static int str9x_build_block_list(struct flash_bank *bank)
-{
-       struct str9x_flash_bank *str9x_info = bank->driver_priv;
-
-       int i;
-       int num_sectors;
-       int b0_sectors = 0, b1_sectors = 0;
-       uint32_t offset = 0;
-
-       /* set if we have large flash str9 */
-       str9x_info->variant = 0;
-       str9x_info->bank1 = 0;
-
-       switch (bank->size)
-       {
-               case (256 * 1024):
-                       b0_sectors = 4;
-                       break;
-               case (512 * 1024):
-                       b0_sectors = 8;
-                       break;
-               case (1024 * 1024):
-                       bank1start = 0x00100000;
-                       str9x_info->variant = 1;
-                       b0_sectors = 16;
-                       break;
-               case (2048 * 1024):
-                       bank1start = 0x00200000;
-                       str9x_info->variant = 1;
-                       b0_sectors = 32;
-                       break;
-               case (128 * 1024):
-                       str9x_info->variant = 1;
-                       str9x_info->bank1 = 1;
-                       b1_sectors = 8;
-                       bank1start = bank->base;
-                       break;
-               case (32 * 1024):
-                       str9x_info->bank1 = 1;
-                       b1_sectors = 4;
-                       bank1start = bank->base;
-                       break;
-               default:
-                       LOG_ERROR("BUG: unknown bank->size encountered");
-                       exit(-1);
-       }
-
-       num_sectors = b0_sectors + b1_sectors;
-
-       bank->num_sectors = num_sectors;
-       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
-       str9x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
-
-       num_sectors = 0;
-
-       for (i = 0; i < b0_sectors; i++)
-       {
-               bank->sectors[num_sectors].offset = offset;
-               bank->sectors[num_sectors].size = 0x10000;
-               offset += bank->sectors[i].size;
-               bank->sectors[num_sectors].is_erased = -1;
-               bank->sectors[num_sectors].is_protected = 1;
-               str9x_info->sector_bits[num_sectors++] = (1 << i);
-       }
-
-       for (i = 0; i < b1_sectors; i++)
-       {
-               bank->sectors[num_sectors].offset = offset;
-               bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000;
-               offset += bank->sectors[i].size;
-               bank->sectors[num_sectors].is_erased = -1;
-               bank->sectors[num_sectors].is_protected = 1;
-               if (str9x_info->variant)
-                       str9x_info->sector_bits[num_sectors++] = (1 << i);
-               else
-                       str9x_info->sector_bits[num_sectors++] = (1 << (i + 8));
-       }
-
-       return ERROR_OK;
-}
-
-/* flash bank str9x <base> <size> 0 0 <target#>
- */
-FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command)
-{
-       struct str9x_flash_bank *str9x_info;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank str9x configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       str9x_info = malloc(sizeof(struct str9x_flash_bank));
-       bank->driver_priv = str9x_info;
-
-       str9x_build_block_list(bank);
-
-       str9x_info->write_algorithm = NULL;
-
-       return ERROR_OK;
-}
-
-static int str9x_protect_check(struct flash_bank *bank)
-{
-       int retval;
-       struct str9x_flash_bank *str9x_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       int i;
-       uint32_t adr;
-       uint32_t status = 0;
-       uint16_t hstatus = 0;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* read level one protection */
-
-       if (str9x_info->variant)
-       {
-               if (str9x_info->bank1)
-               {
-                       adr = bank1start + 0x18;
-                       if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       status = hstatus;
-               }
-               else
-               {
-                       adr = bank1start + 0x14;
-                       if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       if ((retval = target_read_u32(target, adr, &status)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-               }
-       }
-       else
-       {
-               adr = bank1start + 0x10;
-               if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               status = hstatus;
-       }
-
-       /* read array command */
-       if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
-       {
-               return retval;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               if (status & str9x_info->sector_bits[i])
-                       bank->sectors[i].is_protected = 1;
-               else
-                       bank->sectors[i].is_protected = 0;
-       }
-
-       return ERROR_OK;
-}
-
-static int str9x_erase(struct flash_bank *bank, int first, int last)
-{
-       struct target *target = bank->target;
-       int i;
-       uint32_t adr;
-       uint8_t status;
-       uint8_t erase_cmd;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* Check if we erase whole bank */
-       if ((first == 0) && (last == (bank->num_sectors - 1)))
-       {
-               /* Optimize to run erase bank command instead of sector */
-               erase_cmd = 0x80;
-       }
-       else
-       {
-               /* Erase sector command */
-               erase_cmd = 0x20;
-       }
-
-       for (i = first; i <= last; i++)
-       {
-               int retval;
-               adr = bank->base + bank->sectors[i].offset;
-
-               /* erase sectors */
-               if ((retval = target_write_u16(target, adr, erase_cmd)) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = target_write_u16(target, adr, 0xD0)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               /* get status */
-               if ((retval = target_write_u16(target, adr, 0x70)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               int timeout;
-               for (timeout = 0; timeout < 1000; timeout++) {
-                       if ((retval = target_read_u8(target, adr, &status)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       if (status & 0x80)
-                               break;
-                       alive_sleep(1);
-               }
-               if (timeout == 1000)
-               {
-                       LOG_ERROR("erase timed out");
-                       return ERROR_FAIL;
-               }
-
-               /* clear status, also clear read array */
-               if ((retval = target_write_u16(target, adr, 0x50)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               /* read array command */
-               if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               if (status & 0x22)
-               {
-                       LOG_ERROR("error erasing flash bank, status: 0x%x", status);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-
-               /* If we ran erase bank command, we are finished */
-               if (erase_cmd == 0x80)
-                       break;
-       }
-
-       for (i = first; i <= last; i++)
-               bank->sectors[i].is_erased = 1;
-
-       return ERROR_OK;
-}
-
-static int str9x_protect(struct flash_bank *bank,
-               int set, int first, int last)
-{
-       struct target *target = bank->target;
-       int i;
-       uint32_t adr;
-       uint8_t status;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       for (i = first; i <= last; i++)
-       {
-               /* Level One Protection */
-
-               adr = bank->base + bank->sectors[i].offset;
-
-               target_write_u16(target, adr, 0x60);
-               if (set)
-                       target_write_u16(target, adr, 0x01);
-               else
-                       target_write_u16(target, adr, 0xD0);
-
-               /* query status */
-               target_read_u8(target, adr, &status);
-
-               /* clear status, also clear read array */
-               target_write_u16(target, adr, 0x50);
-
-               /* read array command */
-               target_write_u16(target, adr, 0xFF);
-       }
-
-       return ERROR_OK;
-}
-
-static int str9x_write_block(struct flash_bank *bank,
-               uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct str9x_flash_bank *str9x_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t buffer_size = 8192;
-       struct working_area *source;
-       uint32_t address = bank->base + offset;
-       struct reg_param reg_params[4];
-       struct armv4_5_algorithm armv4_5_info;
-       int retval = ERROR_OK;
-
-       uint32_t str9x_flash_write_code[] = {
-                                       /* write:                               */
-               0xe3c14003,     /*      bic     r4, r1, #3              */
-               0xe3a03040,     /*      mov     r3, #0x40               */
-               0xe1c430b0,     /*      strh r3, [r4, #0]       */
-               0xe0d030b2,     /*      ldrh r3, [r0], #2       */
-               0xe0c130b2,     /*      strh r3, [r1], #2       */
-               0xe3a03070,     /*      mov r3, #0x70           */
-               0xe1c430b0,     /*      strh r3, [r4, #0]       */
-                                       /* busy:                                */
-               0xe5d43000,     /*      ldrb r3, [r4, #0]       */
-               0xe3130080,     /*      tst r3, #0x80           */
-               0x0afffffc,     /*      beq busy                        */
-               0xe3a05050,     /*      mov     r5, #0x50               */
-               0xe1c450b0,     /*      strh r5, [r4, #0]       */
-               0xe3a050ff,     /*      mov     r5, #0xFF               */
-               0xe1c450b0,     /*      strh r5, [r4, #0]       */
-               0xe3130012,     /*      tst     r3, #0x12               */
-               0x1a000001,     /*      bne exit                        */
-               0xe2522001,     /*      subs r2, r2, #1         */
-               0x1affffed,     /*      bne write                       */
-                                       /* exit:                                */
-               0xeafffffe,     /*      b exit                          */
-       };
-
-       /* flash write code */
-       if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
-       {
-               LOG_WARNING("no working area available, can't do block memory writes");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
-
-       target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (uint8_t*)str9x_flash_write_code);
-
-       /* 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 (str9x_info->write_algorithm)
-                               target_free_working_area(target, str9x_info->write_algorithm);
-
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
-       }
-
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
-
-       while (count > 0)
-       {
-               uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
-
-               target_write_buffer(target, source->address, thisrun_count * 2, buffer);
-
-               buf_set_u32(reg_params[0].value, 0, 32, source->address);
-               buf_set_u32(reg_params[1].value, 0, 32, address);
-               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
-
-               if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
-               {
-                       LOG_ERROR("error executing str9x flash write algorithm");
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
-               {
-                       retval = ERROR_FLASH_OPERATION_FAILED;
-                       break;
-               }
-
-               buffer += thisrun_count * 2;
-               address += thisrun_count * 2;
-               count -= thisrun_count;
-       }
-
-       target_free_working_area(target, source);
-       target_free_working_area(target, str9x_info->write_algorithm);
-
-       destroy_reg_param(&reg_params[0]);
-       destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
-       destroy_reg_param(&reg_params[3]);
-
-       return retval;
-}
-
-static int str9x_write(struct flash_bank *bank,
-               uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct target *target = bank->target;
-       uint32_t words_remaining = (count / 2);
-       uint32_t bytes_remaining = (count & 0x00000001);
-       uint32_t address = bank->base + offset;
-       uint32_t bytes_written = 0;
-       uint8_t status;
-       int retval;
-       uint32_t check_address = offset;
-       uint32_t bank_adr;
-       int i;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset & 0x1)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               uint32_t sec_start = bank->sectors[i].offset;
-               uint32_t sec_end = sec_start + bank->sectors[i].size;
-
-               /* check if destination falls within the current sector */
-               if ((check_address >= sec_start) && (check_address < sec_end))
-               {
-                       /* check if destination ends in the current sector */
-                       if (offset + count < sec_end)
-                               check_address = offset + count;
-                       else
-                               check_address = sec_end;
-               }
-       }
-
-       if (check_address != offset + count)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       /* multiple half words (2-byte) to be programmed? */
-       if (words_remaining > 0)
-       {
-               /* try using a block write */
-               if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
-               {
-                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                       {
-                               /* if block write failed (no sufficient working area),
-                                * we use normal (slow) single dword accesses */
-                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
-                       }
-                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
-                       {
-                               LOG_ERROR("flash writing failed with error code: 0x%x", retval);
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-               }
-               else
-               {
-                       buffer += words_remaining * 2;
-                       address += words_remaining * 2;
-                       words_remaining = 0;
-               }
-       }
-
-       while (words_remaining > 0)
-       {
-               bank_adr = address & ~0x03;
-
-               /* write data command */
-               target_write_u16(target, bank_adr, 0x40);
-               target_write_memory(target, address, 2, 1, buffer + bytes_written);
-
-               /* get status command */
-               target_write_u16(target, bank_adr, 0x70);
-
-               int timeout;
-               for (timeout = 0; timeout < 1000; timeout++)
-               {
-                       target_read_u8(target, bank_adr, &status);
-                       if (status & 0x80)
-                               break;
-                       alive_sleep(1);
-               }
-               if (timeout == 1000)
-               {
-                       LOG_ERROR("write timed out");
-                       return ERROR_FAIL;
-               }
-
-               /* clear status reg and read array */
-               target_write_u16(target, bank_adr, 0x50);
-               target_write_u16(target, bank_adr, 0xFF);
-
-               if (status & 0x10)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               else if (status & 0x02)
-                       return ERROR_FLASH_OPERATION_FAILED;
-
-               bytes_written += 2;
-               words_remaining--;
-               address += 2;
-       }
-
-       if (bytes_remaining)
-       {
-               uint8_t last_halfword[2] = {0xff, 0xff};
-               int i = 0;
-
-               while (bytes_remaining > 0)
-               {
-                       last_halfword[i++] = *(buffer + bytes_written);
-                       bytes_remaining--;
-                       bytes_written++;
-               }
-
-               bank_adr = address & ~0x03;
-
-               /* write data command */
-               target_write_u16(target, bank_adr, 0x40);
-               target_write_memory(target, address, 2, 1, last_halfword);
-
-               /* query status command */
-               target_write_u16(target, bank_adr, 0x70);
-
-               int timeout;
-               for (timeout = 0; timeout < 1000; timeout++)
-               {
-                       target_read_u8(target, bank_adr, &status);
-                       if (status & 0x80)
-                               break;
-                       alive_sleep(1);
-               }
-               if (timeout == 1000)
-               {
-                       LOG_ERROR("write timed out");
-                       return ERROR_FAIL;
-               }
-
-               /* clear status reg and read array */
-               target_write_u16(target, bank_adr, 0x50);
-               target_write_u16(target, bank_adr, 0xFF);
-
-               if (status & 0x10)
-                       return ERROR_FLASH_OPERATION_FAILED;
-               else if (status & 0x02)
-                       return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
-}
-
-static int str9x_probe(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-#if 0
-COMMAND_HANDLER(str9x_handle_part_id_command)
-{
-       return ERROR_OK;
-}
-#endif
-
-static int str9x_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "str9x flash driver info");
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9x_handle_flash_config_command)
-{
-       struct str9x_flash_bank *str9x_info;
-       struct target *target = NULL;
-
-       if (CMD_ARGC < 5)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       uint32_t bbsr, nbbsr, bbadr, nbbadr;
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], bbsr);
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], nbbsr);
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], bbadr);
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], nbbadr);
-
-       str9x_info = bank->driver_priv;
-
-       target = bank->target;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* config flash controller */
-       target_write_u32(target, FLASH_BBSR, bbsr);
-       target_write_u32(target, FLASH_NBBSR, nbbsr);
-       target_write_u32(target, FLASH_BBADR, bbadr >> 2);
-       target_write_u32(target, FLASH_NBBADR, nbbadr >> 2);
-
-       /* set bit 18 instruction TCM order as per flash programming manual */
-       arm966e_write_cp15(target, 62, 0x40000);
-
-       /* enable flash bank 1 */
-       target_write_u32(target, FLASH_CR, 0x18);
-       return ERROR_OK;
-}
-
-static const struct command_registration str9x_config_command_handlers[] = {
-       {
-               .name = "disable_jtag",
-               .handler = &str9x_handle_flash_config_command,
-               .mode = COMMAND_EXEC,
-               .help = "configure str9x flash controller",
-               .usage = "<bank_id> <BBSR> <NBBSR> <BBADR> <NBBADR>",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration str9x_command_handlers[] = {
-       {
-               .name = "str9x",
-               .mode = COMMAND_ANY,
-               .help = "str9x flash command group",
-               .chain = str9x_config_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver str9x_flash = {
-               .name = "str9x",
-               .commands = str9x_command_handlers,
-               .flash_bank_command = &str9x_flash_bank_command,
-               .erase = &str9x_erase,
-               .protect = &str9x_protect,
-               .write = &str9x_write,
-               .probe = &str9x_probe,
-               .auto_probe = &str9x_probe,
-               .erase_check = &default_flash_blank_check,
-               .protect_check = &str9x_protect_check,
-               .info = &str9x_info,
-       };
diff --git a/src/flash/str9x.h b/src/flash/str9x.h
deleted file mode 100644 (file)
index c9d5152..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef STR9X_H
-#define STR9X_H
-
-#include "flash.h"
-
-struct str9x_flash_bank
-{
-       uint32_t *sector_bits;
-       int variant;
-       int bank1;
-       struct working_area *write_algorithm;
-};
-
-enum str9x_status_codes
-{
-       STR9X_CMD_SUCCESS = 0,
-       STR9X_INVALID_COMMAND = 1,
-       STR9X_SRC_ADDR_ERROR = 2,
-       STR9X_DST_ADDR_ERROR = 3,
-       STR9X_SRC_ADDR_NOT_MAPPED = 4,
-       STR9X_DST_ADDR_NOT_MAPPED = 5,
-       STR9X_COUNT_ERROR = 6,
-       STR9X_INVALID_SECTOR = 7,
-       STR9X_SECTOR_NOT_BLANK = 8,
-       STR9X_SECTOR_NOT_PREPARED = 9,
-       STR9X_COMPARE_ERROR = 10,
-       STR9X_BUSY = 11
-};
-
-/* Flash registers */
-
-#define FLASH_BBSR             0x54000000              /* Boot Bank Size Register                */
-#define FLASH_NBBSR            0x54000004              /* Non-Boot Bank Size Register            */
-#define FLASH_BBADR            0x5400000C              /* Boot Bank Base Address Register        */
-#define FLASH_NBBADR   0x54000010              /* Non-Boot Bank Base Address Register    */
-#define FLASH_CR               0x54000018              /* Control Register                       */
-#define FLASH_SR               0x5400001C              /* Status Register                        */
-#define FLASH_BCE5ADDR 0x54000020              /* BC Fifth Entry Target Address Register */
-
-#endif /* STR9X_H */
diff --git a/src/flash/str9xpec.c b/src/flash/str9xpec.c
deleted file mode 100644 (file)
index 96e1259..0000000
+++ /dev/null
@@ -1,1257 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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 "str9xpec.h"
-#include "arm7_9_common.h"
-
-
-static int str9xpec_erase_area(struct flash_bank *bank, int first, int last);
-static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector);
-static int str9xpec_write_options(struct flash_bank *bank);
-
-int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state)
-{
-       if (tap == NULL) {
-               return ERROR_TARGET_INVALID;
-       }
-
-       if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr)
-       {
-               struct scan_field field;
-
-               field.tap = tap;
-               field.num_bits = tap->ir_length;
-               field.out_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
-               buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
-               field.in_value = NULL;
-
-               jtag_add_ir_scan(1, &field, end_state);
-
-               free(field.out_value);
-       }
-
-       return ERROR_OK;
-}
-
-static uint8_t str9xpec_isc_status(struct jtag_tap *tap)
-{
-       struct scan_field field;
-       uint8_t status;
-
-       if (str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE) != ERROR_OK)
-               return ISC_STATUS_ERROR;
-
-       field.tap = tap;
-       field.num_bits = 8;
-       field.out_value = NULL;
-       field.in_value = &status;
-
-
-       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-       jtag_execute_queue();
-
-       LOG_DEBUG("status: 0x%2.2x", status);
-
-       if (status & ISC_STATUS_SECURITY)
-               LOG_INFO("Device Security Bit Set");
-
-       return status;
-}
-
-static int str9xpec_isc_enable(struct flash_bank *bank)
-{
-       uint8_t status;
-       struct jtag_tap *tap;
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       tap = str9xpec_info->tap;
-
-       if (str9xpec_info->isc_enable)
-               return ERROR_OK;
-
-       /* enter isc mode */
-       if (str9xpec_set_instr(tap, ISC_ENABLE, TAP_IDLE) != ERROR_OK)
-               return ERROR_TARGET_INVALID;
-
-       /* check ISC status */
-       status = str9xpec_isc_status(tap);
-       if (status & ISC_STATUS_MODE)
-       {
-               /* we have entered isc mode */
-               str9xpec_info->isc_enable = 1;
-               LOG_DEBUG("ISC_MODE Enabled");
-       }
-
-       return ERROR_OK;
-}
-
-static int str9xpec_isc_disable(struct flash_bank *bank)
-{
-       uint8_t status;
-       struct jtag_tap *tap;
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       tap = str9xpec_info->tap;
-
-       if (!str9xpec_info->isc_enable)
-               return ERROR_OK;
-
-       if (str9xpec_set_instr(tap, ISC_DISABLE, TAP_IDLE) != ERROR_OK)
-               return ERROR_TARGET_INVALID;
-
-       /* delay to handle aborts */
-       jtag_add_sleep(50);
-
-       /* check ISC status */
-       status = str9xpec_isc_status(tap);
-       if (!(status & ISC_STATUS_MODE))
-       {
-               /* we have left isc mode */
-               str9xpec_info->isc_enable = 0;
-               LOG_DEBUG("ISC_MODE Disabled");
-       }
-
-       return ERROR_OK;
-}
-
-static int str9xpec_read_config(struct flash_bank *bank)
-{
-       struct scan_field field;
-       uint8_t status;
-       struct jtag_tap *tap;
-
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       tap = str9xpec_info->tap;
-
-       LOG_DEBUG("ISC_CONFIGURATION");
-
-       /* execute ISC_CONFIGURATION command */
-       str9xpec_set_instr(tap, ISC_CONFIGURATION, TAP_IRPAUSE);
-
-       field.tap = tap;
-       field.num_bits = 64;
-       field.out_value = NULL;
-       field.in_value = str9xpec_info->options;
-
-
-       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-       jtag_execute_queue();
-
-       status = str9xpec_isc_status(tap);
-
-       return status;
-}
-
-static int str9xpec_build_block_list(struct flash_bank *bank)
-{
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       int i;
-       int num_sectors;
-       int b0_sectors = 0, b1_sectors = 0;
-       uint32_t offset = 0;
-       int b1_size = 0x2000;
-
-       switch (bank->size)
-       {
-               case (256 * 1024):
-                       b0_sectors = 4;
-                       break;
-               case (512 * 1024):
-                       b0_sectors = 8;
-                       break;
-               case (1024 * 1024):
-                       b0_sectors = 16;
-                       break;
-               case (2048 * 1024):
-                       b0_sectors = 32;
-                       break;
-               case (128 * 1024):
-                       b1_size = 0x4000;
-                       b1_sectors = 8;
-                       break;
-               case (32 * 1024):
-                       b1_sectors = 4;
-                       break;
-               default:
-                       LOG_ERROR("BUG: unknown bank->size encountered");
-                       exit(-1);
-       }
-
-       num_sectors = b0_sectors + b1_sectors;
-
-       bank->num_sectors = num_sectors;
-       bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
-       str9xpec_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
-
-       num_sectors = 0;
-
-       for (i = 0; i < b0_sectors; i++)
-       {
-               bank->sectors[num_sectors].offset = offset;
-               bank->sectors[num_sectors].size = 0x10000;
-               offset += bank->sectors[i].size;
-               bank->sectors[num_sectors].is_erased = -1;
-               bank->sectors[num_sectors].is_protected = 1;
-               str9xpec_info->sector_bits[num_sectors++] = i;
-       }
-
-       for (i = 0; i < b1_sectors; i++)
-       {
-               bank->sectors[num_sectors].offset = offset;
-               bank->sectors[num_sectors].size = b1_size;
-               offset += bank->sectors[i].size;
-               bank->sectors[num_sectors].is_erased = -1;
-               bank->sectors[num_sectors].is_protected = 1;
-               str9xpec_info->sector_bits[num_sectors++] = i + 32;
-       }
-
-       return ERROR_OK;
-}
-
-/* flash bank str9x <base> <size> 0 0 <target#>
- */
-FLASH_BANK_COMMAND_HANDLER(str9xpec_flash_bank_command)
-{
-       struct str9xpec_flash_controller *str9xpec_info;
-       struct arm *armv4_5 = NULL;
-       struct arm7_9_common *arm7_9 = NULL;
-       struct arm_jtag *jtag_info = NULL;
-
-       if (CMD_ARGC < 6)
-       {
-               LOG_WARNING("incomplete flash_bank str9x configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-
-       str9xpec_info = malloc(sizeof(struct str9xpec_flash_controller));
-       bank->driver_priv = str9xpec_info;
-
-       /* REVISIT verify that the jtag position of flash controller is
-        * right after *THIS* core, which must be a STR9xx core ...
-        */
-       armv4_5 = bank->target->arch_info;
-       arm7_9 = armv4_5->arch_info;
-       jtag_info = &arm7_9->jtag_info;
-
-       str9xpec_info->tap = bank->target->tap;
-       str9xpec_info->isc_enable = 0;
-
-       str9xpec_build_block_list(bank);
-
-       /* clear option byte register */
-       buf_set_u32(str9xpec_info->options, 0, 64, 0);
-
-       return ERROR_OK;
-}
-
-static int str9xpec_blank_check(struct flash_bank *bank, int first, int last)
-{
-       struct scan_field field;
-       uint8_t status;
-       struct jtag_tap *tap;
-       int i;
-       uint8_t *buffer = NULL;
-
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       tap = str9xpec_info->tap;
-
-       if (!str9xpec_info->isc_enable) {
-               str9xpec_isc_enable(bank);
-       }
-
-       if (!str9xpec_info->isc_enable) {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       buffer = calloc(DIV_ROUND_UP(64, 8), 1);
-
-       LOG_DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);
-
-       for (i = first; i <= last; i++) {
-               buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
-       }
-
-       /* execute ISC_BLANK_CHECK command */
-       str9xpec_set_instr(tap, ISC_BLANK_CHECK, TAP_IRPAUSE);
-
-       field.tap = tap;
-       field.num_bits = 64;
-       field.out_value = buffer;
-       field.in_value = NULL;
-
-       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-       jtag_add_sleep(40000);
-
-       /* read blank check result */
-       field.tap = tap;
-       field.num_bits = 64;
-       field.out_value = NULL;
-       field.in_value = buffer;
-
-       jtag_add_dr_scan(1, &field, TAP_IRPAUSE);
-       jtag_execute_queue();
-
-       status = str9xpec_isc_status(tap);
-
-       for (i = first; i <= last; i++)
-       {
-               if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))
-                       bank->sectors[i].is_erased = 0;
-               else
-                       bank->sectors[i].is_erased = 1;
-       }
-
-       free(buffer);
-
-       str9xpec_isc_disable(bank);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-       return ERROR_OK;
-}
-
-static int str9xpec_protect_check(struct flash_bank *bank)
-{
-       uint8_t status;
-       int i;
-
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       status = str9xpec_read_config(bank);
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))
-                       bank->sectors[i].is_protected = 1;
-               else
-                       bank->sectors[i].is_protected = 0;
-       }
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-       return ERROR_OK;
-}
-
-static int str9xpec_erase_area(struct flash_bank *bank, int first, int last)
-{
-       struct scan_field field;
-       uint8_t status;
-       struct jtag_tap *tap;
-       int i;
-       uint8_t *buffer = NULL;
-
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       tap = str9xpec_info->tap;
-
-       if (!str9xpec_info->isc_enable) {
-               str9xpec_isc_enable(bank);
-       }
-
-       if (!str9xpec_info->isc_enable) {
-               return ISC_STATUS_ERROR;
-       }
-
-       buffer = calloc(DIV_ROUND_UP(64, 8), 1);
-
-       LOG_DEBUG("erase: first_bank: %i, last_bank: %i", first, last);
-
-       /* last bank: 0xFF signals a full erase (unlock complete device) */
-       /* last bank: 0xFE signals a option byte erase */
-       if (last == 0xFF)
-       {
-               for (i = 0; i < 64; i++) {
-                       buf_set_u32(buffer, i, 1, 1);
-               }
-       }
-       else if (last == 0xFE)
-       {
-               buf_set_u32(buffer, 49, 1, 1);
-       }
-       else
-       {
-               for (i = first; i <= last; i++) {
-                       buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
-               }
-       }
-
-       LOG_DEBUG("ISC_ERASE");
-
-       /* execute ISC_ERASE command */
-       str9xpec_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
-
-       field.tap = tap;
-       field.num_bits = 64;
-       field.out_value = buffer;
-       field.in_value = NULL;
-
-       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-       jtag_execute_queue();
-
-       jtag_add_sleep(10);
-
-       /* wait for erase completion */
-       while (!((status = str9xpec_isc_status(tap)) & ISC_STATUS_BUSY)) {
-               alive_sleep(1);
-       }
-
-       free(buffer);
-
-       str9xpec_isc_disable(bank);
-
-       return status;
-}
-
-static int str9xpec_erase(struct flash_bank *bank, int first, int last)
-{
-       int status;
-
-       status = str9xpec_erase_area(bank, first, last);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       return ERROR_OK;
-}
-
-static int str9xpec_lock_device(struct flash_bank *bank)
-{
-       struct scan_field field;
-       uint8_t status;
-       struct jtag_tap *tap;
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       str9xpec_info = bank->driver_priv;
-       tap = str9xpec_info->tap;
-
-       if (!str9xpec_info->isc_enable) {
-               str9xpec_isc_enable(bank);
-       }
-
-       if (!str9xpec_info->isc_enable) {
-               return ISC_STATUS_ERROR;
-       }
-
-       /* set security address */
-       str9xpec_set_address(bank, 0x80);
-
-       /* execute ISC_PROGRAM command */
-       str9xpec_set_instr(tap, ISC_PROGRAM_SECURITY, TAP_IDLE);
-
-       str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
-
-       do {
-               field.tap = tap;
-               field.num_bits = 8;
-               field.out_value = NULL;
-               field.in_value = &status;
-
-               jtag_add_dr_scan(1, &field, jtag_get_end_state());
-               jtag_execute_queue();
-
-       } while (!(status & ISC_STATUS_BUSY));
-
-       str9xpec_isc_disable(bank);
-
-       return status;
-}
-
-static int str9xpec_unlock_device(struct flash_bank *bank)
-{
-       uint8_t status;
-
-       status = str9xpec_erase_area(bank, 0, 255);
-
-       return status;
-}
-
-static int str9xpec_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       uint8_t status;
-       int i;
-
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       status = str9xpec_read_config(bank);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       LOG_DEBUG("protect: first_bank: %i, last_bank: %i", first, last);
-
-       /* last bank: 0xFF signals a full device protect */
-       if (last == 0xFF)
-       {
-               if (set)
-               {
-                       status = str9xpec_lock_device(bank);
-               }
-               else
-               {
-                       /* perform full erase to unlock device */
-                       status = str9xpec_unlock_device(bank);
-               }
-       }
-       else
-       {
-               for (i = first; i <= last; i++)
-               {
-                       if (set)
-                               buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);
-                       else
-                               buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);
-               }
-
-               status = str9xpec_write_options(bank);
-       }
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       return ERROR_OK;
-}
-
-static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector)
-{
-       struct jtag_tap *tap;
-       struct scan_field field;
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-
-       tap = str9xpec_info->tap;
-
-       /* set flash controller address */
-       str9xpec_set_instr(tap, ISC_ADDRESS_SHIFT, TAP_IRPAUSE);
-
-       field.tap = tap;
-       field.num_bits = 8;
-       field.out_value = &sector;
-       field.in_value = NULL;
-
-       jtag_add_dr_scan(1, &field, jtag_get_end_state());
-
-       return ERROR_OK;
-}
-
-static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-       struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
-       uint32_t dwords_remaining = (count / 8);
-       uint32_t bytes_remaining = (count & 0x00000007);
-       uint32_t bytes_written = 0;
-       uint8_t status;
-       uint32_t check_address = offset;
-       struct jtag_tap *tap;
-       struct scan_field field;
-       uint8_t *scanbuf;
-       int i;
-       int first_sector = 0;
-       int last_sector = 0;
-
-       tap = str9xpec_info->tap;
-
-       if (!str9xpec_info->isc_enable) {
-               str9xpec_isc_enable(bank);
-       }
-
-       if (!str9xpec_info->isc_enable) {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (offset & 0x7)
-       {
-               LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
-
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               uint32_t sec_start = bank->sectors[i].offset;
-               uint32_t sec_end = sec_start + bank->sectors[i].size;
-
-               /* check if destination falls within the current sector */
-               if ((check_address >= sec_start) && (check_address < sec_end))
-               {
-                       /* check if destination ends in the current sector */
-                       if (offset + count < sec_end)
-                               check_address = offset + count;
-                       else
-                               check_address = sec_end;
-               }
-
-               if ((offset >= sec_start) && (offset < sec_end)) {
-                       first_sector = i;
-               }
-
-               if ((offset + count >= sec_start) && (offset + count < sec_end)) {
-                       last_sector = i;
-               }
-       }
-
-       if (check_address != offset + count)
-               return ERROR_FLASH_DST_OUT_OF_BANK;
-
-       LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
-
-       scanbuf = calloc(DIV_ROUND_UP(64, 8), 1);
-
-       LOG_DEBUG("ISC_PROGRAM");
-
-       for (i = first_sector; i <= last_sector; i++)
-       {
-               str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);
-
-               dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);
-
-               while (dwords_remaining > 0)
-               {
-                       str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
-
-                       field.tap = tap;
-                       field.num_bits = 64;
-                       field.out_value = (buffer + bytes_written);
-                       field.in_value = NULL;
-
-                       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-
-                       /* small delay before polling */
-                       jtag_add_sleep(50);
-
-                       str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
-
-                       do {
-                               field.tap = tap;
-                               field.num_bits = 8;
-                               field.out_value = NULL;
-                               field.in_value = scanbuf;
-
-                               jtag_add_dr_scan(1, &field, jtag_get_end_state());
-                               jtag_execute_queue();
-
-                               status = buf_get_u32(scanbuf, 0, 8);
-
-                       } while (!(status & ISC_STATUS_BUSY));
-
-                       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-                               return ERROR_FLASH_OPERATION_FAILED;
-
-                       /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
-                               return ERROR_FLASH_OPERATION_FAILED; */
-
-                       dwords_remaining--;
-                       bytes_written += 8;
-               }
-       }
-
-       if (bytes_remaining)
-       {
-               uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-               int i = 0;
-
-               while (bytes_remaining > 0)
-               {
-                       last_dword[i++] = *(buffer + bytes_written);
-                       bytes_remaining--;
-                       bytes_written++;
-               }
-
-               str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
-
-               field.tap = tap;
-               field.num_bits = 64;
-               field.out_value = last_dword;
-               field.in_value = NULL;
-
-               jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-
-               /* small delay before polling */
-               jtag_add_sleep(50);
-
-               str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
-
-               do {
-                       field.tap = tap;
-                       field.num_bits = 8;
-                       field.out_value = NULL;
-                       field.in_value = scanbuf;
-
-                       jtag_add_dr_scan(1, &field, jtag_get_end_state());
-                       jtag_execute_queue();
-
-                       status = buf_get_u32(scanbuf, 0, 8);
-
-               } while (!(status & ISC_STATUS_BUSY));
-
-               if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-                       return ERROR_FLASH_OPERATION_FAILED;
-
-               /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
-                       return ERROR_FLASH_OPERATION_FAILED; */
-       }
-
-       free(scanbuf);
-
-       str9xpec_isc_disable(bank);
-
-       return ERROR_OK;
-}
-
-static int str9xpec_probe(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_part_id_command)
-{
-       struct scan_field field;
-       uint8_t *buffer = NULL;
-       struct jtag_tap *tap;
-       uint32_t idcode;
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 1)
-               return ERROR_COMMAND_SYNTAX_ERROR;
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-       tap = str9xpec_info->tap;
-
-       buffer = calloc(DIV_ROUND_UP(32, 8), 1);
-
-       str9xpec_set_instr(tap, ISC_IDCODE, TAP_IRPAUSE);
-
-       field.tap = tap;
-       field.num_bits = 32;
-       field.out_value = NULL;
-       field.in_value = buffer;
-
-       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-       jtag_execute_queue();
-
-       idcode = buf_get_u32(buffer, 0, 32);
-
-       command_print(CMD_CTX, "str9xpec part id: 0x%8.8" PRIx32 "", idcode);
-
-       free(buffer);
-
-       return ERROR_OK;
-}
-
-static int str9xpec_erase_check(struct flash_bank *bank)
-{
-       return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-static int str9xpec_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       snprintf(buf, buf_size, "str9xpec flash driver info");
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_options_read_command)
-{
-       uint8_t status;
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str9xpec options_read <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-
-       status = str9xpec_read_config(bank);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       /* boot bank */
-       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))
-               command_print(CMD_CTX, "CS Map: bank1");
-       else
-               command_print(CMD_CTX, "CS Map: bank0");
-
-       /* OTP lock */
-       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))
-               command_print(CMD_CTX, "OTP Lock: OTP Locked");
-       else
-               command_print(CMD_CTX, "OTP Lock: OTP Unlocked");
-
-       /* LVD Threshold */
-       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))
-               command_print(CMD_CTX, "LVD Threshold: 2.7v");
-       else
-               command_print(CMD_CTX, "LVD Threshold: 2.4v");
-
-       /* LVD reset warning */
-       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))
-               command_print(CMD_CTX, "LVD Reset Warning: VDD or VDDQ Inputs");
-       else
-               command_print(CMD_CTX, "LVD Reset Warning: VDD Input Only");
-
-       /* LVD reset select */
-       if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))
-               command_print(CMD_CTX, "LVD Reset Selection: VDD or VDDQ Inputs");
-       else
-               command_print(CMD_CTX, "LVD Reset Selection: VDD Input Only");
-
-       return ERROR_OK;
-}
-
-static int str9xpec_write_options(struct flash_bank *bank)
-{
-       struct scan_field field;
-       uint8_t status;
-       struct jtag_tap *tap;
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       str9xpec_info = bank->driver_priv;
-       tap = str9xpec_info->tap;
-
-       /* erase config options first */
-       status = str9xpec_erase_area(bank, 0xFE, 0xFE);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return status;
-
-       if (!str9xpec_info->isc_enable) {
-               str9xpec_isc_enable(bank);
-       }
-
-       if (!str9xpec_info->isc_enable) {
-               return ISC_STATUS_ERROR;
-       }
-
-       /* according to data 64th bit has to be set */
-       buf_set_u32(str9xpec_info->options, 63, 1, 1);
-
-       /* set option byte address */
-       str9xpec_set_address(bank, 0x50);
-
-       /* execute ISC_PROGRAM command */
-       str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
-
-       field.tap = tap;
-       field.num_bits = 64;
-       field.out_value = str9xpec_info->options;
-       field.in_value = NULL;
-
-       jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
-
-       /* small delay before polling */
-       jtag_add_sleep(50);
-
-       str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
-
-       do {
-               field.tap = tap;
-               field.num_bits = 8;
-               field.out_value = NULL;
-               field.in_value = &status;
-
-               jtag_add_dr_scan(1, &field, jtag_get_end_state());
-               jtag_execute_queue();
-
-       } while (!(status & ISC_STATUS_BUSY));
-
-       str9xpec_isc_disable(bank);
-
-       return status;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_options_write_command)
-{
-       uint8_t status;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str9xpec options_write <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       status = str9xpec_write_options(bank);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command)
-{
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 2)
-       {
-               command_print(CMD_CTX, "str9xpec options_cmap <bank> <bank0 | bank1>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-
-       if (strcmp(CMD_ARGV[1], "bank1") == 0)
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);
-       }
-       else
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_options_lvdthd_command)
-{
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 2)
-       {
-               command_print(CMD_CTX, "str9xpec options_lvdthd <bank> <2.4v | 2.7v>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-
-       if (strcmp(CMD_ARGV[1], "2.7v") == 0)
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);
-       }
-       else
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_options_lvdsel_command)
-{
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 2)
-       {
-               command_print(CMD_CTX, "str9xpec options_lvdsel <bank> <vdd | vdd_vddq>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-
-       if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0)
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);
-       }
-       else
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_options_lvdwarn_command)
-{
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 2)
-       {
-               command_print(CMD_CTX, "str9xpec options_lvdwarn <bank> <vdd | vdd_vddq>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-
-       if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0)
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);
-       }
-       else
-       {
-               buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);
-       }
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_lock_command)
-{
-       uint8_t status;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str9xpec lock <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       status = str9xpec_lock_device(bank);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_unlock_command)
-{
-       uint8_t status;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str9xpec unlock <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       status = str9xpec_unlock_device(bank);
-
-       if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
-               return ERROR_FLASH_OPERATION_FAILED;
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command)
-{
-       struct jtag_tap *tap0;
-       struct jtag_tap *tap1;
-       struct jtag_tap *tap2;
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str9xpec enable_turbo <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-
-       tap0 = str9xpec_info->tap;
-
-       /* remove arm core from chain - enter turbo mode */
-       tap1 = tap0->next_tap;
-       if (tap1 == NULL)
-       {
-               /* things are *WRONG* */
-               command_print(CMD_CTX,"**STR9FLASH** (tap1) invalid chain?");
-               return ERROR_OK;
-       }
-       tap2 = tap1->next_tap;
-       if (tap2 == NULL)
-       {
-               /* things are *WRONG* */
-               command_print(CMD_CTX,"**STR9FLASH** (tap2) invalid chain?");
-               return ERROR_OK;
-       }
-
-       /* enable turbo mode - TURBO-PROG-ENABLE */
-       str9xpec_set_instr(tap2, 0xD, TAP_IDLE);
-       if ((retval = jtag_execute_queue()) != ERROR_OK)
-               return retval;
-
-       /* modify scan chain - str9 core has been removed */
-       tap1->enabled = 0;
-
-       return ERROR_OK;
-}
-
-COMMAND_HANDLER(str9xpec_handle_flash_disable_turbo_command)
-{
-       struct jtag_tap *tap;
-       struct str9xpec_flash_controller *str9xpec_info = NULL;
-
-       if (CMD_ARGC < 1)
-       {
-               command_print(CMD_CTX, "str9xpec disable_turbo <bank>");
-               return ERROR_OK;
-       }
-
-       struct flash_bank *bank;
-       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
-               return retval;
-
-       str9xpec_info = bank->driver_priv;
-       tap = str9xpec_info->tap;
-
-       if (tap == NULL)
-               return ERROR_FAIL;
-
-       /* exit turbo mode via RESET */
-       str9xpec_set_instr(tap, ISC_NOOP, TAP_IDLE);
-       jtag_add_tlr();
-       jtag_execute_queue();
-
-       /* restore previous scan chain */
-       if (tap->next_tap) {
-               tap->next_tap->enabled = 1;
-       }
-
-       return ERROR_OK;
-}
-
-static const struct command_registration str9xpec_config_command_handlers[] = {
-       {
-               .name = "enable_turbo",
-               .handler = str9xpec_handle_flash_enable_turbo_command,
-               .mode = COMMAND_EXEC,
-               .help = "enable str9xpec turbo mode",
-       },
-       {
-               .name = "disable_turbo",
-               .handler = str9xpec_handle_flash_disable_turbo_command,
-               .mode = COMMAND_EXEC,
-               .help = "disable str9xpec turbo mode",
-       },
-       {
-               .name = "options_cmap",
-               .handler = str9xpec_handle_flash_options_cmap_command,
-               .mode = COMMAND_EXEC,
-               .help = "configure str9xpec boot sector",
-       },
-       {
-               .name = "options_lvdthd",
-               .handler = str9xpec_handle_flash_options_lvdthd_command,
-               .mode = COMMAND_EXEC,
-               .help = "configure str9xpec lvd threshold",
-       },
-       {
-               .name = "options_lvdsel",
-               .handler = str9xpec_handle_flash_options_lvdsel_command,
-               .mode = COMMAND_EXEC,
-               .help = "configure str9xpec lvd selection",
-       },
-       {
-               .name = "options_lvdwarn",
-               .handler = str9xpec_handle_flash_options_lvdwarn_command,
-               .mode = COMMAND_EXEC,
-               .help = "configure str9xpec lvd warning",
-       },
-       {
-               .name = "options_read",
-               .handler = str9xpec_handle_flash_options_read_command,
-               .mode = COMMAND_EXEC,
-               .help = "read str9xpec options",
-       },
-       {
-               .name = "options_write",
-               .handler = str9xpec_handle_flash_options_write_command,
-               .mode = COMMAND_EXEC,
-               .help = "write str9xpec options",
-       },
-       {
-               .name = "lock",
-               .handler = str9xpec_handle_flash_lock_command,
-               .mode = COMMAND_EXEC,
-               .help = "lock str9xpec device",
-       },
-       {
-               .name = "unlock",
-               .handler = str9xpec_handle_flash_unlock_command,
-               .mode = COMMAND_EXEC,
-               .help = "unlock str9xpec device",
-       },
-       {
-               .name = "part_id",
-               .handler = str9xpec_handle_part_id_command,
-               .mode = COMMAND_EXEC,
-               .help = "print part id of str9xpec flash bank <num>",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration str9xpec_command_handlers[] = {
-       {
-               .name = "str9xpec",
-               .mode = COMMAND_ANY,
-               .help = "str9xpec flash command group",
-               .chain = str9xpec_config_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-struct flash_driver str9xpec_flash = {
-               .name = "str9xpec",
-               .commands = str9xpec_command_handlers,
-               .flash_bank_command = &str9xpec_flash_bank_command,
-               .erase = &str9xpec_erase,
-               .protect = &str9xpec_protect,
-               .write = &str9xpec_write,
-               .probe = &str9xpec_probe,
-               .auto_probe = &str9xpec_probe,
-               .erase_check = &str9xpec_erase_check,
-               .protect_check = &str9xpec_protect_check,
-               .info = &str9xpec_info,
-       };
diff --git a/src/flash/str9xpec.h b/src/flash/str9xpec.h
deleted file mode 100644 (file)
index 1c8d41b..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   Copyright (C) 2008 by Spencer Oliver                                  *
- *   spen@spen-soft.co.uk                                                  *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef STR9XPEC_H
-#define STR9XPEC_H
-
-#include "flash.h"
-#include "jtag.h"
-
-struct str9xpec_flash_controller
-{
-       struct jtag_tap *tap;
-       uint32_t *sector_bits;
-       int chain_pos;
-       int isc_enable;
-       uint8_t options[8];
-};
-
-enum str9xpec_status_codes
-{
-       STR9XPEC_INVALID_COMMAND = 1,
-       STR9XPEC_ISC_SUCCESS = 2,
-       STR9XPEC_ISC_DISABLED = 3,
-       STR9XPEC_ISC_INTFAIL = 32,
-};
-
-/* ISC commands */
-
-#define ISC_IDCODE                             0xFE
-#define ISC_MFG_READ                   0x4C
-#define ISC_CONFIGURATION              0x07
-#define ISC_ENABLE                             0x0C
-#define ISC_DISABLE                            0x0F
-#define ISC_NOOP                               0x10
-#define ISC_ADDRESS_SHIFT              0x11
-#define ISC_CLR_STATUS                 0x13
-#define ISC_PROGRAM                            0x20
-#define ISC_PROGRAM_SECURITY   0x22
-#define ISC_PROGRAM_UC                 0x23
-#define ISC_ERASE                              0x30
-#define ISC_READ                               0x50
-#define ISC_BLANK_CHECK                        0x60
-
-/* ISC_DEFAULT bit definitions */
-
-#define ISC_STATUS_SECURITY            0x40
-#define ISC_STATUS_INT_ERROR   0x30
-#define ISC_STATUS_MODE                        0x08
-#define ISC_STATUS_BUSY                        0x04
-#define ISC_STATUS_ERROR               0x03
-
-/* Option bytes definitions */
-
-#define STR9XPEC_OPT_CSMAPBIT          48
-#define STR9XPEC_OPT_LVDTHRESBIT       49
-#define STR9XPEC_OPT_LVDSELBIT         50
-#define STR9XPEC_OPT_LVDWARNBIT                51
-#define STR9XPEC_OPT_OTPBIT                    63
-
-#endif /* STR9XPEC_H */
diff --git a/src/flash/tms470.c b/src/flash/tms470.c
deleted file mode 100644 (file)
index 5965934..0000000
+++ /dev/null
@@ -1,1271 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007,2008 by Christopher Kilgour                        *
- *   techie |_at_| whiterocker |_dot_| com                                 *
- *                                                                         *
- *   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 "tms470.h"
-
-
-/* ----------------------------------------------------------------------
-                      Internal Support, Helpers
-   ---------------------------------------------------------------------- */
-
-const struct flash_sector TMS470R1A256_SECTORS[] = {
-       {0x00000000, 0x00002000, -1, -1},
-       {0x00002000, 0x00002000, -1, -1},
-       {0x00004000, 0x00002000, -1, -1},
-       {0x00006000, 0x00002000, -1, -1},
-       {0x00008000, 0x00008000, -1, -1},
-       {0x00010000, 0x00008000, -1, -1},
-       {0x00018000, 0x00008000, -1, -1},
-       {0x00020000, 0x00008000, -1, -1},
-       {0x00028000, 0x00008000, -1, -1},
-       {0x00030000, 0x00008000, -1, -1},
-       {0x00038000, 0x00002000, -1, -1},
-       {0x0003A000, 0x00002000, -1, -1},
-       {0x0003C000, 0x00002000, -1, -1},
-       {0x0003E000, 0x00002000, -1, -1},
-};
-
-#define TMS470R1A256_NUM_SECTORS \
-       ARRAY_SIZE(TMS470R1A256_SECTORS)
-
-const struct flash_sector TMS470R1A288_BANK0_SECTORS[] = {
-       {0x00000000, 0x00002000, -1, -1},
-       {0x00002000, 0x00002000, -1, -1},
-       {0x00004000, 0x00002000, -1, -1},
-       {0x00006000, 0x00002000, -1, -1},
-};
-
-#define TMS470R1A288_BANK0_NUM_SECTORS \
-       ARRAY_SIZE(TMS470R1A288_BANK0_SECTORS)
-
-const struct flash_sector TMS470R1A288_BANK1_SECTORS[] = {
-       {0x00040000, 0x00010000, -1, -1},
-       {0x00050000, 0x00010000, -1, -1},
-       {0x00060000, 0x00010000, -1, -1},
-       {0x00070000, 0x00010000, -1, -1},
-};
-
-#define TMS470R1A288_BANK1_NUM_SECTORS \
-       ARRAY_SIZE(TMS470R1A288_BANK1_SECTORS)
-
-const struct flash_sector TMS470R1A384_BANK0_SECTORS[] = {
-       {0x00000000, 0x00002000, -1, -1},
-       {0x00002000, 0x00002000, -1, -1},
-       {0x00004000, 0x00004000, -1, -1},
-       {0x00008000, 0x00004000, -1, -1},
-       {0x0000C000, 0x00004000, -1, -1},
-       {0x00010000, 0x00004000, -1, -1},
-       {0x00014000, 0x00004000, -1, -1},
-       {0x00018000, 0x00002000, -1, -1},
-       {0x0001C000, 0x00002000, -1, -1},
-       {0x0001E000, 0x00002000, -1, -1},
-};
-
-#define TMS470R1A384_BANK0_NUM_SECTORS \
-       ARRAY_SIZE(TMS470R1A384_BANK0_SECTORS)
-
-const struct flash_sector TMS470R1A384_BANK1_SECTORS[] = {
-       {0x00020000, 0x00008000, -1, -1},
-       {0x00028000, 0x00008000, -1, -1},
-       {0x00030000, 0x00008000, -1, -1},
-       {0x00038000, 0x00008000, -1, -1},
-};
-
-#define TMS470R1A384_BANK1_NUM_SECTORS \
-       ARRAY_SIZE(TMS470R1A384_BANK1_SECTORS)
-
-const struct flash_sector TMS470R1A384_BANK2_SECTORS[] = {
-       {0x00040000, 0x00008000, -1, -1},
-       {0x00048000, 0x00008000, -1, -1},
-       {0x00050000, 0x00008000, -1, -1},
-       {0x00058000, 0x00008000, -1, -1},
-};
-
-#define TMS470R1A384_BANK2_NUM_SECTORS \
-       ARRAY_SIZE(TMS470R1A384_BANK2_SECTORS)
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_read_part_info(struct flash_bank *bank)
-{
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t device_ident_reg;
-       uint32_t silicon_version;
-       uint32_t technology_family;
-       uint32_t rom_flash;
-       uint32_t part_number;
-       char *part_name;
-
-       /* we shall not rely on the caller in this test, this function allocates memory,
-          thus and executing the code more than once may cause memory leak */
-       if (tms470_info->device_ident_reg)
-         return ERROR_OK;
-
-       /* read and parse the device identification register */
-       target_read_u32(target, 0xFFFFFFF0, &device_ident_reg);
-
-       LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg);
-
-       if ((device_ident_reg & 7) == 0)
-       {
-               LOG_WARNING("Cannot identify target as a TMS470 family.");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       silicon_version = (device_ident_reg >> 12) & 0xF;
-       technology_family = (device_ident_reg >> 11) & 1;
-       rom_flash = (device_ident_reg >> 10) & 1;
-       part_number = (device_ident_reg >> 3) & 0x7f;
-
-       /*
-        * If the part number is known, determine if the flash bank is valid
-        * based on the base address being within the known flash bank
-        * ranges.  Then fixup/complete the remaining fields of the flash
-        * bank structure.
-        */
-       switch (part_number)
-       {
-       case 0x0a:
-               part_name = "TMS470R1A256";
-
-               if (bank->base >= 0x00040000)
-               {
-                       LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               tms470_info->ordinal = 0;
-               bank->base = 0x00000000;
-               bank->size = 256 * 1024;
-               bank->num_sectors = TMS470R1A256_NUM_SECTORS;
-               bank->sectors = malloc(sizeof(TMS470R1A256_SECTORS));
-               if (!bank->sectors)
-               {
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               (void)memcpy(bank->sectors, TMS470R1A256_SECTORS, sizeof(TMS470R1A256_SECTORS));
-               break;
-
-       case 0x2b:
-               part_name = "TMS470R1A288";
-
-               if (bank->base < 0x00008000)
-               {
-                       tms470_info->ordinal = 0;
-                       bank->base = 0x00000000;
-                       bank->size = 32 * 1024;
-                       bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS;
-                       bank->sectors = malloc(sizeof(TMS470R1A288_BANK0_SECTORS));
-                       if (!bank->sectors)
-                       {
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-                       (void)memcpy(bank->sectors, TMS470R1A288_BANK0_SECTORS, sizeof(TMS470R1A288_BANK0_SECTORS));
-               }
-               else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000))
-               {
-                       tms470_info->ordinal = 1;
-                       bank->base = 0x00040000;
-                       bank->size = 256 * 1024;
-                       bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS;
-                       bank->sectors = malloc(sizeof(TMS470R1A288_BANK1_SECTORS));
-                       if (!bank->sectors)
-                       {
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-                       (void)memcpy(bank->sectors, TMS470R1A288_BANK1_SECTORS, sizeof(TMS470R1A288_BANK1_SECTORS));
-               }
-               else
-               {
-                       LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               break;
-
-       case 0x2d:
-               part_name = "TMS470R1A384";
-
-               if (bank->base < 0x00020000)
-               {
-                       tms470_info->ordinal = 0;
-                       bank->base = 0x00000000;
-                       bank->size = 128 * 1024;
-                       bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS;
-                       bank->sectors = malloc(sizeof(TMS470R1A384_BANK0_SECTORS));
-                       if (!bank->sectors)
-                       {
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-                       (void)memcpy(bank->sectors, TMS470R1A384_BANK0_SECTORS, sizeof(TMS470R1A384_BANK0_SECTORS));
-               }
-               else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000))
-               {
-                       tms470_info->ordinal = 1;
-                       bank->base = 0x00020000;
-                       bank->size = 128 * 1024;
-                       bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS;
-                       bank->sectors = malloc(sizeof(TMS470R1A384_BANK1_SECTORS));
-                       if (!bank->sectors)
-                       {
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-                       (void)memcpy(bank->sectors, TMS470R1A384_BANK1_SECTORS, sizeof(TMS470R1A384_BANK1_SECTORS));
-               }
-               else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000))
-               {
-                       tms470_info->ordinal = 2;
-                       bank->base = 0x00040000;
-                       bank->size = 128 * 1024;
-                       bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS;
-                       bank->sectors = malloc(sizeof(TMS470R1A384_BANK2_SECTORS));
-                       if (!bank->sectors)
-                       {
-                               return ERROR_FLASH_OPERATION_FAILED;
-                       }
-                       (void)memcpy(bank->sectors, TMS470R1A384_BANK2_SECTORS, sizeof(TMS470R1A384_BANK2_SECTORS));
-               }
-               else
-               {
-                       LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
-               break;
-
-       default:
-               LOG_WARNING("Could not identify part 0x%02x as a member of the TMS470 family.", (unsigned)part_number);
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       /* turn off memory selects */
-       target_write_u32(target, 0xFFFFFFE4, 0x00000000);
-       target_write_u32(target, 0xFFFFFFE0, 0x00000000);
-
-       bank->chip_width = 32;
-       bank->bus_width = 32;
-
-       LOG_INFO("Identified %s, ver=%d, core=%s, nvmem=%s.",
-                part_name,
-                (int)(silicon_version),
-                (technology_family ? "1.8v" : "3.3v"),
-                (rom_flash ? "rom" : "flash"));
-
-       tms470_info->device_ident_reg = device_ident_reg;
-       tms470_info->silicon_version = silicon_version;
-       tms470_info->technology_family = technology_family;
-       tms470_info->rom_flash = rom_flash;
-       tms470_info->part_number = part_number;
-       tms470_info->part_name = part_name;
-
-       /*
-        * Disable reset on address access violation.
-        */
-       target_write_u32(target, 0xFFFFFFE0, 0x00004007);
-
-       return ERROR_OK;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static uint32_t keysSet = 0;
-static uint32_t flashKeys[4];
-
-COMMAND_HANDLER(tms470_handle_flash_keyset_command)
-{
-       if (CMD_ARGC > 4)
-       {
-               command_print(CMD_CTX, "tms470 flash_keyset <key0> <key1> <key2> <key3>");
-               return ERROR_INVALID_ARGUMENTS;
-       }
-       else if (CMD_ARGC == 4)
-       {
-               int i;
-
-               for (i = 0; i < 4; i++)
-               {
-                       int start = (0 == strncmp(CMD_ARGV[i], "0x", 2)) ? 2 : 0;
-
-                       if (1 != sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flashKeys[i]))
-                       {
-                               command_print(CMD_CTX, "could not process flash key %s", CMD_ARGV[i]);
-                               LOG_ERROR("could not process flash key %s", CMD_ARGV[i]);
-                               return ERROR_INVALID_ARGUMENTS;
-                       }
-               }
-
-               keysSet = 1;
-       }
-       else if (CMD_ARGC != 0)
-       {
-               command_print(CMD_CTX, "tms470 flash_keyset <key0> <key1> <key2> <key3>");
-               return ERROR_INVALID_ARGUMENTS;
-       }
-
-       if (keysSet)
-       {
-               command_print(CMD_CTX, "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "",
-                             flashKeys[0], flashKeys[1], flashKeys[2], flashKeys[3]);
-       }
-       else
-       {
-               command_print(CMD_CTX, "flash keys not set");
-       }
-
-       return ERROR_OK;
-}
-
-static const uint32_t FLASH_KEYS_ALL_ONES[] = { 0xFFFFFFFF, 0xFFFFFFFF,
-       0xFFFFFFFF, 0xFFFFFFFF,
-};
-
-static const uint32_t FLASH_KEYS_ALL_ZEROS[] = { 0x00000000, 0x00000000,
-       0x00000000, 0x00000000,
-};
-
-static const uint32_t FLASH_KEYS_MIX1[] = { 0xf0fff0ff, 0xf0fff0ff,
-       0xf0fff0ff, 0xf0fff0ff
-};
-
-static const uint32_t FLASH_KEYS_MIX2[] = { 0x0000ffff, 0x0000ffff,
-       0x0000ffff, 0x0000ffff
-};
-
-/* ---------------------------------------------------------------------- */
-
-static int oscMHz = 12;
-
-COMMAND_HANDLER(tms470_handle_osc_megahertz_command)
-{
-       if (CMD_ARGC > 1)
-       {
-               command_print(CMD_CTX, "tms470 osc_megahertz <MHz>");
-               return ERROR_INVALID_ARGUMENTS;
-       }
-       else if (CMD_ARGC == 1)
-       {
-               sscanf(CMD_ARGV[0], "%d", &oscMHz);
-       }
-
-       if (oscMHz <= 0)
-       {
-               LOG_ERROR("osc_megahertz must be positive and non-zero!");
-               command_print(CMD_CTX, "osc_megahertz must be positive and non-zero!");
-               oscMHz = 12;
-               return ERROR_INVALID_ARGUMENTS;
-       }
-
-       command_print(CMD_CTX, "osc_megahertz=%d", oscMHz);
-
-       return ERROR_OK;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int plldis = 0;
-
-COMMAND_HANDLER(tms470_handle_plldis_command)
-{
-       if (CMD_ARGC > 1)
-       {
-               command_print(CMD_CTX, "tms470 plldis <0 | 1>");
-               return ERROR_INVALID_ARGUMENTS;
-       }
-       else if (CMD_ARGC == 1)
-       {
-               sscanf(CMD_ARGV[0], "%d", &plldis);
-               plldis = plldis ? 1 : 0;
-       }
-
-       command_print(CMD_CTX, "plldis=%d", plldis);
-
-       return ERROR_OK;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_check_flash_unlocked(struct target * target)
-{
-       uint32_t fmbbusy;
-
-       target_read_u32(target, 0xFFE89C08, &fmbbusy);
-       LOG_INFO("tms470 fmbbusy = 0x%08" PRIx32 " -> %s", fmbbusy, fmbbusy & 0x8000 ? "unlocked" : "LOCKED");
-       return fmbbusy & 0x8000 ? ERROR_OK : ERROR_FLASH_OPERATION_FAILED;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_try_flash_keys(struct target * target, const uint32_t * key_set)
-{
-       uint32_t glbctrl, fmmstat;
-       int retval = ERROR_FLASH_OPERATION_FAILED;
-
-       /* set GLBCTRL.4  */
-       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
-
-       /* only perform the key match when 3VSTAT is clear */
-       target_read_u32(target, 0xFFE8BC0C, &fmmstat);
-       if (!(fmmstat & 0x08))
-       {
-               unsigned i;
-               uint32_t fmbptr, fmbac2, orig_fmregopt;
-
-               target_write_u32(target, 0xFFE8BC04, fmmstat & ~0x07);
-
-               /* wait for pump ready */
-               do
-               {
-                       target_read_u32(target, 0xFFE8A814, &fmbptr);
-                       alive_sleep(1);
-               }
-               while (!(fmbptr & 0x0200));
-
-               /* force max wait states */
-               target_read_u32(target, 0xFFE88004, &fmbac2);
-               target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
-
-               /* save current access mode, force normal read mode */
-               target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
-               target_write_u32(target, 0xFFE89C00, 0x00);
-
-               for (i = 0; i < 4; i++)
-               {
-                       uint32_t tmp;
-
-                       /* There is no point displaying the value of tmp, it is
-                        * filtered by the chip.  The purpose of this read is to
-                        * prime the unlocking logic rather than read out the value.
-                        */
-                       target_read_u32(target, 0x00001FF0 + 4 * i, &tmp);
-
-                       LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]);
-                       target_write_u32(target, 0xFFE89C0C, key_set[i]);
-               }
-
-               if (ERROR_OK == tms470_check_flash_unlocked(target))
-               {
-                       /*
-                        * There seems to be a side-effect of reading the FMPKEY
-                        * register in that it re-enables the protection.  So we
-                        * re-enable it.
-                        */
-                       for (i = 0; i < 4; i++)
-                       {
-                               uint32_t tmp;
-
-                               target_read_u32(target, 0x00001FF0 + 4 * i, &tmp);
-                               target_write_u32(target, 0xFFE89C0C, key_set[i]);
-                       }
-                       retval = ERROR_OK;
-               }
-
-               /* restore settings */
-               target_write_u32(target, 0xFFE89C00, orig_fmregopt);
-               target_write_u32(target, 0xFFE88004, fmbac2);
-       }
-
-       /* clear config bit */
-       target_write_u32(target, 0xFFFFFFDC, glbctrl);
-
-       return retval;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_unlock_flash(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       const uint32_t *p_key_sets[5];
-       unsigned i, key_set_count;
-
-       if (keysSet)
-       {
-               key_set_count = 5;
-               p_key_sets[0] = flashKeys;
-               p_key_sets[1] = FLASH_KEYS_ALL_ONES;
-               p_key_sets[2] = FLASH_KEYS_ALL_ZEROS;
-               p_key_sets[3] = FLASH_KEYS_MIX1;
-               p_key_sets[4] = FLASH_KEYS_MIX2;
-       }
-       else
-       {
-               key_set_count = 4;
-               p_key_sets[0] = FLASH_KEYS_ALL_ONES;
-               p_key_sets[1] = FLASH_KEYS_ALL_ZEROS;
-               p_key_sets[2] = FLASH_KEYS_MIX1;
-               p_key_sets[3] = FLASH_KEYS_MIX2;
-       }
-
-       for (i = 0; i < key_set_count; i++)
-       {
-               if (tms470_try_flash_keys(target, p_key_sets[i]) == ERROR_OK)
-               {
-                       LOG_INFO("tms470 flash is unlocked");
-                       return ERROR_OK;
-               }
-       }
-
-       LOG_WARNING("tms470 could not unlock flash memory protection level 2");
-       return ERROR_FLASH_OPERATION_FAILED;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_flash_initialize_internal_state_machine(struct flash_bank *bank)
-{
-       uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk;
-       struct target *target = bank->target;
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-       int result = ERROR_OK;
-
-       /*
-        * Select the desired bank to be programmed by writing BANK[2:0] of
-        * FMMAC2.
-        */
-       target_read_u32(target, 0xFFE8BC04, &fmmac2);
-       fmmac2 &= ~0x0007;
-       fmmac2 |= (tms470_info->ordinal & 7);
-       target_write_u32(target, 0xFFE8BC04, fmmac2);
-       LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2);
-
-       /*
-        * Disable level 1 sector protection by setting bit 15 of FMMAC1.
-        */
-       target_read_u32(target, 0xFFE8BC00, &fmmac1);
-       fmmac1 |= 0x8000;
-       target_write_u32(target, 0xFFE8BC00, fmmac1);
-       LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1);
-
-       /*
-        * FMTCREG = 0x2fc0;
-        */
-       target_write_u32(target, 0xFFE8BC10, 0x2fc0);
-       LOG_DEBUG("set fmtcreg = 0x2fc0");
-
-       /*
-        * MAXPP = 50
-        */
-       target_write_u32(target, 0xFFE8A07C, 50);
-       LOG_DEBUG("set fmmaxpp = 50");
-
-       /*
-        * MAXCP = 0xf000 + 2000
-        */
-       target_write_u32(target, 0xFFE8A084, 0xf000 + 2000);
-       LOG_DEBUG("set fmmaxcp = 0x%04x", 0xf000 + 2000);
-
-       /*
-        * configure VHV
-        */
-       target_read_u32(target, 0xFFE8A080, &fmmaxep);
-       if (fmmaxep == 0xf000)
-       {
-               fmmaxep = 0xf000 + 4095;
-               target_write_u32(target, 0xFFE8A80C, 0x9964);
-               LOG_DEBUG("set fmptr3 = 0x9964");
-       }
-       else
-       {
-               fmmaxep = 0xa000 + 4095;
-               target_write_u32(target, 0xFFE8A80C, 0x9b64);
-               LOG_DEBUG("set fmptr3 = 0x9b64");
-       }
-       target_write_u32(target, 0xFFE8A080, fmmaxep);
-       LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep);
-
-       /*
-        * FMPTR4 = 0xa000
-        */
-       target_write_u32(target, 0xFFE8A810, 0xa000);
-       LOG_DEBUG("set fmptr4 = 0xa000");
-
-       /*
-        * FMPESETUP, delay parameter selected based on clock frequency.
-        *
-        * According to the TI App Note SPNU257 and flashing code, delay is
-        * int((sysclk(MHz) + 1) / 2), with a minimum of 5.  The system
-        * clock is usually derived from the ZPLL module, and selected by
-        * the plldis global.
-        */
-       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
-       sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * oscMHz / (1 + (glbctrl & 7));
-       delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5;
-       target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8));
-       LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8));
-
-       /*
-        * FMPVEVACCESS, based on delay.
-        */
-       k = delay | (delay << 8);
-       target_write_u32(target, 0xFFE8A05C, k);
-       LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k);
-
-       /*
-        * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay.
-        */
-       k <<= 1;
-       target_write_u32(target, 0xFFE8A034, k);
-       LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k);
-       target_write_u32(target, 0xFFE8A040, k);
-       LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k);
-       target_write_u32(target, 0xFFE8A024, k);
-       LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k);
-
-       /*
-        * FMCVACCESS, based on delay.
-        */
-       k = delay * 16;
-       target_write_u32(target, 0xFFE8A060, k);
-       LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k);
-
-       /*
-        * FMCSETUP, based on delay.
-        */
-       k = 0x3000 | delay * 20;
-       target_write_u32(target, 0xFFE8A020, k);
-       LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k);
-
-       /*
-        * FMEHOLD, based on delay.
-        */
-       k = (delay * 20) << 2;
-       target_write_u32(target, 0xFFE8A038, k);
-       LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k);
-
-       /*
-        * PWIDTH, CWIDTH, EWIDTH, based on delay.
-        */
-       target_write_u32(target, 0xFFE8A050, delay * 8);
-       LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8);
-       target_write_u32(target, 0xFFE8A058, delay * 1000);
-       LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000);
-       target_write_u32(target, 0xFFE8A054, delay * 5400);
-       LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400);
-
-       return result;
-}
-
-/* ---------------------------------------------------------------------- */
-
-int tms470_flash_status(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       int result = ERROR_OK;
-       uint32_t fmmstat;
-
-       target_read_u32(target, 0xFFE8BC0C, &fmmstat);
-       LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat);
-
-       if (fmmstat & 0x0080)
-       {
-               LOG_WARNING("tms470 flash command: erase still active after busy clear.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (fmmstat & 0x0040)
-       {
-               LOG_WARNING("tms470 flash command: program still active after busy clear.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (fmmstat & 0x0020)
-       {
-               LOG_WARNING("tms470 flash command: invalid data command.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (fmmstat & 0x0010)
-       {
-               LOG_WARNING("tms470 flash command: program, erase or validate sector failed.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (fmmstat & 0x0008)
-       {
-               LOG_WARNING("tms470 flash command: voltage instability detected.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (fmmstat & 0x0006)
-       {
-               LOG_WARNING("tms470 flash command: command suspend detected.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       if (fmmstat & 0x0001)
-       {
-               LOG_WARNING("tms470 flash command: sector was locked.");
-               result = ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return result;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_erase_sector(struct flash_bank *bank, int sector)
-{
-       uint32_t glbctrl, orig_fmregopt, fmbsea, fmbseb, fmmstat;
-       struct target *target = bank->target;
-       uint32_t flashAddr = bank->base + bank->sectors[sector].offset;
-       int result = ERROR_OK;
-
-       /*
-        * Set the bit GLBCTRL4 of the GLBCTRL register (in the System
-        * module) to enable writing to the flash registers }.
-        */
-       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
-       LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10);
-
-       /* Force normal read mode. */
-       target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
-       target_write_u32(target, 0xFFE89C00, 0);
-       LOG_DEBUG("set fmregopt = 0x%08x", 0);
-
-       (void)tms470_flash_initialize_internal_state_machine(bank);
-
-       /*
-        * Select one or more bits in FMBSEA or FMBSEB to disable Level 1
-        * protection for the particular sector to be erased/written.
-        */
-       if (sector < 16)
-       {
-               target_read_u32(target, 0xFFE88008, &fmbsea);
-               target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector));
-               LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector));
-       }
-       else
-       {
-               target_read_u32(target, 0xFFE8800C, &fmbseb);
-               target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16)));
-               LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16)));
-       }
-       bank->sectors[sector].is_protected = 0;
-
-       /*
-        * clear status regiser, sent erase command, kickoff erase
-        */
-       target_write_u16(target, flashAddr, 0x0040);
-       LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flashAddr);
-       target_write_u16(target, flashAddr, 0x0020);
-       LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flashAddr);
-       target_write_u16(target, flashAddr, 0xffff);
-       LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flashAddr);
-
-       /*
-        * Monitor FMMSTAT, busy until clear, then check and other flags for
-        * ultimate result of the operation.
-        */
-       do
-       {
-               target_read_u32(target, 0xFFE8BC0C, &fmmstat);
-               if (fmmstat & 0x0100)
-               {
-                       alive_sleep(1);
-               }
-       }
-       while (fmmstat & 0x0100);
-
-       result = tms470_flash_status(bank);
-
-       if (sector < 16)
-       {
-               target_write_u32(target, 0xFFE88008, fmbsea);
-               LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea);
-               bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1;
-       }
-       else
-       {
-               target_write_u32(target, 0xFFE8800C, fmbseb);
-               LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb);
-               bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1;
-       }
-       target_write_u32(target, 0xFFE89C00, orig_fmregopt);
-       LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl);
-       LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl);
-
-       if (result == ERROR_OK)
-       {
-               bank->sectors[sector].is_erased = 1;
-       }
-
-       return result;
-}
-
-/* ----------------------------------------------------------------------
-              Implementation of Flash Driver Interfaces
-   ---------------------------------------------------------------------- */
-
-static const struct command_registration tms470_any_command_handlers[] = {
-       {
-               .name = "flash_keyset",
-               .handler = &tms470_handle_flash_keyset_command,
-               .mode = COMMAND_ANY,
-               .help = "tms470 flash_keyset <key0> <key1> <key2> <key3>",
-       },
-       {
-               .name = "osc_megahertz",
-               .handler = &tms470_handle_osc_megahertz_command,
-               .mode = COMMAND_ANY,
-               .help = "tms470 osc_megahertz <MHz>",
-       },
-       {
-               .name = "plldis",
-               .handler = &tms470_handle_plldis_command,
-               .mode = COMMAND_ANY,
-               .help = "tms470 plldis <0/1>",
-       },
-       COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration tms470_command_handlers[] = {
-       {
-               .name = "tms470",
-               .mode = COMMAND_ANY,
-               .help = "TI tms470 flash command group",
-               .chain = tms470_any_command_handlers,
-       },
-       COMMAND_REGISTRATION_DONE
-};
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_erase(struct flash_bank *bank, int first, int last)
-{
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-       int sector, result = ERROR_OK;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       tms470_read_part_info(bank);
-
-       if ((first < 0) || (first >= bank->num_sectors) || (last < 0) || (last >= bank->num_sectors) || (first > last))
-       {
-               LOG_ERROR("Sector range %d to %d invalid.", first, last);
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       result = tms470_unlock_flash(bank);
-       if (result != ERROR_OK)
-       {
-               return result;
-       }
-
-       for (sector = first; sector <= last; sector++)
-       {
-               LOG_INFO("Erasing tms470 bank %d sector %d...", tms470_info->ordinal, sector);
-
-               result = tms470_erase_sector(bank, sector);
-
-               if (result != ERROR_OK)
-               {
-                       LOG_ERROR("tms470 could not erase flash sector.");
-                       break;
-               }
-               else
-               {
-                       LOG_INFO("sector erased successfully.");
-               }
-       }
-
-       return result;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-       struct target *target = bank->target;
-       uint32_t fmmac2, fmbsea, fmbseb;
-       int sector;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       tms470_read_part_info(bank);
-
-       if ((first < 0) || (first >= bank->num_sectors) || (last < 0) || (last >= bank->num_sectors) || (first > last))
-       {
-               LOG_ERROR("Sector range %d to %d invalid.", first, last);
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-
-       /* enable the appropriate bank */
-       target_read_u32(target, 0xFFE8BC04, &fmmac2);
-       target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
-
-       /* get the original sector proection flags for this bank */
-       target_read_u32(target, 0xFFE88008, &fmbsea);
-       target_read_u32(target, 0xFFE8800C, &fmbseb);
-
-       for (sector = 0; sector < bank->num_sectors; sector++)
-       {
-               if (sector < 16)
-               {
-                       fmbsea = set ? fmbsea & ~(1 << sector) : fmbsea | (1 << sector);
-                       bank->sectors[sector].is_protected = set ? 1 : 0;
-               }
-               else
-               {
-                       fmbseb = set ? fmbseb & ~(1 << (sector - 16)) : fmbseb | (1 << (sector - 16));
-                       bank->sectors[sector].is_protected = set ? 1 : 0;
-               }
-       }
-
-       /* update the protection bits */
-       target_write_u32(target, 0xFFE88008, fmbsea);
-       target_write_u32(target, 0xFFE8800C, fmbseb);
-
-       return ERROR_OK;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_write(struct flash_bank *bank, uint8_t * buffer, uint32_t offset, uint32_t count)
-{
-       struct target *target = bank->target;
-       uint32_t glbctrl, fmbac2, orig_fmregopt, fmbsea, fmbseb, fmmaxpp, fmmstat;
-       int result = ERROR_OK;
-       uint32_t i;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       tms470_read_part_info(bank);
-
-       LOG_INFO("Writing %" PRId32 " bytes starting at 0x%08" PRIx32 "", count, bank->base + offset);
-
-       /* set GLBCTRL.4  */
-       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
-
-       (void)tms470_flash_initialize_internal_state_machine(bank);
-
-       /* force max wait states */
-       target_read_u32(target, 0xFFE88004, &fmbac2);
-       target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
-
-       /* save current access mode, force normal read mode */
-       target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
-       target_write_u32(target, 0xFFE89C00, 0x00);
-
-       /*
-        * Disable Level 1 protection for all sectors to be erased/written.
-        */
-       target_read_u32(target, 0xFFE88008, &fmbsea);
-       target_write_u32(target, 0xFFE88008, 0xffff);
-       target_read_u32(target, 0xFFE8800C, &fmbseb);
-       target_write_u32(target, 0xFFE8800C, 0xffff);
-
-       /* read MAXPP */
-       target_read_u32(target, 0xFFE8A07C, &fmmaxpp);
-
-       for (i = 0; i < count; i += 2)
-       {
-               uint32_t addr = bank->base + offset + i;
-               uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1];
-
-               if (word != 0xffff)
-               {
-                       LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr);
-
-                       /* clear status register */
-                       target_write_u16(target, addr, 0x0040);
-                       /* program flash command */
-                       target_write_u16(target, addr, 0x0010);
-                       /* burn the 16-bit word (big-endian) */
-                       target_write_u16(target, addr, word);
-
-                       /*
-                        * Monitor FMMSTAT, busy until clear, then check and other flags
-                        * for ultimate result of the operation.
-                        */
-                       do
-                       {
-                               target_read_u32(target, 0xFFE8BC0C, &fmmstat);
-                               if (fmmstat & 0x0100)
-                               {
-                                       alive_sleep(1);
-                               }
-                       }
-                       while (fmmstat & 0x0100);
-
-                       if (fmmstat & 0x3ff)
-                       {
-                               LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat);
-                               LOG_ERROR("Could not program word 0x%04x at address 0x%08" PRIx32 ".", word, addr);
-                               result = ERROR_FLASH_OPERATION_FAILED;
-                               break;
-                       }
-               }
-               else
-               {
-                       LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr);
-               }
-       }
-
-       /* restore */
-       target_write_u32(target, 0xFFE88008, fmbsea);
-       target_write_u32(target, 0xFFE8800C, fmbseb);
-       target_write_u32(target, 0xFFE88004, fmbac2);
-       target_write_u32(target, 0xFFE89C00, orig_fmregopt);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl);
-
-       return result;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_probe(struct flash_bank *bank)
-{
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_WARNING("Cannot communicate... target not halted.");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       return tms470_read_part_info(bank);
-}
-
-static int tms470_auto_probe(struct flash_bank *bank)
-{
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-
-       if (tms470_info->device_ident_reg)
-               return ERROR_OK;
-       return tms470_probe(bank);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_erase_check(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-       int sector, result = ERROR_OK;
-       uint32_t fmmac2, fmbac2, glbctrl, orig_fmregopt;
-       static uint8_t buffer[64 * 1024];
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (!tms470_info->device_ident_reg)
-       {
-               tms470_read_part_info(bank);
-       }
-
-       /* set GLBCTRL.4  */
-       target_read_u32(target, 0xFFFFFFDC, &glbctrl);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
-
-       /* save current access mode, force normal read mode */
-       target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
-       target_write_u32(target, 0xFFE89C00, 0x00);
-
-       /* enable the appropriate bank */
-       target_read_u32(target, 0xFFE8BC04, &fmmac2);
-       target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
-
-       /* TCR = 0 */
-       target_write_u32(target, 0xFFE8BC10, 0x2fc0);
-
-       /* clear TEZ in fmbrdy */
-       target_write_u32(target, 0xFFE88010, 0x0b);
-
-       /* save current wait states, force max */
-       target_read_u32(target, 0xFFE88004, &fmbac2);
-       target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
-
-       /*
-        * The TI primitives inspect the flash memory by reading one 32-bit
-        * word at a time.  Here we read an entire sector and inspect it in
-        * an attempt to reduce the JTAG overhead.
-        */
-       for (sector = 0; sector < bank->num_sectors; sector++)
-       {
-               if (bank->sectors[sector].is_erased != 1)
-               {
-                       uint32_t i, addr = bank->base + bank->sectors[sector].offset;
-
-                       LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
-
-                       target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
-
-                       bank->sectors[sector].is_erased = 1;
-                       for (i = 0; i < bank->sectors[sector].size; i++)
-                       {
-                               if (buffer[i] != 0xff)
-                               {
-                                       LOG_WARNING("tms470 bank %d, sector %d, not erased.", tms470_info->ordinal, sector);
-                                       LOG_WARNING("at location 0x%08" PRIx32 ": flash data is 0x%02x.", addr + i, buffer[i]);
-
-                                       bank->sectors[sector].is_erased = 0;
-                                       break;
-                               }
-                       }
-               }
-               if (bank->sectors[sector].is_erased != 1)
-               {
-                       result = ERROR_FLASH_SECTOR_NOT_ERASED;
-                       break;
-               }
-               else
-               {
-                       LOG_INFO("sector erased");
-               }
-       }
-
-       /* reset TEZ, wait states, read mode, GLBCTRL.4 */
-       target_write_u32(target, 0xFFE88010, 0x0f);
-       target_write_u32(target, 0xFFE88004, fmbac2);
-       target_write_u32(target, 0xFFE89C00, orig_fmregopt);
-       target_write_u32(target, 0xFFFFFFDC, glbctrl);
-
-       return result;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_protect_check(struct flash_bank *bank)
-{
-       struct target *target = bank->target;
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-       int sector, result = ERROR_OK;
-       uint32_t fmmac2, fmbsea, fmbseb;
-
-       if (target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (!tms470_info->device_ident_reg)
-       {
-               tms470_read_part_info(bank);
-       }
-
-       /* enable the appropriate bank */
-       target_read_u32(target, 0xFFE8BC04, &fmmac2);
-       target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
-
-       target_read_u32(target, 0xFFE88008, &fmbsea);
-       target_read_u32(target, 0xFFE8800C, &fmbseb);
-
-       for (sector = 0; sector < bank->num_sectors; sector++)
-       {
-               int protected;
-
-               if (sector < 16)
-               {
-                       protected = fmbsea & (1 << sector) ? 0 : 1;
-                       bank->sectors[sector].is_protected = protected;
-               }
-               else
-               {
-                       protected = fmbseb & (1 << (sector - 16)) ? 0 : 1;
-                       bank->sectors[sector].is_protected = protected;
-               }
-
-               LOG_DEBUG("bank %d sector %d is %s", tms470_info->ordinal, sector, protected ? "protected" : "not protected");
-       }
-
-       return result;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tms470_info(struct flash_bank *bank, char *buf, int buf_size)
-{
-       int used = 0;
-       struct tms470_flash_bank *tms470_info = bank->driver_priv;
-
-       if (!tms470_info->device_ident_reg)
-       {
-               tms470_read_part_info(bank);
-       }
-
-       if (!tms470_info->device_ident_reg)
-       {
-               (void)snprintf(buf, buf_size, "Cannot identify target as a TMS470\n");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       used += snprintf(buf, buf_size, "\ntms470 information: Chip is %s\n", tms470_info->part_name);
-       buf += used;
-       buf_size -= used;
-
-       used += snprintf(buf, buf_size, "Flash protection level 2 is %s\n", tms470_check_flash_unlocked(bank->target) == ERROR_OK ? "disabled" : "enabled");
-       buf += used;
-       buf_size -= used;
-
-       return ERROR_OK;
-}
-
-/* ---------------------------------------------------------------------- */
-
-/*
- * flash bank tms470 <base> <size> <chip_width> <bus_width> <target>
- * [options...]
- */
-
-FLASH_BANK_COMMAND_HANDLER(tms470_flash_bank_command)
-{
-       bank->driver_priv = malloc(sizeof(struct tms470_flash_bank));
-
-       if (!bank->driver_priv)
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       (void)memset(bank->driver_priv, 0, sizeof(struct tms470_flash_bank));
-
-       return ERROR_OK;
-}
-
-struct flash_driver tms470_flash = {
-               .name = "tms470",
-               .commands = tms470_command_handlers,
-               .flash_bank_command = &tms470_flash_bank_command,
-               .erase = &tms470_erase,
-               .protect = &tms470_protect,
-               .write = &tms470_write,
-               .probe = &tms470_probe,
-               .auto_probe = &tms470_auto_probe,
-               .erase_check = &tms470_erase_check,
-               .protect_check = &tms470_protect_check,
-               .info = &tms470_info,
-       };
diff --git a/src/flash/tms470.h b/src/flash/tms470.h
deleted file mode 100644 (file)
index f275e51..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2007,2008 by Christopher Kilgour                        *
- *   techie |_at_| whiterocker |_dot_| com                                 *
- *                                                                         *
- *   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.             *
- ***************************************************************************/
-#ifndef TMS470_DOT_H
-#define TMS470_DOT_H
-
-#include "flash.h"
-
-struct tms470_flash_bank
-{
-       unsigned ordinal;
-
-       /* device identification register */
-       uint32_t device_ident_reg;
-       uint32_t silicon_version;
-       uint32_t technology_family;
-       uint32_t rom_flash;
-       uint32_t part_number;
-       char * part_name;
-
-};
-
-#endif /* TMS470_DOT_H */