dos2unix fix.
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 25 Feb 2008 08:01:21 +0000 (08:01 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 25 Feb 2008 08:01:21 +0000 (08:01 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@339 b42882b7-edfa-0310-969c-e2dbd0fdcd60

13 files changed:
src/flash/at91sam7.c
src/flash/flash.c
src/flash/flash.h
src/flash/lpc2000.c
src/flash/lpc3180_nand_controller.c
src/flash/nand.c
src/flash/stellaris.c
src/flash/stm32x.c
src/flash/str7x.c
src/flash/str9x.c
src/flash/str9xpec.c
src/helper/interpreter.c
src/server/gdb_server.c

index a9776d4..a1f055f 100644 (file)
-/***************************************************************************\r
- *   Copyright (C) 2006 by Magnus Lundin                                   *\r
- *   lundin@mlu.mine.nu                                                    *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
- ***************************************************************************/\r
-\r
-/***************************************************************************\r
-There are some things to notice\r
-\r
-* AT91SAM7S64 is tested\r
-* All AT91SAM7Sxx  and  AT91SAM7Xxx should work but is not tested\r
-* All parameters are identified from onchip configuartion registers \r
-*\r
-* The flash controller handles erases automatically on a page (128/265 byte) basis\r
-* Only an EraseAll command is supported by the controller\r
-* Partial erases can be implemented in software by writing one 0xFFFFFFFF word to \r
-* some location in every page in the region to be erased\r
-*  \r
-* Lock regions (sectors) are 32 or 64 pages\r
-*\r
- ***************************************************************************/\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "replacements.h"\r
-\r
-#include "at91sam7.h"\r
-\r
-#include "flash.h"\r
-#include "target.h"\r
-#include "log.h"\r
-#include "binarybuffer.h"\r
-#include "types.h"\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-\r
-int at91sam7_register_commands(struct command_context_s *cmd_ctx);\r
-int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
-int at91sam7_erase(struct flash_bank_s *bank, int first, int last);\r
-int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);\r
-int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
-int at91sam7_probe(struct flash_bank_s *bank);\r
-int at91sam7_auto_probe(struct flash_bank_s *bank);\r
-int at91sam7_erase_check(struct flash_bank_s *bank);\r
-int at91sam7_protect_check(struct flash_bank_s *bank);\r
-int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
-\r
-u32 at91sam7_get_flash_status(flash_bank_t *bank, u8 flashplane);\r
-void at91sam7_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode);\r
-u32 at91sam7_wait_status_busy(flash_bank_t *bank, u8 flashplane, u32 waitbits, int timeout);\r
-int at91sam7_flash_command(struct flash_bank_s *bank, u8 flashplane, u8 cmd, u16 pagen); \r
-int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-\r
-flash_driver_t at91sam7_flash =\r
-{\r
-       .name = "at91sam7",\r
-       .register_commands = at91sam7_register_commands,\r
-       .flash_bank_command = at91sam7_flash_bank_command,\r
-       .erase = at91sam7_erase,\r
-       .protect = at91sam7_protect,\r
-       .write = at91sam7_write,\r
-       .probe = at91sam7_probe,\r
-       .auto_probe = at91sam7_auto_probe,\r
-       .erase_check = at91sam7_erase_check,\r
-       .protect_check = at91sam7_protect_check,\r
-       .info = at91sam7_info\r
-};\r
-\r
-u32 MC_FMR[4] =        { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };\r
-u32 MC_FCR[4] =        { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };\r
-u32 MC_FSR[4] =        { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };\r
-\r
-char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};\r
-long NVPSIZ[16] = {\r
-   0,\r
-   0x2000, /*  8K */\r
-   0x4000, /* 16K */ \r
-   0x8000, /* 32K */\r
-   -1,\r
-   0x10000, /* 64K */\r
-   -1,\r
-   0x20000, /* 128K */\r
-   -1,\r
-   0x40000, /* 256K */\r
-   0x80000, /* 512K */\r
-   -1,\r
-   0x100000, /* 1024K */\r
-   -1,\r
-   0x200000, /* 2048K */\r
-   -1\r
-};\r
-\r
-long SRAMSIZ[16] = {\r
-   -1,\r
-   0x0400, /*  1K */\r
-   0x0800, /*  2K */ \r
-   -1, \r
-   0x1c000,  /* 112K */\r
-   0x1000,  /*   4K */\r
-   0x14000, /*  80K */\r
-   0x28000, /* 160K */\r
-   0x2000,  /*   8K */\r
-   0x4000,  /*  16K */\r
-   0x8000,  /*  32K */\r
-   0x10000, /*  64K */\r
-   0x20000, /* 128K */\r
-   0x40000, /* 256K */\r
-   0x18000, /* 96K */\r
-   0x80000, /* 512K */\r
-};\r
-\r
-int at91sam7_register_commands(struct command_context_s *cmd_ctx)\r
-{\r
-       command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);\r
-       register_command(cmd_ctx, at91sam7_cmd, "gpnvm", at91sam7_handle_gpnvm_command, COMMAND_EXEC,\r
-                       "at91sam7 gpnvm <num> <bit> set|clear, set or clear at91sam7 gpnvm bit");\r
-\r
-       return ERROR_OK;\r
-}\r
-\r
-u32 at91sam7_get_flash_status(flash_bank_t *bank, u8 flashplane)\r
-{\r
-       target_t *target = bank->target;\r
-       u32 fsr;\r
-       \r
-       target_read_u32(target, MC_FSR[flashplane], &fsr);\r
-       \r
-       return fsr;\r
-}\r
-\r
-/** Read clock configuration and set at91sam7_info->usec_clocks*/ \r
-void at91sam7_read_clock_info(flash_bank_t *bank)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-       u32 mckr, mcfr, pllr;\r
-       unsigned long tmp = 0, mainfreq;\r
-       int flashplane;\r
-\r
-       /* Read main clock freqency register */\r
-       target_read_u32(target, CKGR_MCFR, &mcfr);\r
-       /* Read master clock register */\r
-       target_read_u32(target, PMC_MCKR, &mckr);\r
-       /* Read Clock Generator PLL Register  */\r
-       target_read_u32(target, CKGR_PLLR, &pllr);\r
-\r
-       at91sam7_info->mck_valid = 0;\r
-       switch (mckr & PMC_MCKR_CSS) \r
-       {\r
-               case 0:                 /* Slow Clock */\r
-                       at91sam7_info->mck_valid = 1;\r
-                       mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);\r
-                       tmp = mainfreq;\r
-                       break;\r
-               case 1:                 /* Main Clock */\r
-                       if (mcfr & CKGR_MCFR_MAINRDY) \r
-                       {\r
-                               at91sam7_info->mck_valid = 1;\r
-                               mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);\r
-                               tmp = mainfreq;\r
-                       }\r
-                       break;\r
-\r
-               case 2:                 /* Reserved */\r
-                       break;\r
-               case 3:         /* PLL Clock */\r
-                       if (mcfr & CKGR_MCFR_MAINRDY) \r
-                       {\r
-                               target_read_u32(target, CKGR_PLLR, &pllr);\r
-                               if (!(pllr & CKGR_PLLR_DIV))\r
-                                       break; /* 0 Hz */\r
-                               at91sam7_info->mck_valid = 1;\r
-                               mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);\r
-                               /* Integer arithmetic should have sufficient precision\r
-                                  as long as PLL is properly configured. */\r
-                               tmp = mainfreq / (pllr & CKGR_PLLR_DIV) *\r
-                                 (((pllr & CKGR_PLLR_MUL) >> 16) + 1);\r
-                       }\r
-                       break;\r
-       }\r
-       \r
-       /* Prescaler adjust */\r
-       if (((mckr & PMC_MCKR_PRES) >> 2) == 7)\r
-               at91sam7_info->mck_valid = 0;\r
-       else\r
-               at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);\r
-\r
-       /* Forget old flash timing */\r
-       for (flashplane = 0; flashplane<at91sam7_info->num_planes; flashplane++)\r
-       {\r
-               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_NONE);\r
-       }\r
-}\r
-\r
-/* Setup the timimg registers for nvbits or normal flash */\r
-void at91sam7_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode)\r
-{\r
-       u32 fmr, fmcn = 0, fws = 0;\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-       \r
-       if (mode && (mode != at91sam7_info->flashmode[flashplane]))\r
-       {\r
-               /* Always round up (ceil) */\r
-               if (mode==FMR_TIMING_NVBITS)\r
-               {\r
-                       if (at91sam7_info->cidr_arch == 0x60)\r
-                       {\r
-                               /* AT91SAM7A3 uses master clocks in 100 ns */\r
-                               fmcn = (at91sam7_info->mck_freq/10000000ul)+1;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* master clocks in 1uS for ARCH 0x7 types */\r
-                               fmcn = (at91sam7_info->mck_freq/1000000ul)+1;\r
-                       }\r
-               }\r
-               else if (mode==FMR_TIMING_FLASH)\r
-                       /* main clocks in 1.5uS */\r
-                       fmcn = (at91sam7_info->mck_freq/666666ul)+1;\r
-\r
-               /* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */\r
-               if (at91sam7_info->mck_freq <= 33333ul)\r
-                       fmcn = 0;\r
-               /* Only allow fws=0 if clock frequency is < 30 MHz. */\r
-               if (at91sam7_info->mck_freq > 30000000ul)\r
-                       fws = 1;\r
-\r
-               DEBUG("fmcn[%i]: %i", flashplane, fmcn); \r
-               fmr = fmcn << 16 | fws << 8;\r
-               target_write_u32(target, MC_FMR[flashplane], fmr);\r
-       }\r
-       \r
-       at91sam7_info->flashmode[flashplane] = mode;            \r
-}\r
-\r
-u32 at91sam7_wait_status_busy(flash_bank_t *bank, u8 flashplane, u32 waitbits, int timeout)\r
-{\r
-       u32 status;\r
-       \r
-       while ((!((status = at91sam7_get_flash_status(bank,flashplane)) & waitbits)) && (timeout-- > 0))\r
-       {\r
-               DEBUG("status[%i]: 0x%x", flashplane, status);\r
-               usleep(1000);\r
-       }\r
-       \r
-       DEBUG("status[%i]: 0x%x", flashplane, status);\r
-\r
-       if (status & 0x0C)\r
-       {\r
-               ERROR("status register: 0x%x", status);\r
-               if (status & 0x4)\r
-                       ERROR("Lock Error Bit Detected, Operation Abort");\r
-               if (status & 0x8)\r
-                       ERROR("Invalid command and/or bad keyword, Operation Abort");\r
-               if (status & 0x10)\r
-                       ERROR("Security Bit Set, Operation Abort");\r
-       }\r
-       \r
-       return status;\r
-}\r
-\r
-\r
-/* Send one command to the AT91SAM flash controller */\r
-int at91sam7_flash_command(struct flash_bank_s *bank, u8 flashplane, u8 cmd, u16 pagen) \r
-{\r
-       u32 fcr;\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-\r
-       fcr = (0x5A<<24) | ((pagen&0x3FF)<<8) | cmd; \r
-       target_write_u32(target, MC_FCR[flashplane], fcr);\r
-       DEBUG("Flash command: 0x%x, flashplane: %i, pagenumber:%u", fcr, flashplane, pagen);\r
-\r
-       if ((at91sam7_info->cidr_arch == 0x60)&&((cmd==SLB)|(cmd==CLB)))\r
-       {\r
-               /* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */\r
-               if (at91sam7_wait_status_busy(bank, flashplane, MC_FSR_EOL, 10)&0x0C) \r
-               {\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-               }\r
-               return ERROR_OK;\r
-       }\r
-\r
-       if (at91sam7_wait_status_busy(bank, flashplane, MC_FSR_FRDY, 10)&0x0C) \r
-       {\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       return ERROR_OK;\r
-}\r
-\r
-/* Read device id register, main clock frequency register and fill in driver info structure */\r
-int at91sam7_read_part_info(struct flash_bank_s *bank)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-       u32 cidr, status;\r
-       int sectornum;\r
-       \r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-       \r
-       /* Read and parse chip identification register */\r
-       target_read_u32(target, DBGU_CIDR, &cidr);\r
-       \r
-       if (cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       at91sam7_info->cidr = cidr;\r
-       at91sam7_info->cidr_ext = (cidr>>31)&0x0001;\r
-       at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;\r
-       at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;\r
-       at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;\r
-       at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;\r
-       at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;\r
-       at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;\r
-       at91sam7_info->cidr_version = cidr&0x001F;\r
-       bank->size = NVPSIZ[at91sam7_info->cidr_nvpsiz];\r
-       at91sam7_info->target_name = "Unknown";\r
-\r
-       /* Support just for bulk erase of a single flash plane, whole device if flash size <= 256k */\r
-       if (NVPSIZ[at91sam7_info->cidr_nvpsiz]<0x80000)  /* Flash size less than 512K, one flash plane */\r
-       {\r
-               bank->num_sectors = 1;\r
-               bank->sectors = malloc(sizeof(flash_sector_t));\r
-               bank->sectors[0].offset = 0;\r
-               bank->sectors[0].size = bank->size;\r
-               bank->sectors[0].is_erased = -1;\r
-               bank->sectors[0].is_protected = -1;\r
-       }\r
-       else    /* Flash size 512K or larger, several flash planes */\r
-       {\r
-               bank->num_sectors = NVPSIZ[at91sam7_info->cidr_nvpsiz]/0x40000;\r
-               bank->sectors = malloc(bank->num_sectors*sizeof(flash_sector_t));\r
-               for (sectornum=0; sectornum<bank->num_sectors; sectornum++)\r
-               {\r
-                       bank->sectors[sectornum].offset = sectornum*0x40000;\r
-                       bank->sectors[sectornum].size = 0x40000;\r
-                       bank->sectors[sectornum].is_erased = -1;\r
-                       bank->sectors[sectornum].is_protected = -1;\r
-               }\r
-       }\r
-               \r
-       \r
-\r
-       DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch );\r
-\r
-       /* Read main and master clock freqency register */\r
-       at91sam7_read_clock_info(bank);\r
-       \r
-       at91sam7_info->num_planes = 1;\r
-       status = at91sam7_get_flash_status(bank, 0);\r
-       at91sam7_info->securitybit = (status>>4)&0x01;\r
-       at91sam7_protect_check(bank);   /* TODO Check the protect check */\r
-       \r
-       if (at91sam7_info->cidr_arch == 0x70 )\r
-       {\r
-               at91sam7_info->num_nvmbits = 2;\r
-               at91sam7_info->nvmbits = (status>>8)&0x03;\r
-               bank->base = 0x100000;\r
-               bank->bus_width = 4;\r
-               if (bank->size==0x80000)  /* AT91SAM7S512 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7S512";\r
-                       at91sam7_info->num_planes = 2;\r
-                       if (at91sam7_info->num_planes != bank->num_sectors)\r
-                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;\r
-                       at91sam7_info->num_lockbits = 2*16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 2*16*64;\r
-               }\r
-               if (bank->size==0x40000)  /* AT91SAM7S256 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7S256";\r
-                       at91sam7_info->num_lockbits = 16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 16*64;\r
-               }\r
-               if (bank->size==0x20000)  /* AT91SAM7S128 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7S128";\r
-                       at91sam7_info->num_lockbits = 8;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 8*64;\r
-               }\r
-               if (bank->size==0x10000)  /* AT91SAM7S64 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7S64";\r
-                       at91sam7_info->num_lockbits = 16;\r
-                       at91sam7_info->pagesize = 128;\r
-                       at91sam7_info->pages_in_lockregion = 32;\r
-                       at91sam7_info->num_pages = 16*32;\r
-               }\r
-               if (bank->size==0x08000)  /* AT91SAM7S321/32 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7S321/32";\r
-                       at91sam7_info->num_lockbits = 8;\r
-                       at91sam7_info->pagesize = 128;\r
-                       at91sam7_info->pages_in_lockregion = 32;\r
-                       at91sam7_info->num_pages = 8*32;\r
-               }\r
-               \r
-               return ERROR_OK;\r
-       }\r
-\r
-       if (at91sam7_info->cidr_arch == 0x71 )\r
-       {\r
-               at91sam7_info->num_nvmbits = 3;\r
-               at91sam7_info->nvmbits = (status>>8)&0x07;\r
-               bank->base = 0x100000;\r
-               bank->bus_width = 4;\r
-               if (bank->size==0x80000)  /* AT91SAM7XC512 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7XC512";\r
-                       at91sam7_info->num_planes = 2;\r
-                       if (at91sam7_info->num_planes != bank->num_sectors)\r
-                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;\r
-                       at91sam7_info->num_lockbits = 2*16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 2*16*64;\r
-               }\r
-               if (bank->size==0x40000)  /* AT91SAM7XC256 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7XC256";\r
-                       at91sam7_info->num_lockbits = 16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 16*64;\r
-               }\r
-               if (bank->size==0x20000)  /* AT91SAM7XC128 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7XC128";\r
-                       at91sam7_info->num_lockbits = 8;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 8*64;\r
-               }\r
-               \r
-               return ERROR_OK;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr_arch == 0x72 )\r
-       {\r
-               at91sam7_info->num_nvmbits = 3;\r
-               at91sam7_info->nvmbits = (status>>8)&0x07;\r
-               bank->base = 0x100000;\r
-               bank->bus_width = 4;\r
-               if (bank->size==0x80000) /* AT91SAM7SE512 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7SE512";\r
-                       at91sam7_info->num_planes = 2;\r
-                       if (at91sam7_info->num_planes != bank->num_sectors)\r
-                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;\r
-                       at91sam7_info->num_lockbits = 32;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 32*64;\r
-               }\r
-               if (bank->size==0x40000)\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7SE256";\r
-                       at91sam7_info->num_lockbits = 16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 16*64;\r
-               }\r
-               if (bank->size==0x08000)\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7SE32";\r
-                       at91sam7_info->num_lockbits = 8;\r
-                       at91sam7_info->pagesize = 128;\r
-                       at91sam7_info->pages_in_lockregion = 32;\r
-                       at91sam7_info->num_pages = 8*32;\r
-               }\r
-               \r
-               return ERROR_OK;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr_arch == 0x75 )\r
-       {\r
-               at91sam7_info->num_nvmbits = 3;\r
-               at91sam7_info->nvmbits = (status>>8)&0x07;\r
-               bank->base = 0x100000;\r
-               bank->bus_width = 4;\r
-               if (bank->size==0x80000)  /* AT91SAM7X512 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7X512";\r
-                       at91sam7_info->num_planes = 2;\r
-                       if (at91sam7_info->num_planes != bank->num_sectors)\r
-                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;\r
-                       at91sam7_info->num_lockbits = 32;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 2*16*64;\r
-                       DEBUG("Support for AT91SAM7X512 is experimental in this version!");\r
-               }\r
-               if (bank->size==0x40000)  /* AT91SAM7X256 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7X256";\r
-                       at91sam7_info->num_lockbits = 16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 16*64;\r
-               }\r
-               if (bank->size==0x20000)  /* AT91SAM7X128 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7X128";\r
-                       at91sam7_info->num_lockbits = 8;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 64;\r
-                       at91sam7_info->num_pages = 8*64;\r
-               }\r
-       \r
-               return ERROR_OK;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr_arch == 0x60 )\r
-       {\r
-               at91sam7_info->num_nvmbits = 3;\r
-               at91sam7_info->nvmbits = (status>>8)&0x07;\r
-               bank->base = 0x100000;\r
-               bank->bus_width = 4;\r
-               \r
-               if (bank->size == 0x40000)  /* AT91SAM7A3 */\r
-               {\r
-                       at91sam7_info->target_name = "AT91SAM7A3";\r
-                       at91sam7_info->num_lockbits = 16;\r
-                       at91sam7_info->pagesize = 256;\r
-                       at91sam7_info->pages_in_lockregion = 16;\r
-                       at91sam7_info->num_pages = 16*64;\r
-               }\r
-               return ERROR_OK;\r
-       }\r
-       \r
-   WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");\r
-       \r
-   return ERROR_OK;\r
-}\r
-\r
-int at91sam7_erase_check(struct flash_bank_s *bank)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       \r
-       if (!at91sam7_info->working_area_size)\r
-       {\r
-       }\r
-       else\r
-       {       \r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int at91sam7_protect_check(struct flash_bank_s *bank)\r
-{\r
-       u32 status;\r
-       int flashplane;\r
-       \r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               at91sam7_read_part_info(bank);\r
-       }\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-\r
-       for (flashplane=0;flashplane<at91sam7_info->num_planes;flashplane++)\r
-       {\r
-               status = at91sam7_get_flash_status(bank, flashplane);\r
-               at91sam7_info->lockbits[flashplane] = (status >> 16);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-/* flash_bank at91sam7 0 0 0 0 <target#>\r
- */\r
-int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info;\r
-       int i;\r
-       \r
-       if (argc < 6)\r
-       {\r
-               WARNING("incomplete flash_bank at91sam7 configuration");\r
-               return ERROR_FLASH_BANK_INVALID;\r
-       }\r
-       \r
-       at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));\r
-       bank->driver_priv = at91sam7_info;\r
-       at91sam7_info->probed = 0;\r
-       \r
-       /* part wasn't probed for info yet */\r
-       at91sam7_info->cidr = 0;\r
-       for (i=0;i<4;i++)\r
-               at91sam7_info->flashmode[i]=0;\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int at91sam7_erase(struct flash_bank_s *bank, int first, int last)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       u8 flashplane;\r
-\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               at91sam7_read_part_info(bank);\r
-       }\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }       \r
-       \r
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
-       {\r
-               if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))\r
-               {\r
-                       WARNING("Sector numbers based on lockbit count, probably a deprecated script");\r
-                       last = bank->num_sectors-1;\r
-               }\r
-               else return ERROR_FLASH_SECTOR_INVALID;\r
-       }\r
-\r
-       /* Configure the flash controller timing */\r
-       at91sam7_read_clock_info(bank); \r
-       for (flashplane = first; flashplane<=last; flashplane++)\r
-       {\r
-               /* Configure the flash controller timing */\r
-               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_FLASH);\r
-               if (at91sam7_flash_command(bank, flashplane, EA, 0) != ERROR_OK) \r
-               {\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-               }       \r
-       }\r
-       return ERROR_OK;\r
-\r
-}\r
-\r
-int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)\r
-{\r
-       u32 cmd, pagen;\r
-       u8 flashplane;\r
-       int lockregion;\r
-       \r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       \r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-       \r
-       if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))\r
-       {\r
-               return ERROR_FLASH_SECTOR_INVALID;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               at91sam7_read_part_info(bank);\r
-       }\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       at91sam7_read_clock_info(bank); \r
-       \r
-       for (lockregion=first;lockregion<=last;lockregion++) \r
-       {\r
-               pagen = lockregion*at91sam7_info->pages_in_lockregion;\r
-               flashplane = (pagen>>10)&0x03;\r
-               /* Configure the flash controller timing */\r
-               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_NVBITS);\r
-               \r
-               if (set)\r
-                        cmd = SLB; \r
-               else\r
-                        cmd = CLB;             \r
-\r
-               if (at91sam7_flash_command(bank, flashplane, cmd, pagen) != ERROR_OK) \r
-               {\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-               }       \r
-       }\r
-       \r
-       at91sam7_protect_check(bank);\r
-               \r
-       return ERROR_OK;\r
-}\r
-\r
-\r
-int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-       u32 dst_min_alignment, wcount, bytes_remaining = count;\r
-       u32 first_page, last_page, pagen, buffer_pos;\r
-       u8 flashplane;\r
-       \r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               at91sam7_read_part_info(bank);\r
-       }\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (offset + count > bank->size)\r
-               return ERROR_FLASH_DST_OUT_OF_BANK;\r
-       \r
-       dst_min_alignment = at91sam7_info->pagesize;\r
-\r
-       if (offset % dst_min_alignment)\r
-       {\r
-               WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);\r
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr_arch == 0)\r
-               return ERROR_FLASH_BANK_NOT_PROBED;\r
-\r
-       first_page = offset/dst_min_alignment;\r
-       last_page = CEIL(offset + count, dst_min_alignment);\r
-       \r
-       DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);\r
-       \r
-       at91sam7_read_clock_info(bank); \r
-\r
-       for (pagen=first_page; pagen<last_page; pagen++) \r
-       {\r
-               if (bytes_remaining<dst_min_alignment)\r
-                       count = bytes_remaining;\r
-               else\r
-                       count = dst_min_alignment;\r
-               bytes_remaining -= count;\r
-               \r
-               /* Write one block to the PageWriteBuffer */\r
-               buffer_pos = (pagen-first_page)*dst_min_alignment;\r
-               wcount = CEIL(count,4);\r
-               target->type->write_memory(target, bank->base+pagen*dst_min_alignment, 4, wcount, buffer+buffer_pos);\r
-               flashplane = (pagen>>10)&0x3;\r
-               \r
-               /* Configure the flash controller timing */     \r
-               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_FLASH);\r
-               /* Send Write Page command to Flash Controller */\r
-               if (at91sam7_flash_command(bank, flashplane, WP, pagen) != ERROR_OK) \r
-               {\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-               }\r
-               DEBUG("Write flash plane:%i page number:%i", flashplane, pagen);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-\r
-int at91sam7_probe(struct flash_bank_s *bank)\r
-{\r
-       /* we can't probe on an at91sam7\r
-        * if this is an at91sam7, it has the configured flash\r
-        */\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       at91sam7_info->probed = 0;\r
-       \r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               at91sam7_read_part_info(bank);\r
-       }\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       at91sam7_info->probed = 1;\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-\r
-int at91sam7_auto_probe(struct flash_bank_s *bank)\r
-{\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       if (at91sam7_info->probed)\r
-               return ERROR_OK;\r
-       return at91sam7_probe(bank);\r
-}\r
-\r
-int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
-{\r
-       int printed, flashplane;\r
-       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;\r
-       \r
-       at91sam7_read_part_info(bank);\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");\r
-               buf += printed;\r
-               buf_size -= printed;\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       printed = snprintf(buf, buf_size, "\nat91sam7 information: Chip is %s\n",at91sam7_info->target_name);\r
-       buf += printed;\r
-       buf_size -= printed;\r
-       \r
-       printed = snprintf(buf, buf_size, "cidr: 0x%8.8x, arch: 0x%4.4x, eproc: %s, version:0x%3.3x,  flashsize: 0x%8.8x\n",\r
-                 at91sam7_info->cidr, at91sam7_info->cidr_arch, EPROC[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size);\r
-       buf += printed;\r
-       buf_size -= printed;\r
-                       \r
-       printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz \n", at91sam7_info->mck_freq / 1000);\r
-       buf += printed;\r
-       buf_size -= printed;\r
-       \r
-       if (at91sam7_info->num_planes>1) {              \r
-               printed = snprintf(buf, buf_size, "flashplanes: %i, pagesize: %i, lock regions: %i, pages in lock region: %i \n", \r
-                          at91sam7_info->num_planes, at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->num_pages/at91sam7_info->num_lockbits);\r
-               buf += printed;\r
-               buf_size -= printed;\r
-               for (flashplane=0; flashplane<at91sam7_info->num_planes; flashplane++)\r
-               {\r
-                       printed = snprintf(buf, buf_size, "lockbits[%i]: 0x%4.4x,  ", flashplane, at91sam7_info->lockbits[flashplane]);\r
-                       buf += printed;\r
-                       buf_size -= printed;\r
-               }\r
-       }\r
-       else\r
-       if (at91sam7_info->num_lockbits>0) {            \r
-               printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", \r
-                          at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->lockbits[0], at91sam7_info->num_pages/at91sam7_info->num_lockbits);\r
-               buf += printed;\r
-               buf_size -= printed;\r
-       }\r
-                       \r
-       printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);\r
-       buf += printed;\r
-       buf_size -= printed;\r
-\r
-       return ERROR_OK;\r
-}\r
-\r
-/* \r
-* On AT91SAM7S: When the gpnvm bits are set with \r
-* > at91sam7 gpnvm 0 bitnr set\r
-* the changes are not visible in the flash controller status register MC_FSR \r
-* until the processor has been reset.\r
-* On the Olimex board this requires a power cycle.\r
-* Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3):\r
-*      The maximum number of write/erase cycles for Non Volatile Memory bits is 100. This includes\r
-*      Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.\r
-*/\r
-int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *bank;\r
-       int bit;\r
-       u8  flashcmd;\r
-       u32 status;\r
-       char *value;\r
-       at91sam7_flash_bank_t *at91sam7_info;\r
-\r
-       if (argc < 3)\r
-       {\r
-               command_print(cmd_ctx, "at91sam7 gpnvm <num> <bit> <set|clear>");\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-       bit = atoi(args[1]);\r
-       value = args[2];\r
-\r
-       if (!bank)\r
-       {\r
-               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
-               return ERROR_OK;\r
-       }\r
-\r
-       at91sam7_info = bank->driver_priv;\r
-\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-       \r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               at91sam7_read_part_info(bank);\r
-       }\r
-\r
-       if (at91sam7_info->cidr == 0)\r
-       {\r
-               WARNING("Cannot identify target as an AT91SAM");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-\r
-       if ((bit<0) || (at91sam7_info->num_nvmbits <= bit))\r
-       { \r
-               command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[1],at91sam7_info->target_name);\r
-               return ERROR_OK;\r
-       }\r
-\r
-       if (strcmp(value, "set") == 0)\r
-       {\r
-               flashcmd = SGPB;\r
-       }\r
-       else if (strcmp(value, "clear") == 0)\r
-       {\r
-               flashcmd = CGPB;\r
-       }\r
-       else\r
-       {\r
+/***************************************************************************
+ *   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.             *
+ ***************************************************************************/
+
+/***************************************************************************
+There are some things to notice
+
+* AT91SAM7S64 is tested
+* All AT91SAM7Sxx  and  AT91SAM7Xxx should work but is not tested
+* All parameters are identified from onchip configuartion registers 
+*
+* The flash controller handles erases automatically on a page (128/265 byte) basis
+* Only an EraseAll command is supported by the controller
+* Partial erases can be implemented in software by writing one 0xFFFFFFFF word to 
+* some location in every page in the region to be erased
+*  
+* Lock regions (sectors) are 32 or 64 pages
+*
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "replacements.h"
+
+#include "at91sam7.h"
+
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "binarybuffer.h"
+#include "types.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int at91sam7_register_commands(struct command_context_s *cmd_ctx);
+int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
+int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
+int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int at91sam7_probe(struct flash_bank_s *bank);
+int at91sam7_auto_probe(struct flash_bank_s *bank);
+int at91sam7_erase_check(struct flash_bank_s *bank);
+int at91sam7_protect_check(struct flash_bank_s *bank);
+int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+u32 at91sam7_get_flash_status(flash_bank_t *bank, u8 flashplane);
+void at91sam7_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode);
+u32 at91sam7_wait_status_busy(flash_bank_t *bank, u8 flashplane, u32 waitbits, int timeout);
+int at91sam7_flash_command(struct flash_bank_s *bank, u8 flashplane, u8 cmd, u16 pagen); 
+int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+flash_driver_t at91sam7_flash =
+{
+       .name = "at91sam7",
+       .register_commands = at91sam7_register_commands,
+       .flash_bank_command = at91sam7_flash_bank_command,
+       .erase = at91sam7_erase,
+       .protect = at91sam7_protect,
+       .write = at91sam7_write,
+       .probe = at91sam7_probe,
+       .auto_probe = at91sam7_auto_probe,
+       .erase_check = at91sam7_erase_check,
+       .protect_check = at91sam7_protect_check,
+       .info = at91sam7_info
+};
+
+u32 MC_FMR[4] =        { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
+u32 MC_FCR[4] =        { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
+u32 MC_FSR[4] =        { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
+
+char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
+long NVPSIZ[16] = {
+   0,
+   0x2000, /*  8K */
+   0x4000, /* 16K */ 
+   0x8000, /* 32K */
+   -1,
+   0x10000, /* 64K */
+   -1,
+   0x20000, /* 128K */
+   -1,
+   0x40000, /* 256K */
+   0x80000, /* 512K */
+   -1,
+   0x100000, /* 1024K */
+   -1,
+   0x200000, /* 2048K */
+   -1
+};
+
+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 */
+};
+
+int at91sam7_register_commands(struct command_context_s *cmd_ctx)
+{
+       command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);
+       register_command(cmd_ctx, at91sam7_cmd, "gpnvm", at91sam7_handle_gpnvm_command, COMMAND_EXEC,
+                       "at91sam7 gpnvm <num> <bit> set|clear, set or clear at91sam7 gpnvm bit");
+
+       return ERROR_OK;
+}
+
+u32 at91sam7_get_flash_status(flash_bank_t *bank, u8 flashplane)
+{
+       target_t *target = bank->target;
+       u32 fsr;
+       
+       target_read_u32(target, MC_FSR[flashplane], &fsr);
+       
+       return fsr;
+}
+
+/** Read clock configuration and set at91sam7_info->usec_clocks*/ 
+void at91sam7_read_clock_info(flash_bank_t *bank)
+{
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       target_t *target = bank->target;
+       u32 mckr, mcfr, pllr;
+       unsigned long tmp = 0, mainfreq;
+       int flashplane;
+
+       /* Read main clock freqency 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;
+       switch (mckr & PMC_MCKR_CSS) 
+       {
+               case 0:                 /* Slow Clock */
+                       at91sam7_info->mck_valid = 1;
+                       mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
+                       tmp = mainfreq;
+                       break;
+               case 1:                 /* Main Clock */
+                       if (mcfr & CKGR_MCFR_MAINRDY) 
+                       {
+                               at91sam7_info->mck_valid = 1;
+                               mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
+                               tmp = mainfreq;
+                       }
+                       break;
+
+               case 2:                 /* Reserved */
+                       break;
+               case 3:         /* PLL Clock */
+                       if (mcfr & CKGR_MCFR_MAINRDY) 
+                       {
+                               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);
+                       }
+                       break;
+       }
+       
+       /* Prescaler adjust */
+       if (((mckr & PMC_MCKR_PRES) >> 2) == 7)
+               at91sam7_info->mck_valid = 0;
+       else
+               at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
+
+       /* Forget old flash timing */
+       for (flashplane = 0; flashplane<at91sam7_info->num_planes; flashplane++)
+       {
+               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_NONE);
+       }
+}
+
+/* Setup the timimg registers for nvbits or normal flash */
+void at91sam7_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode)
+{
+       u32 fmr, fmcn = 0, fws = 0;
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       target_t *target = bank->target;
+       
+       if (mode && (mode != at91sam7_info->flashmode[flashplane]))
+       {
+               /* 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/666666ul)+1;
+
+               /* 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;
+
+               DEBUG("fmcn[%i]: %i", flashplane, fmcn); 
+               fmr = fmcn << 16 | fws << 8;
+               target_write_u32(target, MC_FMR[flashplane], fmr);
+       }
+       
+       at91sam7_info->flashmode[flashplane] = mode;            
+}
+
+u32 at91sam7_wait_status_busy(flash_bank_t *bank, u8 flashplane, u32 waitbits, int timeout)
+{
+       u32 status;
+       
+       while ((!((status = at91sam7_get_flash_status(bank,flashplane)) & waitbits)) && (timeout-- > 0))
+       {
+               DEBUG("status[%i]: 0x%x", flashplane, status);
+               usleep(1000);
+       }
+       
+       DEBUG("status[%i]: 0x%x", flashplane, status);
+
+       if (status & 0x0C)
+       {
+               ERROR("status register: 0x%x", status);
+               if (status & 0x4)
+                       ERROR("Lock Error Bit Detected, Operation Abort");
+               if (status & 0x8)
+                       ERROR("Invalid command and/or bad keyword, Operation Abort");
+               if (status & 0x10)
+                       ERROR("Security Bit Set, Operation Abort");
+       }
+       
+       return status;
+}
+
+
+/* Send one command to the AT91SAM flash controller */
+int at91sam7_flash_command(struct flash_bank_s *bank, u8 flashplane, u8 cmd, u16 pagen) 
+{
+       u32 fcr;
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       target_t *target = bank->target;
+
+       fcr = (0x5A<<24) | ((pagen&0x3FF)<<8) | cmd; 
+       target_write_u32(target, MC_FCR[flashplane], fcr);
+       DEBUG("Flash command: 0x%x, flashplane: %i, pagenumber:%u", fcr, flashplane, 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, flashplane, MC_FSR_EOL, 10)&0x0C) 
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               return ERROR_OK;
+       }
+
+       if (at91sam7_wait_status_busy(bank, flashplane, 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 */
+int at91sam7_read_part_info(struct flash_bank_s *bank)
+{
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       target_t *target = bank->target;
+       u32 cidr, status;
+       int sectornum;
+       
+       if (bank->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       /* Read and parse chip identification register */
+       target_read_u32(target, DBGU_CIDR, &cidr);
+       
+       if (cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       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;
+       bank->size = NVPSIZ[at91sam7_info->cidr_nvpsiz];
+       at91sam7_info->target_name = "Unknown";
+
+       /* Support just for bulk erase of a single flash plane, whole device if flash size <= 256k */
+       if (NVPSIZ[at91sam7_info->cidr_nvpsiz]<0x80000)  /* Flash size less than 512K, one flash plane */
+       {
+               bank->num_sectors = 1;
+               bank->sectors = malloc(sizeof(flash_sector_t));
+               bank->sectors[0].offset = 0;
+               bank->sectors[0].size = bank->size;
+               bank->sectors[0].is_erased = -1;
+               bank->sectors[0].is_protected = -1;
+       }
+       else    /* Flash size 512K or larger, several flash planes */
+       {
+               bank->num_sectors = NVPSIZ[at91sam7_info->cidr_nvpsiz]/0x40000;
+               bank->sectors = malloc(bank->num_sectors*sizeof(flash_sector_t));
+               for (sectornum=0; sectornum<bank->num_sectors; sectornum++)
+               {
+                       bank->sectors[sectornum].offset = sectornum*0x40000;
+                       bank->sectors[sectornum].size = 0x40000;
+                       bank->sectors[sectornum].is_erased = -1;
+                       bank->sectors[sectornum].is_protected = -1;
+               }
+       }
+               
+       
+
+       DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch );
+
+       /* Read main and master clock freqency register */
+       at91sam7_read_clock_info(bank);
+       
+       at91sam7_info->num_planes = 1;
+       status = at91sam7_get_flash_status(bank, 0);
+       at91sam7_info->securitybit = (status>>4)&0x01;
+       at91sam7_protect_check(bank);   /* TODO Check the protect check */
+       
+       if (at91sam7_info->cidr_arch == 0x70 )
+       {
+               at91sam7_info->num_nvmbits = 2;
+               at91sam7_info->nvmbits = (status>>8)&0x03;
+               bank->base = 0x100000;
+               bank->bus_width = 4;
+               if (bank->size==0x80000)  /* AT91SAM7S512 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7S512";
+                       at91sam7_info->num_planes = 2;
+                       if (at91sam7_info->num_planes != bank->num_sectors)
+                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
+                       at91sam7_info->num_lockbits = 2*16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 2*16*64;
+               }
+               if (bank->size==0x40000)  /* AT91SAM7S256 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7S256";
+                       at91sam7_info->num_lockbits = 16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 16*64;
+               }
+               if (bank->size==0x20000)  /* AT91SAM7S128 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7S128";
+                       at91sam7_info->num_lockbits = 8;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 8*64;
+               }
+               if (bank->size==0x10000)  /* AT91SAM7S64 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7S64";
+                       at91sam7_info->num_lockbits = 16;
+                       at91sam7_info->pagesize = 128;
+                       at91sam7_info->pages_in_lockregion = 32;
+                       at91sam7_info->num_pages = 16*32;
+               }
+               if (bank->size==0x08000)  /* AT91SAM7S321/32 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7S321/32";
+                       at91sam7_info->num_lockbits = 8;
+                       at91sam7_info->pagesize = 128;
+                       at91sam7_info->pages_in_lockregion = 32;
+                       at91sam7_info->num_pages = 8*32;
+               }
+               
+               return ERROR_OK;
+       }
+
+       if (at91sam7_info->cidr_arch == 0x71 )
+       {
+               at91sam7_info->num_nvmbits = 3;
+               at91sam7_info->nvmbits = (status>>8)&0x07;
+               bank->base = 0x100000;
+               bank->bus_width = 4;
+               if (bank->size==0x80000)  /* AT91SAM7XC512 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7XC512";
+                       at91sam7_info->num_planes = 2;
+                       if (at91sam7_info->num_planes != bank->num_sectors)
+                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
+                       at91sam7_info->num_lockbits = 2*16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 2*16*64;
+               }
+               if (bank->size==0x40000)  /* AT91SAM7XC256 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7XC256";
+                       at91sam7_info->num_lockbits = 16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 16*64;
+               }
+               if (bank->size==0x20000)  /* AT91SAM7XC128 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7XC128";
+                       at91sam7_info->num_lockbits = 8;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 8*64;
+               }
+               
+               return ERROR_OK;
+       }
+       
+       if (at91sam7_info->cidr_arch == 0x72 )
+       {
+               at91sam7_info->num_nvmbits = 3;
+               at91sam7_info->nvmbits = (status>>8)&0x07;
+               bank->base = 0x100000;
+               bank->bus_width = 4;
+               if (bank->size==0x80000) /* AT91SAM7SE512 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7SE512";
+                       at91sam7_info->num_planes = 2;
+                       if (at91sam7_info->num_planes != bank->num_sectors)
+                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
+                       at91sam7_info->num_lockbits = 32;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 32*64;
+               }
+               if (bank->size==0x40000)
+               {
+                       at91sam7_info->target_name = "AT91SAM7SE256";
+                       at91sam7_info->num_lockbits = 16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 16*64;
+               }
+               if (bank->size==0x08000)
+               {
+                       at91sam7_info->target_name = "AT91SAM7SE32";
+                       at91sam7_info->num_lockbits = 8;
+                       at91sam7_info->pagesize = 128;
+                       at91sam7_info->pages_in_lockregion = 32;
+                       at91sam7_info->num_pages = 8*32;
+               }
+               
+               return ERROR_OK;
+       }
+       
+       if (at91sam7_info->cidr_arch == 0x75 )
+       {
+               at91sam7_info->num_nvmbits = 3;
+               at91sam7_info->nvmbits = (status>>8)&0x07;
+               bank->base = 0x100000;
+               bank->bus_width = 4;
+               if (bank->size==0x80000)  /* AT91SAM7X512 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7X512";
+                       at91sam7_info->num_planes = 2;
+                       if (at91sam7_info->num_planes != bank->num_sectors)
+                               WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
+                       at91sam7_info->num_lockbits = 32;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 2*16*64;
+                       DEBUG("Support for AT91SAM7X512 is experimental in this version!");
+               }
+               if (bank->size==0x40000)  /* AT91SAM7X256 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7X256";
+                       at91sam7_info->num_lockbits = 16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 16*64;
+               }
+               if (bank->size==0x20000)  /* AT91SAM7X128 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7X128";
+                       at91sam7_info->num_lockbits = 8;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 64;
+                       at91sam7_info->num_pages = 8*64;
+               }
+       
+               return ERROR_OK;
+       }
+       
+       if (at91sam7_info->cidr_arch == 0x60 )
+       {
+               at91sam7_info->num_nvmbits = 3;
+               at91sam7_info->nvmbits = (status>>8)&0x07;
+               bank->base = 0x100000;
+               bank->bus_width = 4;
+               
+               if (bank->size == 0x40000)  /* AT91SAM7A3 */
+               {
+                       at91sam7_info->target_name = "AT91SAM7A3";
+                       at91sam7_info->num_lockbits = 16;
+                       at91sam7_info->pagesize = 256;
+                       at91sam7_info->pages_in_lockregion = 16;
+                       at91sam7_info->num_pages = 16*64;
+               }
+               return ERROR_OK;
+       }
+       
+   WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
+       
+   return ERROR_OK;
+}
+
+int at91sam7_erase_check(struct flash_bank_s *bank)
+{
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       
+       if (!at91sam7_info->working_area_size)
+       {
+       }
+       else
+       {       
+       }
+       
+       return ERROR_OK;
+}
+
+int at91sam7_protect_check(struct flash_bank_s *bank)
+{
+       u32 status;
+       int flashplane;
+       
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+
+       if (at91sam7_info->cidr == 0)
+       {
+               at91sam7_read_part_info(bank);
+       }
+
+       if (at91sam7_info->cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       for (flashplane=0;flashplane<at91sam7_info->num_planes;flashplane++)
+       {
+               status = at91sam7_get_flash_status(bank, flashplane);
+               at91sam7_info->lockbits[flashplane] = (status >> 16);
+       }
+       
+       return ERROR_OK;
+}
+
+/* flash_bank at91sam7 0 0 0 0 <target#>
+ */
+int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+       at91sam7_flash_bank_t *at91sam7_info;
+       int i;
+       
+       if (argc < 6)
+       {
+               WARNING("incomplete flash_bank at91sam7 configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       
+       at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
+       bank->driver_priv = at91sam7_info;
+       at91sam7_info->probed = 0;
+       
+       /* part wasn't probed for info yet */
+       at91sam7_info->cidr = 0;
+       for (i=0;i<4;i++)
+               at91sam7_info->flashmode[i]=0;
+       
+       return ERROR_OK;
+}
+
+int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
+{
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       u8 flashplane;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (at91sam7_info->cidr == 0)
+       {
+               at91sam7_read_part_info(bank);
+       }
+
+       if (at91sam7_info->cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }       
+       
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))
+               {
+                       WARNING("Sector numbers based on lockbit count, probably a deprecated script");
+                       last = bank->num_sectors-1;
+               }
+               else return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank); 
+       for (flashplane = first; flashplane<=last; flashplane++)
+       {
+               /* Configure the flash controller timing */
+               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_FLASH);
+               if (at91sam7_flash_command(bank, flashplane, EA, 0) != ERROR_OK) 
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }       
+       }
+       return ERROR_OK;
+
+}
+
+int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+       u32 cmd, pagen;
+       u8 flashplane;
+       int lockregion;
+       
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       
+       if (bank->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
+       {
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+       
+       if (at91sam7_info->cidr == 0)
+       {
+               at91sam7_read_part_info(bank);
+       }
+
+       if (at91sam7_info->cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       at91sam7_read_clock_info(bank); 
+       
+       for (lockregion=first;lockregion<=last;lockregion++) 
+       {
+               pagen = lockregion*at91sam7_info->pages_in_lockregion;
+               flashplane = (pagen>>10)&0x03;
+               /* Configure the flash controller timing */
+               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_NVBITS);
+               
+               if (set)
+                        cmd = SLB; 
+               else
+                        cmd = CLB;             
+
+               if (at91sam7_flash_command(bank, flashplane, cmd, pagen) != ERROR_OK) 
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }       
+       }
+       
+       at91sam7_protect_check(bank);
+               
+       return ERROR_OK;
+}
+
+
+int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       target_t *target = bank->target;
+       u32 dst_min_alignment, wcount, bytes_remaining = count;
+       u32 first_page, last_page, pagen, buffer_pos;
+       u8 flashplane;
+       
+       if (at91sam7_info->cidr == 0)
+       {
+               at91sam7_read_part_info(bank);
+       }
+
+       if (at91sam7_info->cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       if (offset + count > bank->size)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+       
+       dst_min_alignment = at91sam7_info->pagesize;
+
+       if (offset % dst_min_alignment)
+       {
+               WARNING("offset 0x%x breaks required alignment 0x%x", 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 = CEIL(offset + count, dst_min_alignment);
+       
+       DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
+       
+       at91sam7_read_clock_info(bank); 
+
+       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 = CEIL(count,4);
+               target->type->write_memory(target, bank->base+pagen*dst_min_alignment, 4, wcount, buffer+buffer_pos);
+               flashplane = (pagen>>10)&0x3;
+               
+               /* Configure the flash controller timing */     
+               at91sam7_set_flash_mode(bank, flashplane, FMR_TIMING_FLASH);
+               /* Send Write Page command to Flash Controller */
+               if (at91sam7_flash_command(bank, flashplane, WP, pagen) != ERROR_OK) 
+               {
+                               return ERROR_FLASH_OPERATION_FAILED;
+               }
+               DEBUG("Write flash plane:%i page number:%i", flashplane, pagen);
+       }
+       
+       return ERROR_OK;
+}
+
+
+int at91sam7_probe(struct flash_bank_s *bank)
+{
+       /* we can't probe on an at91sam7
+        * if this is an at91sam7, it has the configured flash
+        */
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       at91sam7_info->probed = 0;
+       
+       if (at91sam7_info->cidr == 0)
+       {
+               at91sam7_read_part_info(bank);
+       }
+
+       if (at91sam7_info->cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       at91sam7_info->probed = 1;
+       
+       return ERROR_OK;
+}
+
+
+int at91sam7_auto_probe(struct flash_bank_s *bank)
+{
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       if (at91sam7_info->probed)
+               return ERROR_OK;
+       return at91sam7_probe(bank);
+}
+
+int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+       int printed, flashplane;
+       at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+       
+       at91sam7_read_part_info(bank);
+
+       if (at91sam7_info->cidr == 0)
+       {
+               printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");
+               buf += printed;
+               buf_size -= printed;
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       printed = snprintf(buf, buf_size, "\nat91sam7 information: Chip is %s\n",at91sam7_info->target_name);
+       buf += printed;
+       buf_size -= printed;
+       
+       printed = snprintf(buf, buf_size, "cidr: 0x%8.8x, arch: 0x%4.4x, eproc: %s, version:0x%3.3x,  flashsize: 0x%8.8x\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): %ikHz \n", at91sam7_info->mck_freq / 1000);
+       buf += printed;
+       buf_size -= printed;
+       
+       if (at91sam7_info->num_planes>1) {              
+               printed = snprintf(buf, buf_size, "flashplanes: %i, pagesize: %i, lock regions: %i, pages in lock region: %i \n", 
+                          at91sam7_info->num_planes, at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->num_pages/at91sam7_info->num_lockbits);
+               buf += printed;
+               buf_size -= printed;
+               for (flashplane=0; flashplane<at91sam7_info->num_planes; flashplane++)
+               {
+                       printed = snprintf(buf, buf_size, "lockbits[%i]: 0x%4.4x,  ", flashplane, at91sam7_info->lockbits[flashplane]);
+                       buf += printed;
+                       buf_size -= printed;
+               }
+       }
+       else
+       if (at91sam7_info->num_lockbits>0) {            
+               printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", 
+                          at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->lockbits[0], at91sam7_info->num_pages/at91sam7_info->num_lockbits);
+               buf += printed;
+               buf_size -= printed;
+       }
+                       
+       printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);
+       buf += printed;
+       buf_size -= printed;
+
+       return ERROR_OK;
+}
+
+/* 
+* On AT91SAM7S: When the gpnvm bits are set with 
+* > at91sam7 gpnvm 0 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.
+*/
+int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *bank;
+       int bit;
+       u8  flashcmd;
+       u32 status;
+       char *value;
+       at91sam7_flash_bank_t *at91sam7_info;
+
+       if (argc < 3)
+       {
+               command_print(cmd_ctx, "at91sam7 gpnvm <num> <bit> <set|clear>");
+               return ERROR_OK;
+       }
+       
+       bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+       bit = atoi(args[1]);
+       value = args[2];
+
+       if (!bank)
+       {
+               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+               return ERROR_OK;
+       }
+
+       at91sam7_info = bank->driver_priv;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (at91sam7_info->cidr == 0)
+       {
+               at91sam7_read_part_info(bank);
+       }
+
+       if (at91sam7_info->cidr == 0)
+       {
+               WARNING("Cannot identify target as an AT91SAM");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       if ((bit<0) || (at91sam7_info->num_nvmbits <= bit))
+       { 
+               command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[1],at91sam7_info->target_name);
+               return ERROR_OK;
+       }
+
+       if (strcmp(value, "set") == 0)
+       {
+               flashcmd = SGPB;
+       }
+       else if (strcmp(value, "clear") == 0)
+       {
+               flashcmd = CGPB;
+       }
+       else
+       {
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }\r
-\r
-       /* Configure the flash controller timing */\r
-       at91sam7_read_clock_info(bank); \r
-       at91sam7_set_flash_mode(bank, 0, FMR_TIMING_NVBITS);\r
-       \r
-       if (at91sam7_flash_command(bank, 0, flashcmd, (u16)(bit)) != ERROR_OK) \r
-       {\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }       \r
-\r
-       status = at91sam7_get_flash_status(bank, 0);\r
-       DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value 0x%x, status 0x%x \n",flashcmd,bit,status);\r
-       at91sam7_info->nvmbits = (status>>8)&((1<<at91sam7_info->num_nvmbits)-1);\r
-\r
-       return ERROR_OK;\r
-}\r
+       }
+
+       /* Configure the flash controller timing */
+       at91sam7_read_clock_info(bank); 
+       at91sam7_set_flash_mode(bank, 0, FMR_TIMING_NVBITS);
+       
+       if (at91sam7_flash_command(bank, 0, flashcmd, (u16)(bit)) != ERROR_OK) 
+       {
+               return ERROR_FLASH_OPERATION_FAILED;
+       }       
+
+       status = at91sam7_get_flash_status(bank, 0);
+       DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value 0x%x, status 0x%x \n",flashcmd,bit,status);
+       at91sam7_info->nvmbits = (status>>8)&((1<<at91sam7_info->num_nvmbits)-1);
+
+       return ERROR_OK;
+}
index 416cac4..2fefb4c 100644 (file)
-/***************************************************************************\r
- *   Copyright (C) 2005 by Dominic Rath                                    *\r
- *   Dominic.Rath@gmx.de                                                   *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
- ***************************************************************************/\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "flash.h"\r
-#include "command.h"\r
-#include "target.h"\r
-#include "time_support.h"\r
-#include "fileio.h"\r
-#include "image.h"\r
-#include "log.h"\r
-\r
-#include <string.h>\r
-#include <unistd.h>\r
-#include <stdlib.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-#include <errno.h>\r
-#include <inttypes.h>\r
-\r
-/* command handlers */\r
-int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);\r
-\r
-/* flash drivers\r
- */\r
-extern flash_driver_t lpc2000_flash;\r
-extern flash_driver_t cfi_flash;\r
-extern flash_driver_t at91sam7_flash;\r
-extern flash_driver_t str7x_flash;\r
-extern flash_driver_t str9x_flash;\r
-extern flash_driver_t stellaris_flash;\r
-extern flash_driver_t str9xpec_flash;\r
-extern flash_driver_t stm32x_flash;\r
-extern flash_driver_t tms470_flash;\r
-\r
-flash_driver_t *flash_drivers[] =\r
-{\r
-       &lpc2000_flash,\r
-       &cfi_flash,\r
-       &at91sam7_flash,\r
-       &str7x_flash,\r
-       &str9x_flash,\r
-       &stellaris_flash,\r
-       &str9xpec_flash,\r
-       &stm32x_flash,\r
-       &tms470_flash,\r
-       NULL,\r
-};\r
-\r
-flash_bank_t *flash_banks;\r
-static         command_t *flash_cmd;\r
-static int auto_erase = 0;\r
-\r
-/* wafer thin wrapper for invoking the flash driver */\r
-static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
-{\r
-       int retval=ERROR_OK;\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target not halted - aborting flash write");\r
-               retval=ERROR_TARGET_NOT_HALTED;\r
-       } else\r
-       {\r
-               retval=bank->driver->write(bank, buffer, offset, count);\r
-       }\r
-       if (retval!=ERROR_OK)\r
-       {\r
-               ERROR("Writing to flash bank at address 0x%08x at offset 0x%8.8x", bank->base, offset);\r
-       }\r
-       return retval;\r
-}\r
-\r
-static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)\r
-{\r
-       int retval=ERROR_OK;\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target not halted - aborting flash erase");\r
-               retval=ERROR_TARGET_NOT_HALTED;\r
-       } else if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
-       {\r
-               ERROR("invalid flash sector");\r
-               retval=ERROR_FLASH_SECTOR_INVALID;\r
-       } else          \r
-       {\r
-               retval=bank->driver->erase(bank, first, last);\r
-       }\r
-       if (retval!=ERROR_OK)\r
-       {\r
-               ERROR("Failed erasing banks %d to %d", first, last);\r
-       }\r
-       return retval;\r
-}\r
-\r
-int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last)\r
-{\r
-       int retval;\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target not halted - aborting flash erase");\r
-               retval=ERROR_TARGET_NOT_HALTED;\r
-       } else if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
-       {\r
-               ERROR("invalid flash sector");\r
-               retval=ERROR_FLASH_SECTOR_INVALID;\r
-       } else          \r
-       {\r
-               retval=bank->driver->protect(bank, set, first, last);\r
-       }\r
-       if (retval!=ERROR_OK)\r
-       {\r
-               ERROR("Failed protecting banks %d to %d", first, last);\r
-       }\r
-       return retval;\r
-}\r
-\r
-\r
-int flash_register_commands(struct command_context_s *cmd_ctx)\r
-{\r
-       flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);\r
-       \r
-       register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, "flash_bank <driver> <base> <size> <chip_width> <bus_width> <target> [driver_options ...]");\r
-       register_command(cmd_ctx, flash_cmd, "auto_erase", handle_flash_auto_erase_command, COMMAND_ANY,\r
-                                                "auto erase flash sectors <on|off>");\r
-       return ERROR_OK;\r
-}\r
-\r
-int flash_init_drivers(struct command_context_s *cmd_ctx)\r
-{\r
-       if (flash_banks)\r
-       {\r
-               register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,\r
-                                                "list configured flash banks ");\r
-               register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,\r
-                                                "print info about flash bank <num>");\r
-               register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,\r
-                                                "identify flash bank <num>");\r
-               register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,\r
-                                                "check erase state of sectors in flash bank <num>");\r
-               register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,\r
-                                                "check protection state of sectors in flash bank <num>");\r
-               register_command(cmd_ctx, flash_cmd, "erase_sector", handle_flash_erase_command, COMMAND_EXEC,\r
-                                                "erase sectors at <bank> <first> <last>");\r
-               register_command(cmd_ctx, flash_cmd, "erase_address", handle_flash_erase_address_command, COMMAND_EXEC,\r
-                                                "erase address range <address> <length>");\r
-               register_command(cmd_ctx, flash_cmd, "write_bank", handle_flash_write_bank_command, COMMAND_EXEC,\r
-                                                "write binary data to <bank> <file> <offset>");\r
-               register_command(cmd_ctx, flash_cmd, "write_image", handle_flash_write_image_command, COMMAND_EXEC,\r
-                                                "write_image <file> [offset] [type]");\r
-               register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,\r
-                                                "set protection of sectors at <bank> <first> <last> <on|off>");\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-flash_bank_t *get_flash_bank_by_num_noprobe(int num)\r
-{\r
-       flash_bank_t *p;\r
-       int i = 0;\r
-\r
-       for (p = flash_banks; p; p = p->next)\r
-       {\r
-               if (i++ == num)\r
-               {\r
-                       return p;\r
-               }\r
-       }\r
-       ERROR("Flash bank %d does not exist", num);\r
-       return NULL;\r
-}\r
-\r
-flash_bank_t *get_flash_bank_by_num(int num)\r
-{\r
-       flash_bank_t *p = get_flash_bank_by_num_noprobe(num);\r
-       int retval;\r
-       \r
-       if (p == NULL)\r
-               return NULL;\r
-       \r
-       retval = p->driver->auto_probe(p);\r
-       \r
-       if (retval != ERROR_OK)\r
-       {\r
-               ERROR("auto_probe failed %d\n", retval);\r
-               return NULL;\r
-       }\r
-       return p;\r
-}\r
-\r
-int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       int i;\r
-       int found = 0;\r
-       target_t *target;\r
-               \r
-       if (argc < 6)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)\r
-       {\r
-               ERROR("target %lu not defined", strtoul(args[5], NULL, 0));\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       for (i = 0; flash_drivers[i]; i++)\r
-       {\r
-               if (strcmp(args[0], flash_drivers[i]->name) == 0)\r
-               {\r
-                       flash_bank_t *p, *c;\r
-                       \r
-                       /* register flash specific commands */\r
-                       if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)\r
-                       {\r
-                               ERROR("couldn't register '%s' commands", args[0]);\r
-                               exit(-1);\r
-                       }\r
-                       \r
-                       c = malloc(sizeof(flash_bank_t));\r
-                       c->target = target;\r
-                       c->driver = flash_drivers[i];\r
-                       c->driver_priv = NULL;\r
-                       c->base = strtoul(args[1], NULL, 0);\r
-                       c->size = strtoul(args[2], NULL, 0);\r
-                       c->chip_width = strtoul(args[3], NULL, 0);\r
-                       c->bus_width = strtoul(args[4], NULL, 0);\r
-                       c->num_sectors = 0;\r
-                       c->sectors = NULL;\r
-                       c->next = NULL;\r
-                       \r
-                       if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)\r
-                       {\r
-                               ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);\r
-                               free(c);\r
-                               return ERROR_OK;\r
-                       }\r
-                       \r
-                       /* put flash bank in linked list */\r
-                       if (flash_banks)\r
-                       {\r
-                               /* find last flash bank */\r
-                               for (p = flash_banks; p && p->next; p = p->next);\r
-                               if (p)\r
-                                       p->next = c;\r
-                       }\r
-                       else\r
-                       {\r
-                               flash_banks = c;\r
-                       }\r
-                       \r
-                       found = 1;\r
-               }\r
-       }\r
-               \r
-       /* no matching flash driver found */\r
-       if (!found)\r
-       {\r
-               ERROR("flash driver '%s' not found", args[0]);\r
-               exit(-1);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *p;\r
-       int i = 0;\r
-       \r
-       if (!flash_banks)\r
-       {\r
-               command_print(cmd_ctx, "no flash banks configured");\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       for (p = flash_banks; p; p = p->next)\r
-       {\r
-               command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",\r
-                                         i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *p;\r
-       int i = 0;\r
-       int j = 0;\r
-               \r
-       if (argc != 1)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       for (p = flash_banks; p; p = p->next, i++)\r
-       {\r
-               if (i == strtoul(args[0], NULL, 0))\r
-               {\r
-                       char buf[1024];\r
-                       \r
-                       /* attempt auto probe */\r
-                       p->driver->auto_probe(p);\r
-                       \r
-                       command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",\r
-                                               i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);\r
-                       for (j = 0; j < p->num_sectors; j++)\r
-                       {\r
-                               char *erase_state, *protect_state;\r
-                               \r
-                               if (p->sectors[j].is_erased == 0)\r
-                                       erase_state = "not erased";\r
-                               else if (p->sectors[j].is_erased == 1)\r
-                                       erase_state = "erased";\r
-                               else\r
-                                       erase_state = "erase state unknown";\r
-                               \r
-                               if (p->sectors[j].is_protected == 0)\r
-                                       protect_state = "not protected";\r
-                               else if (p->sectors[j].is_protected == 1)\r
-                                       protect_state = "protected";\r
-                               else\r
-                                       protect_state = "protection state unknown";\r
-\r
-                               command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s, %s",\r
-                                                       j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,\r
-                                                       erase_state, protect_state);\r
-                       }\r
-                       \r
-                       p->driver->info(p, buf, 1024);\r
-                       command_print(cmd_ctx, "%s", buf);\r
-               }\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *p;\r
-       int retval;\r
-               \r
-       if (argc != 1)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       p = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));\r
-       if (p)\r
-       {\r
-               if ((retval = p->driver->probe(p)) == ERROR_OK)\r
-               {\r
-                       command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);\r
-               }\r
-               else if (retval == ERROR_FLASH_BANK_INVALID)\r
-               {\r
-                       command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",\r
-                                                 args[0], p->base);\r
-               }\r
-               else\r
-               {\r
-                       command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",\r
-                                                 args[0], p->base);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *p;\r
-       int retval;\r
-               \r
-       if (argc != 1)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-       if (p)\r
-       {\r
-               if ((retval = p->driver->erase_check(p)) == ERROR_OK)\r
-               {\r
-                       command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);\r
-               }\r
-               else\r
-               {\r
-                       command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",\r
-                               args[0], p->base);\r
-               }\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *p;\r
-       int retval;\r
-       int address;\r
-       int length;\r
-       duration_t duration;\r
-       char *duration_text;\r
-       \r
-       target_t *target = get_current_target(cmd_ctx);\r
-\r
-       if (argc != 2)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       address = strtoul(args[0], NULL, 0);\r
-       length = strtoul(args[1], NULL, 0);\r
-       if (length <= 0)\r
-       {\r
-               command_print(cmd_ctx, "Length must be >0");\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-\r
-       p = get_flash_bank_by_addr(target, address);\r
-       if (p == NULL)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       /* We can't know if we did a resume + halt, in which case we no longer know the erased state */\r
-       flash_set_dirty();\r
-       \r
-       duration_start_measure(&duration);\r
-       \r
-       if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)\r
-       {\r
-               duration_stop_measure(&duration, &duration_text);       \r
-               command_print(cmd_ctx, "erased address 0x%8.8x length %i in %s", address, length, duration_text);\r
-               free(duration_text);\r
-       }\r
-       \r
-       return retval;\r
-}\r
-\r
-int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *p;\r
-       int retval;\r
-               \r
-       if (argc != 1)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-       if (p)\r
-       {\r
-               if ((retval = p->driver->protect_check(p)) == ERROR_OK)\r
-               {\r
-                       command_print(cmd_ctx, "successfully checked protect state");\r
-               }\r
-               else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
-               {\r
-                       command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);\r
-               }\r
-               else\r
-               {\r
-                       command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       if (argc > 2)\r
-       {\r
-               int first = strtoul(args[1], NULL, 0);\r
-               int last = strtoul(args[2], NULL, 0);\r
-               int retval;\r
-               flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-               duration_t duration;\r
-               char *duration_text;\r
-       \r
-               duration_start_measure(&duration);\r
-       \r
-               if (!p)\r
-               {\r
-                       return ERROR_COMMAND_SYNTAX_ERROR;\r
-               }\r
-               \r
-               if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)\r
-               {\r
-                       duration_stop_measure(&duration, &duration_text);       \r
-                       \r
-                       command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %s", first, last, strtoul(args[0], 0, 0), duration_text);\r
-                       free(duration_text);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-\r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       if (argc > 3)\r
-       {\r
-               int first = strtoul(args[1], NULL, 0);\r
-               int last = strtoul(args[2], NULL, 0);\r
-               int set;\r
-               int retval;\r
-               flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-               if (!p)\r
-               {\r
-                       command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
-                       return ERROR_OK;\r
-               }\r
-               \r
-               if (strcmp(args[3], "on") == 0)\r
-                       set = 1;\r
-               else if (strcmp(args[3], "off") == 0)\r
-                       set = 0;\r
-               else\r
-               {\r
-                       return ERROR_COMMAND_SYNTAX_ERROR;\r
-               }\r
-               \r
-               retval = flash_driver_protect(p, set, first, last);\r
-               if (retval == ERROR_OK)\r
-               {\r
-                       command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %i", (set) ? "set" : "cleared", first, last, strtoul(args[0], 0, 0));\r
-               }\r
-       }\r
-       else\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-\r
-       }\r
-\r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       target_t *target = get_current_target(cmd_ctx);\r
-       \r
-       image_t image;\r
-       u32 written;\r
-       \r
-       duration_t duration;\r
-       char *duration_text;\r
-       \r
-       int retval;\r
-\r
-       if (argc < 1)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-\r
-       }\r
-       \r
-       if (!target)\r
-       {\r
-               ERROR("no target selected");\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       duration_start_measure(&duration);\r
-       \r
-       if (argc >= 2)\r
-       {\r
-               image.base_address_set = 1;\r
-               image.base_address = strtoul(args[1], NULL, 0);\r
-       }\r
-       else\r
-       {\r
-               image.base_address_set = 0;\r
-               image.base_address = 0x0;\r
-       }\r
-       \r
-       image.start_address_set = 0;\r
-\r
-       retval = image_open(&image, args[0], (argc == 3) ? args[2] : NULL);\r
-       if (retval != ERROR_OK)\r
-       {\r
-               command_print(cmd_ctx, "image_open error: %s", image.error_str);\r
-               return retval;\r
-       }\r
-       \r
-       retval = flash_write(target, &image, &written, auto_erase);\r
-\r
-       if (retval != ERROR_OK)\r
-       {\r
-               image_close(&image);\r
-               return retval;\r
-       }\r
-       \r
-       duration_stop_measure(&duration, &duration_text);\r
-       if (retval == ERROR_OK)\r
-       {\r
-       command_print(cmd_ctx, "wrote %u byte from file %s in %s (%f kb/s)",\r
-               written, args[0], duration_text,\r
-               (float)written / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));\r
-       }\r
-       free(duration_text);\r
-\r
-       image_close(&image);\r
-       \r
-       return retval;\r
-}\r
-\r
-int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       u32 offset;\r
-       u8 *buffer;\r
-       u32 buf_cnt;\r
-\r
-       fileio_t fileio;\r
-       \r
-       duration_t duration;\r
-       char *duration_text;\r
-       \r
-       int retval;\r
-       flash_bank_t *p;\r
-\r
-       if (argc != 3)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       }\r
-       \r
-       duration_start_measure(&duration);\r
-       \r
-       offset = strtoul(args[2], NULL, 0);\r
-       p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-       if (!p)\r
-       {\r
-               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)\r
-       {\r
-               command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       buffer = malloc(fileio.size);\r
-       if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)\r
-       {\r
-               command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);\r
-               return ERROR_OK;\r
-       }\r
-       \r
-       retval = flash_driver_write(p, buffer, offset, buf_cnt);\r
-               \r
-       free(buffer);\r
-       \r
-       duration_stop_measure(&duration, &duration_text);\r
-       if (retval!=ERROR_OK)\r
-       {\r
-       command_print(cmd_ctx, "wrote  %"PRIi64" byte from file %s to flash bank %i at offset 0x%8.8x in %s (%f kb/s)",\r
-               fileio.size, args[1], strtoul(args[0], NULL, 0), offset, duration_text,\r
-               (float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));\r
-       }\r
-       free(duration_text);\r
-\r
-       fileio_close(&fileio);\r
-       \r
-       return retval;\r
-}\r
-\r
-void flash_set_dirty(void)\r
-{\r
-       flash_bank_t *c;\r
-       int i;\r
-       \r
-       /* set all flash to require erasing */\r
-       for (c = flash_banks; c; c = c->next)\r
-       {\r
-               for (i = 0; i < c->num_sectors; i++)\r
-               {\r
-                       c->sectors[i].is_erased = 0; \r
-               }\r
-       }\r
-}\r
-\r
-/* lookup flash bank by address */\r
-flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)\r
-{\r
-       flash_bank_t *c;\r
-\r
-       /* cycle through bank list */\r
-       for (c = flash_banks; c; c = c->next)\r
-       {\r
-               int retval;\r
-               retval = c->driver->auto_probe(c);\r
-               \r
-               if (retval != ERROR_OK)\r
-               {\r
-                       ERROR("auto_probe failed %d\n", retval);\r
-                       return NULL;\r
-               }\r
-               /* check whether address belongs to this flash bank */\r
-               if ((addr >= c->base) && (addr < c->base + c->size) && target == c->target)\r
-                       return c;\r
-       }\r
-       ERROR("No flash at address 0x%08x\n", addr);\r
-       return NULL;\r
-}\r
-\r
-/* erase given flash region, selects proper bank according to target and address */\r
-int flash_erase_address_range(target_t *target, u32 addr, u32 length)\r
-{\r
-       flash_bank_t *c;\r
-       int first = -1;\r
-       int last = -1;\r
-       int i;\r
-       \r
-       if ((c = get_flash_bank_by_addr(target, addr)) == NULL)\r
-               return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */\r
-\r
-       if (c->size == 0 || c->num_sectors == 0)\r
-               return ERROR_FLASH_BANK_INVALID;\r
-       \r
-       if (length == 0)\r
-       {\r
-               /* special case, erase whole bank when length is zero */\r
-               if (addr != c->base)\r
-                       return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
-               \r
-               return flash_driver_erase(c, 0, c->num_sectors - 1);\r
-       }\r
-\r
-       /* check whether it fits */\r
-       if (addr + length > c->base + c->size)\r
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
-       \r
-       addr -= c->base;\r
-       \r
-       for (i = 0; i < c->num_sectors; i++)\r
-       {               \r
-               /* check whether sector overlaps with the given range and is not yet erased */\r
-               if (addr < c->sectors[i].offset + c->sectors[i].size && addr + length > c->sectors[i].offset && c->sectors[i].is_erased != 1) {\r
-                       /* if first is not set yet then this is the first sector */\r
-                       if (first == -1)\r
-                               first = i;\r
-                       last = i; /* and it is the last one so far in any case */\r
-               }\r
-       }\r
-       \r
-       if( first == -1 || last == -1 )\r
-               return ERROR_OK;\r
-       \r
-       return flash_driver_erase(c, first, last);\r
-}\r
-\r
-/* write (optional verify) an image to flash memory of the given target */\r
-int flash_write(target_t *target, image_t *image, u32 *written, int erase)\r
-{\r
-       int retval;\r
-\r
-       int section;\r
-       u32 section_offset;\r
-       flash_bank_t *c;\r
-       \r
-       section = 0;\r
-       section_offset = 0;\r
-\r
-       if (written)\r
-               *written = 0;\r
-       \r
-       if (erase)\r
-       {\r
-               /* assume all sectors need erasing - stops any problems\r
-                * when flash_write is called multiple times */\r
-               \r
-               flash_set_dirty();\r
-       }\r
-       \r
-       /* loop until we reach end of the image */\r
-       while (section < image->num_sections)\r
-       {\r
-               u32 buffer_size;\r
-               u8 *buffer;\r
-               int section_first;\r
-               int section_last;\r
-               u32 run_address = image->sections[section].base_address + section_offset;\r
-               u32 run_size = image->sections[section].size - section_offset;\r
-\r
-               if (image->sections[section].size ==  0)\r
-               {\r
-                       WARNING("empty section %d", section);\r
-                       section++;\r
-                       section_offset = 0;\r
-                       continue;\r
-               }\r
-\r
-               /* find the corresponding flash bank */\r
-               if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)\r
-               {\r
-                       section++; /* and skip it */\r
-                       section_offset = 0;\r
-                       continue;\r
-               }\r
-\r
-               /* collect consecutive sections which fall into the same bank */\r
-               section_first = section;\r
-               section_last = section;\r
-               while ((run_address + run_size < c->base + c->size)\r
-                               && (section_last + 1 < image->num_sections))\r
-               {\r
-                       if (image->sections[section_last + 1].base_address < (run_address + run_size))\r
-                       {\r
-                               DEBUG("section %d out of order(very slightly surprising, but supported)", section_last + 1);\r
-                               break;\r
-                       }\r
-                       if (image->sections[section_last + 1].base_address != (run_address + run_size))\r
-                               break;\r
-                       run_size += image->sections[++section_last].size;\r
-               }\r
-\r
-               /* fit the run into bank constraints */\r
-               if (run_address + run_size > c->base + c->size)\r
-                       run_size = c->base + c->size - run_address;\r
-\r
-               /* allocate buffer */\r
-               buffer = malloc(run_size);\r
-               buffer_size = 0;\r
-\r
-               /* read sections to the buffer */\r
-               while (buffer_size < run_size)\r
-               {\r
-                       u32 size_read;\r
-                       \r
-                       if (buffer_size - run_size <= image->sections[section].size - section_offset)\r
-                               size_read = buffer_size - run_size;\r
-                       else\r
-                               size_read = image->sections[section].size - section_offset;\r
-                       \r
-                       if ((retval = image_read_section(image, section, section_offset,\r
-                                       size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)\r
-                       {\r
-                               free(buffer);\r
-                               \r
-                               return retval;\r
-                       }\r
-\r
-                       buffer_size += size_read;\r
-                       section_offset += size_read;\r
-\r
-                       if (section_offset >= image->sections[section].size)\r
-                       {\r
-                               section++;\r
-                               section_offset = 0;\r
-                       }\r
-               }\r
-\r
-               retval = ERROR_OK;\r
-               \r
-               if (erase)\r
-               {\r
-                       /* calculate and erase sectors */\r
-                       retval = flash_erase_address_range( target, run_address, run_size );\r
-               }\r
-               \r
-               if (retval == ERROR_OK)\r
-               {\r
-                       /* write flash sectors */\r
-                       retval = flash_driver_write(c, buffer, run_address - c->base, run_size);\r
-               }\r
-               \r
-               free(buffer);\r
-\r
-               if (retval != ERROR_OK)\r
-               {\r
-                               return retval; /* abort operation */\r
-                       }\r
-\r
-               if (written != NULL)\r
-                       *written += run_size; /* add run size to total written counter */\r
-       }\r
-\r
-       return ERROR_OK;\r
-}\r
-\r
-int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       if (argc != 1)\r
-       {\r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-\r
-       }\r
-       \r
-       if (strcmp(args[0], "on") == 0)\r
-               auto_erase = 1;\r
-       else if (strcmp(args[0], "off") == 0)\r
-               auto_erase = 0;\r
-       else \r
-               return ERROR_COMMAND_SYNTAX_ERROR;\r
-       \r
-       return ERROR_OK;\r
-}\r
+/***************************************************************************
+ *   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.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "flash.h"
+#include "command.h"
+#include "target.h"
+#include "time_support.h"
+#include "fileio.h"
+#include "image.h"
+#include "log.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <inttypes.h>
+
+/* command handlers */
+int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);
+
+/* flash drivers
+ */
+extern flash_driver_t lpc2000_flash;
+extern flash_driver_t cfi_flash;
+extern flash_driver_t at91sam7_flash;
+extern flash_driver_t str7x_flash;
+extern flash_driver_t str9x_flash;
+extern flash_driver_t stellaris_flash;
+extern flash_driver_t str9xpec_flash;
+extern flash_driver_t stm32x_flash;
+extern flash_driver_t tms470_flash;
+
+flash_driver_t *flash_drivers[] =
+{
+       &lpc2000_flash,
+       &cfi_flash,
+       &at91sam7_flash,
+       &str7x_flash,
+       &str9x_flash,
+       &stellaris_flash,
+       &str9xpec_flash,
+       &stm32x_flash,
+       &tms470_flash,
+       NULL,
+};
+
+flash_bank_t *flash_banks;
+static         command_t *flash_cmd;
+static int auto_erase = 0;
+
+/* wafer thin wrapper for invoking the flash driver */
+static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+       int retval=ERROR_OK;
+       if (bank->target->state != TARGET_HALTED)
+       {
+               ERROR("target not halted - aborting flash write");
+               retval=ERROR_TARGET_NOT_HALTED;
+       } else
+       {
+               retval=bank->driver->write(bank, buffer, offset, count);
+       }
+       if (retval!=ERROR_OK)
+       {
+               ERROR("Writing to flash bank at address 0x%08x at offset 0x%8.8x", bank->base, offset);
+       }
+       return retval;
+}
+
+static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
+{
+       int retval=ERROR_OK;
+       if (bank->target->state != TARGET_HALTED)
+       {
+               ERROR("target not halted - aborting flash erase");
+               retval=ERROR_TARGET_NOT_HALTED;
+       } else if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               ERROR("invalid flash sector");
+               retval=ERROR_FLASH_SECTOR_INVALID;
+       } else          
+       {
+               retval=bank->driver->erase(bank, first, last);
+       }
+       if (retval!=ERROR_OK)
+       {
+               ERROR("Failed erasing banks %d to %d", first, last);
+       }
+       return retval;
+}
+
+int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+       int retval;
+       if (bank->target->state != TARGET_HALTED)
+       {
+               ERROR("target not halted - aborting flash erase");
+               retval=ERROR_TARGET_NOT_HALTED;
+       } else if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+       {
+               ERROR("invalid flash sector");
+               retval=ERROR_FLASH_SECTOR_INVALID;
+       } else          
+       {
+               retval=bank->driver->protect(bank, set, first, last);
+       }
+       if (retval!=ERROR_OK)
+       {
+               ERROR("Failed protecting banks %d to %d", first, last);
+       }
+       return retval;
+}
+
+
+int flash_register_commands(struct command_context_s *cmd_ctx)
+{
+       flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);
+       
+       register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, "flash_bank <driver> <base> <size> <chip_width> <bus_width> <target> [driver_options ...]");
+       register_command(cmd_ctx, flash_cmd, "auto_erase", handle_flash_auto_erase_command, COMMAND_ANY,
+                                                "auto erase flash sectors <on|off>");
+       return ERROR_OK;
+}
+
+int flash_init_drivers(struct command_context_s *cmd_ctx)
+{
+       if (flash_banks)
+       {
+               register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,
+                                                "list configured flash banks ");
+               register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,
+                                                "print info about flash bank <num>");
+               register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,
+                                                "identify flash bank <num>");
+               register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,
+                                                "check erase state of sectors in flash bank <num>");
+               register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,
+                                                "check protection state of sectors in flash bank <num>");
+               register_command(cmd_ctx, flash_cmd, "erase_sector", handle_flash_erase_command, COMMAND_EXEC,
+                                                "erase sectors at <bank> <first> <last>");
+               register_command(cmd_ctx, flash_cmd, "erase_address", handle_flash_erase_address_command, COMMAND_EXEC,
+                                                "erase address range <address> <length>");
+               register_command(cmd_ctx, flash_cmd, "write_bank", handle_flash_write_bank_command, COMMAND_EXEC,
+                                                "write binary data to <bank> <file> <offset>");
+               register_command(cmd_ctx, flash_cmd, "write_image", handle_flash_write_image_command, COMMAND_EXEC,
+                                                "write_image <file> [offset] [type]");
+               register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
+                                                "set protection of sectors at <bank> <first> <last> <on|off>");
+       }
+       
+       return ERROR_OK;
+}
+
+flash_bank_t *get_flash_bank_by_num_noprobe(int num)
+{
+       flash_bank_t *p;
+       int i = 0;
+
+       for (p = flash_banks; p; p = p->next)
+       {
+               if (i++ == num)
+               {
+                       return p;
+               }
+       }
+       ERROR("Flash bank %d does not exist", num);
+       return NULL;
+}
+
+flash_bank_t *get_flash_bank_by_num(int num)
+{
+       flash_bank_t *p = get_flash_bank_by_num_noprobe(num);
+       int retval;
+       
+       if (p == NULL)
+               return NULL;
+       
+       retval = p->driver->auto_probe(p);
+       
+       if (retval != ERROR_OK)
+       {
+               ERROR("auto_probe failed %d\n", retval);
+               return NULL;
+       }
+       return p;
+}
+
+int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       int i;
+       int found = 0;
+       target_t *target;
+               
+       if (argc < 6)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)
+       {
+               ERROR("target %lu not defined", strtoul(args[5], NULL, 0));
+               return ERROR_OK;
+       }
+       
+       for (i = 0; flash_drivers[i]; i++)
+       {
+               if (strcmp(args[0], flash_drivers[i]->name) == 0)
+               {
+                       flash_bank_t *p, *c;
+                       
+                       /* register flash specific commands */
+                       if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
+                       {
+                               ERROR("couldn't register '%s' commands", args[0]);
+                               exit(-1);
+                       }
+                       
+                       c = malloc(sizeof(flash_bank_t));
+                       c->target = target;
+                       c->driver = flash_drivers[i];
+                       c->driver_priv = NULL;
+                       c->base = strtoul(args[1], NULL, 0);
+                       c->size = strtoul(args[2], NULL, 0);
+                       c->chip_width = strtoul(args[3], NULL, 0);
+                       c->bus_width = strtoul(args[4], NULL, 0);
+                       c->num_sectors = 0;
+                       c->sectors = NULL;
+                       c->next = NULL;
+                       
+                       if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)
+                       {
+                               ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
+                               free(c);
+                               return ERROR_OK;
+                       }
+                       
+                       /* put flash bank in linked list */
+                       if (flash_banks)
+                       {
+                               /* find last flash bank */
+                               for (p = flash_banks; p && p->next; p = p->next);
+                               if (p)
+                                       p->next = c;
+                       }
+                       else
+                       {
+                               flash_banks = c;
+                       }
+                       
+                       found = 1;
+               }
+       }
+               
+       /* no matching flash driver found */
+       if (!found)
+       {
+               ERROR("flash driver '%s' not found", args[0]);
+               exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *p;
+       int i = 0;
+       
+       if (!flash_banks)
+       {
+               command_print(cmd_ctx, "no flash banks configured");
+               return ERROR_OK;
+       }
+       
+       for (p = flash_banks; p; p = p->next)
+       {
+               command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
+                                         i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *p;
+       int i = 0;
+       int j = 0;
+               
+       if (argc != 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       for (p = flash_banks; p; p = p->next, i++)
+       {
+               if (i == strtoul(args[0], NULL, 0))
+               {
+                       char buf[1024];
+                       
+                       /* attempt auto probe */
+                       p->driver->auto_probe(p);
+                       
+                       command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
+                                               i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
+                       for (j = 0; j < p->num_sectors; j++)
+                       {
+                               char *erase_state, *protect_state;
+                               
+                               if (p->sectors[j].is_erased == 0)
+                                       erase_state = "not erased";
+                               else if (p->sectors[j].is_erased == 1)
+                                       erase_state = "erased";
+                               else
+                                       erase_state = "erase state unknown";
+                               
+                               if (p->sectors[j].is_protected == 0)
+                                       protect_state = "not protected";
+                               else if (p->sectors[j].is_protected == 1)
+                                       protect_state = "protected";
+                               else
+                                       protect_state = "protection state unknown";
+
+                               command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s, %s",
+                                                       j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
+                                                       erase_state, protect_state);
+                       }
+                       
+                       p->driver->info(p, buf, 1024);
+                       command_print(cmd_ctx, "%s", buf);
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *p;
+       int retval;
+               
+       if (argc != 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       p = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if ((retval = p->driver->probe(p)) == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);
+               }
+               else if (retval == ERROR_FLASH_BANK_INVALID)
+               {
+                       command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",
+                                                 args[0], p->base);
+               }
+               else
+               {
+                       command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",
+                                                 args[0], p->base);
+               }
+       }
+       else
+       {
+               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *p;
+       int retval;
+               
+       if (argc != 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if ((retval = p->driver->erase_check(p)) == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
+               }
+               else
+               {
+                       command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
+                               args[0], p->base);
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *p;
+       int retval;
+       int address;
+       int length;
+       duration_t duration;
+       char *duration_text;
+       
+       target_t *target = get_current_target(cmd_ctx);
+
+       if (argc != 2)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       address = strtoul(args[0], NULL, 0);
+       length = strtoul(args[1], NULL, 0);
+       if (length <= 0)
+       {
+               command_print(cmd_ctx, "Length must be >0");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       p = get_flash_bank_by_addr(target, address);
+       if (p == NULL)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       /* We can't know if we did a resume + halt, in which case we no longer know the erased state */
+       flash_set_dirty();
+       
+       duration_start_measure(&duration);
+       
+       if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)
+       {
+               duration_stop_measure(&duration, &duration_text);       
+               command_print(cmd_ctx, "erased address 0x%8.8x length %i in %s", address, length, duration_text);
+               free(duration_text);
+       }
+       
+       return retval;
+}
+
+int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *p;
+       int retval;
+               
+       if (argc != 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if ((retval = p->driver->protect_check(p)) == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "successfully checked protect state");
+               }
+               else if (retval == ERROR_FLASH_OPERATION_FAILED)
+               {
+                       command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);
+               }
+               else
+               {
+                       command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);
+               }
+       }
+       else
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc > 2)
+       {
+               int first = strtoul(args[1], NULL, 0);
+               int last = strtoul(args[2], NULL, 0);
+               int retval;
+               flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+               duration_t duration;
+               char *duration_text;
+       
+               duration_start_measure(&duration);
+       
+               if (!p)
+               {
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               
+               if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)
+               {
+                       duration_stop_measure(&duration, &duration_text);       
+                       
+                       command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %s", first, last, strtoul(args[0], 0, 0), duration_text);
+                       free(duration_text);
+               }
+       }
+       else
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       return ERROR_OK;
+}
+
+int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc > 3)
+       {
+               int first = strtoul(args[1], NULL, 0);
+               int last = strtoul(args[2], NULL, 0);
+               int set;
+               int retval;
+               flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+               if (!p)
+               {
+                       command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+                       return ERROR_OK;
+               }
+               
+               if (strcmp(args[3], "on") == 0)
+                       set = 1;
+               else if (strcmp(args[3], "off") == 0)
+                       set = 0;
+               else
+               {
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               
+               retval = flash_driver_protect(p, set, first, last);
+               if (retval == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %i", (set) ? "set" : "cleared", first, last, strtoul(args[0], 0, 0));
+               }
+       }
+       else
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       }
+
+       return ERROR_OK;
+}
+
+int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       
+       image_t image;
+       u32 written;
+       
+       duration_t duration;
+       char *duration_text;
+       
+       int retval;
+
+       if (argc < 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       }
+       
+       if (!target)
+       {
+               ERROR("no target selected");
+               return ERROR_OK;
+       }
+       
+       duration_start_measure(&duration);
+       
+       if (argc >= 2)
+       {
+               image.base_address_set = 1;
+               image.base_address = strtoul(args[1], NULL, 0);
+       }
+       else
+       {
+               image.base_address_set = 0;
+               image.base_address = 0x0;
+       }
+       
+       image.start_address_set = 0;
+
+       retval = image_open(&image, args[0], (argc == 3) ? args[2] : NULL);
+       if (retval != ERROR_OK)
+       {
+               command_print(cmd_ctx, "image_open error: %s", image.error_str);
+               return retval;
+       }
+       
+       retval = flash_write(target, &image, &written, auto_erase);
+
+       if (retval != ERROR_OK)
+       {
+               image_close(&image);
+               return retval;
+       }
+       
+       duration_stop_measure(&duration, &duration_text);
+       if (retval == ERROR_OK)
+       {
+       command_print(cmd_ctx, "wrote %u byte from file %s in %s (%f kb/s)",
+               written, args[0], duration_text,
+               (float)written / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
+       }
+       free(duration_text);
+
+       image_close(&image);
+       
+       return retval;
+}
+
+int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       u32 offset;
+       u8 *buffer;
+       u32 buf_cnt;
+
+       fileio_t fileio;
+       
+       duration_t duration;
+       char *duration_text;
+       
+       int retval;
+       flash_bank_t *p;
+
+       if (argc != 3)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       
+       duration_start_measure(&duration);
+       
+       offset = strtoul(args[2], NULL, 0);
+       p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+       if (!p)
+       {
+               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+               return ERROR_OK;
+       }
+       
+       if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);
+               return ERROR_OK;
+       }
+       
+       buffer = malloc(fileio.size);
+       if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);
+               return ERROR_OK;
+       }
+       
+       retval = flash_driver_write(p, buffer, offset, buf_cnt);
+               
+       free(buffer);
+       
+       duration_stop_measure(&duration, &duration_text);
+       if (retval!=ERROR_OK)
+       {
+       command_print(cmd_ctx, "wrote  %"PRIi64" byte from file %s to flash bank %i at offset 0x%8.8x in %s (%f kb/s)",
+               fileio.size, args[1], strtoul(args[0], NULL, 0), offset, duration_text,
+               (float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
+       }
+       free(duration_text);
+
+       fileio_close(&fileio);
+       
+       return retval;
+}
+
+void flash_set_dirty(void)
+{
+       flash_bank_t *c;
+       int i;
+       
+       /* set all flash to require erasing */
+       for (c = flash_banks; c; c = c->next)
+       {
+               for (i = 0; i < c->num_sectors; i++)
+               {
+                       c->sectors[i].is_erased = 0; 
+               }
+       }
+}
+
+/* lookup flash bank by address */
+flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)
+{
+       flash_bank_t *c;
+
+       /* cycle through bank list */
+       for (c = flash_banks; c; c = c->next)
+       {
+               int retval;
+               retval = c->driver->auto_probe(c);
+               
+               if (retval != ERROR_OK)
+               {
+                       ERROR("auto_probe failed %d\n", retval);
+                       return NULL;
+               }
+               /* check whether address belongs to this flash bank */
+               if ((addr >= c->base) && (addr < c->base + c->size) && target == c->target)
+                       return c;
+       }
+       ERROR("No flash at address 0x%08x\n", addr);
+       return NULL;
+}
+
+/* erase given flash region, selects proper bank according to target and address */
+int flash_erase_address_range(target_t *target, u32 addr, u32 length)
+{
+       flash_bank_t *c;
+       int first = -1;
+       int last = -1;
+       int i;
+       
+       if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
+               return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */
+
+       if (c->size == 0 || c->num_sectors == 0)
+               return ERROR_FLASH_BANK_INVALID;
+       
+       if (length == 0)
+       {
+               /* special case, erase whole bank when length is zero */
+               if (addr != c->base)
+                       return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+               
+               return flash_driver_erase(c, 0, c->num_sectors - 1);
+       }
+
+       /* check whether it fits */
+       if (addr + length > c->base + c->size)
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       
+       addr -= c->base;
+       
+       for (i = 0; i < c->num_sectors; i++)
+       {               
+               /* check whether sector overlaps with the given range and is not yet erased */
+               if (addr < c->sectors[i].offset + c->sectors[i].size && addr + length > c->sectors[i].offset && c->sectors[i].is_erased != 1) {
+                       /* if first is not set yet then this is the first sector */
+                       if (first == -1)
+                               first = i;
+                       last = i; /* and it is the last one so far in any case */
+               }
+       }
+       
+       if( first == -1 || last == -1 )
+               return ERROR_OK;
+       
+       return flash_driver_erase(c, first, last);
+}
+
+/* write (optional verify) an image to flash memory of the given target */
+int flash_write(target_t *target, image_t *image, u32 *written, int erase)
+{
+       int retval;
+
+       int section;
+       u32 section_offset;
+       flash_bank_t *c;
+       
+       section = 0;
+       section_offset = 0;
+
+       if (written)
+               *written = 0;
+       
+       if (erase)
+       {
+               /* assume all sectors need erasing - stops any problems
+                * when flash_write is called multiple times */
+               
+               flash_set_dirty();
+       }
+       
+       /* loop until we reach end of the image */
+       while (section < image->num_sections)
+       {
+               u32 buffer_size;
+               u8 *buffer;
+               int section_first;
+               int section_last;
+               u32 run_address = image->sections[section].base_address + section_offset;
+               u32 run_size = image->sections[section].size - section_offset;
+
+               if (image->sections[section].size ==  0)
+               {
+                       WARNING("empty section %d", section);
+                       section++;
+                       section_offset = 0;
+                       continue;
+               }
+
+               /* find the corresponding flash bank */
+               if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
+               {
+                       section++; /* and skip it */
+                       section_offset = 0;
+                       continue;
+               }
+
+               /* collect consecutive sections which fall into the same bank */
+               section_first = section;
+               section_last = section;
+               while ((run_address + run_size < c->base + c->size)
+                               && (section_last + 1 < image->num_sections))
+               {
+                       if (image->sections[section_last + 1].base_address < (run_address + run_size))
+                       {
+                               DEBUG("section %d out of order(very slightly surprising, but supported)", section_last + 1);
+                               break;
+                       }
+                       if (image->sections[section_last + 1].base_address != (run_address + run_size))
+                               break;
+                       run_size += image->sections[++section_last].size;
+               }
+
+               /* fit the run into bank constraints */
+               if (run_address + run_size > c->base + c->size)
+                       run_size = c->base + c->size - run_address;
+
+               /* allocate buffer */
+               buffer = malloc(run_size);
+               buffer_size = 0;
+
+               /* read sections to the buffer */
+               while (buffer_size < run_size)
+               {
+                       u32 size_read;
+                       
+                       if (buffer_size - run_size <= image->sections[section].size - section_offset)
+                               size_read = buffer_size - run_size;
+                       else
+                               size_read = image->sections[section].size - section_offset;
+                       
+                       if ((retval = image_read_section(image, section, section_offset,
+                                       size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
+                       {
+                               free(buffer);
+                               
+                               return retval;
+                       }
+
+                       buffer_size += size_read;
+                       section_offset += size_read;
+
+                       if (section_offset >= image->sections[section].size)
+                       {
+                               section++;
+                               section_offset = 0;
+                       }
+               }
+
+               retval = ERROR_OK;
+               
+               if (erase)
+               {
+                       /* calculate and erase sectors */
+                       retval = flash_erase_address_range( target, run_address, run_size );
+               }
+               
+               if (retval == ERROR_OK)
+               {
+                       /* write flash sectors */
+                       retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
+               }
+               
+               free(buffer);
+
+               if (retval != ERROR_OK)
+               {
+                               return retval; /* abort operation */
+                       }
+
+               if (written != NULL)
+                       *written += run_size; /* add run size to total written counter */
+       }
+
+       return ERROR_OK;
+}
+
+int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc != 1)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       }
+       
+       if (strcmp(args[0], "on") == 0)
+               auto_erase = 1;
+       else if (strcmp(args[0], "off") == 0)
+               auto_erase = 0;
+       else 
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       
+       return ERROR_OK;
+}
index e8262ef..b707b51 100644 (file)
@@ -1,97 +1,97 @@
-/***************************************************************************\r
- *   Copyright (C) 2005 by Dominic Rath                                    *\r
- *   Dominic.Rath@gmx.de                                                   *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
- ***************************************************************************/\r
-#ifndef FLASH_H\r
-#define FLASH_H\r
-\r
-#include "target.h"\r
-#include "image.h"\r
-\r
-#define FLASH_MAX_ERROR_STR    (128)\r
-\r
-typedef struct flash_sector_s\r
-{\r
-       u32 offset;\r
-       u32 size;\r
-       int is_erased;\r
-       int is_protected;\r
-} flash_sector_t;\r
-\r
-struct flash_bank_s;\r
-\r
-typedef struct flash_driver_s\r
-{\r
-       char *name;\r
-       int (*register_commands)(struct command_context_s *cmd_ctx);\r
-       int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
-       /* low level flash erase. Only invoke from flash_driver_erase()\r
-        * \r
-        * Will only be invoked when target is halted. \r
-        */\r
-       int (*erase)(struct flash_bank_s *bank, int first, int last);\r
-       /* invoked only from flash_driver_protect().\r
-        *  \r
-        * Only invoked if target is halted\r
-        */\r
-       int (*protect)(struct flash_bank_s *bank, int set, int first, int last);\r
-       /* low level flash write. Will only be invoked if the target is halted.\r
-        * use the flash_driver_write() wrapper to invoke.\r
-        */\r
-       int (*write)(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
-       int (*probe)(struct flash_bank_s *bank);\r
-       int (*erase_check)(struct flash_bank_s *bank);\r
-       int (*protect_check)(struct flash_bank_s *bank);\r
-       int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);\r
-       int (*auto_probe)(struct flash_bank_s *bank);\r
-} flash_driver_t;\r
-\r
-typedef struct flash_bank_s\r
-{\r
-       target_t *target;\r
-       flash_driver_t *driver;\r
-       void *driver_priv;\r
-       u32 base;\r
-       u32 size;\r
-       int chip_width;\r
-       int bus_width;\r
-       int num_sectors;\r
-       flash_sector_t *sectors;\r
-       struct flash_bank_s *next;\r
-} flash_bank_t;\r
-\r
-extern int flash_register_commands(struct command_context_s *cmd_ctx);\r
-extern int flash_init_drivers(struct command_context_s *cmd_ctx);\r
-\r
-extern int flash_erase_address_range(target_t *target, u32 addr, u32 length);\r
-extern int flash_write(target_t *target, image_t *image, u32 *written, int erase);\r
-extern void flash_set_dirty(void);\r
-\r
-extern flash_bank_t *get_flash_bank_by_num(int num);\r
-extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);\r
-\r
-#define                ERROR_FLASH_BANK_INVALID                (-900)\r
-#define                ERROR_FLASH_SECTOR_INVALID              (-901)\r
-#define                ERROR_FLASH_OPERATION_FAILED    (-902)\r
-#define                ERROR_FLASH_DST_OUT_OF_BANK             (-903)\r
-#define                ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)\r
-#define                ERROR_FLASH_BUSY                                (-905)\r
-#define                ERROR_FLASH_SECTOR_NOT_ERASED   (-906)\r
-#define                ERROR_FLASH_BANK_NOT_PROBED             (-907)\r
-\r
-#endif /* FLASH_H */\r
+/***************************************************************************
+ *   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 FLASH_H
+#define FLASH_H
+
+#include "target.h"
+#include "image.h"
+
+#define FLASH_MAX_ERROR_STR    (128)
+
+typedef struct flash_sector_s
+{
+       u32 offset;
+       u32 size;
+       int is_erased;
+       int is_protected;
+} flash_sector_t;
+
+struct flash_bank_s;
+
+typedef struct flash_driver_s
+{
+       char *name;
+       int (*register_commands)(struct command_context_s *cmd_ctx);
+       int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+       /* low level flash erase. Only invoke from flash_driver_erase()
+        * 
+        * Will only be invoked when target is halted. 
+        */
+       int (*erase)(struct flash_bank_s *bank, int first, int last);
+       /* invoked only from flash_driver_protect().
+        *  
+        * Only invoked if target is halted
+        */
+       int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
+       /* low level flash write. Will only be invoked if the target is halted.
+        * use the flash_driver_write() wrapper to invoke.
+        */
+       int (*write)(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+       int (*probe)(struct flash_bank_s *bank);
+       int (*erase_check)(struct flash_bank_s *bank);
+       int (*protect_check)(struct flash_bank_s *bank);
+       int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);
+       int (*auto_probe)(struct flash_bank_s *bank);
+} flash_driver_t;
+
+typedef struct flash_bank_s
+{
+       target_t *target;
+       flash_driver_t *driver;
+       void *driver_priv;
+       u32 base;
+       u32 size;
+       int chip_width;
+       int bus_width;
+       int num_sectors;
+       flash_sector_t *sectors;
+       struct flash_bank_s *next;
+} flash_bank_t;
+
+extern int flash_register_commands(struct command_context_s *cmd_ctx);
+extern int flash_init_drivers(struct command_context_s *cmd_ctx);
+
+extern int flash_erase_address_range(target_t *target, u32 addr, u32 length);
+extern int flash_write(target_t *target, image_t *image, u32 *written, int erase);
+extern void flash_set_dirty(void);
+
+extern flash_bank_t *get_flash_bank_by_num(int num);
+extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);
+
+#define                ERROR_FLASH_BANK_INVALID                (-900)
+#define                ERROR_FLASH_SECTOR_INVALID              (-901)
+#define                ERROR_FLASH_OPERATION_FAILED    (-902)
+#define                ERROR_FLASH_DST_OUT_OF_BANK             (-903)
+#define                ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)
+#define                ERROR_FLASH_BUSY                                (-905)
+#define                ERROR_FLASH_SECTOR_NOT_ERASED   (-906)
+#define                ERROR_FLASH_BANK_NOT_PROBED             (-907)
+
+#endif /* FLASH_H */
index 009c0c0..396f910 100644 (file)
-/***************************************************************************\r
- *   Copyright (C) 2005 by Dominic Rath                                    *\r
- *   Dominic.Rath@gmx.de                                                   *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
- ***************************************************************************/\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "lpc2000.h"\r
-\r
-#include "flash.h"\r
-#include "target.h"\r
-#include "log.h"\r
-#include "armv4_5.h"\r
-#include "algorithm.h"\r
-#include "binarybuffer.h"\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-/* flash programming support for Philips LPC2xxx devices\r
- * currently supported devices:\r
- * variant 1 (lpc2000_v1):\r
- * - 2104|5|6\r
- * - 2114|9\r
- * - 2124|9\r
- * - 2194\r
- * - 2212|4\r
- * - 2292|4\r
- *\r
- * variant 2 (lpc2000_v2):\r
- * - 213x\r
- * - 214x\r
- * - 2101|2|3\r
- * - 2364|6|8\r
- * - 2378\r
- */\r
-\r
-int lpc2000_register_commands(struct command_context_s *cmd_ctx);\r
-int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
-int lpc2000_erase(struct flash_bank_s *bank, int first, int last);\r
-int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);\r
-int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
-int lpc2000_probe(struct flash_bank_s *bank);\r
-int lpc2000_erase_check(struct flash_bank_s *bank);\r
-int lpc2000_protect_check(struct flash_bank_s *bank);\r
-int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
-       \r
-int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-\r
-flash_driver_t lpc2000_flash =\r
-{\r
-       .name = "lpc2000",\r
-       .register_commands = lpc2000_register_commands,\r
-       .flash_bank_command = lpc2000_flash_bank_command,\r
-       .erase = lpc2000_erase,\r
-       .protect = lpc2000_protect,\r
-       .write = lpc2000_write,\r
-       .probe = lpc2000_probe,\r
-       .auto_probe = lpc2000_probe,\r
-       .erase_check = lpc2000_erase_check,\r
-       .protect_check = lpc2000_protect_check,\r
-       .info = lpc2000_info\r
-};\r
-\r
-int lpc2000_register_commands(struct command_context_s *cmd_ctx)\r
-{\r
-       command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);\r
-       \r
-       register_command(cmd_ctx, lpc2000_cmd, "part_id", lpc2000_handle_part_id_command, COMMAND_EXEC,\r
-                                        "print part id of lpc2000 flash bank <num>");\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_build_sector_list(struct flash_bank_s *bank)\r
-{\r
-       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;\r
-       \r
-       /* default to a 4096 write buffer */\r
-       lpc2000_info->cmd51_max_buffer = 4096;\r
-       \r
-       if (lpc2000_info->variant == 1)\r
-       {\r
-               int i = 0;\r
-               u32 offset = 0;\r
-               \r
-               /* variant 1 has different layout for 128kb and 256kb flashes */\r
-               if (bank->size == 128 * 1024)\r
-               {\r
-                       bank->num_sectors = 16;\r
-                       bank->sectors = malloc(sizeof(flash_sector_t) * 16);\r
-                       for (i = 0; i < 16; i++)\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 8 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-               }\r
-               else if (bank->size == 256 * 1024)\r
-               {\r
-                       bank->num_sectors = 18;\r
-                       bank->sectors = malloc(sizeof(flash_sector_t) * 18);\r
-                       \r
-                       for (i = 0; i < 8; i++)\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 8 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-                       for (i = 8; i < 10; i++)\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 64 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-                       for (i = 10; i < 18; i++)\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 8 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       ERROR("BUG: unknown bank->size encountered");\r
-                       exit(-1);\r
-               }\r
-       }\r
-       else if (lpc2000_info->variant == 2)\r
-       {\r
-               int num_sectors;\r
-               int i;\r
-               u32 offset = 0;\r
-       \r
-               /* variant 2 has a uniform layout, only number of sectors differs */\r
-               switch (bank->size)\r
-               {\r
-                       case 4 * 1024:\r
-                               lpc2000_info->cmd51_max_buffer = 1024;\r
-                               num_sectors = 1;\r
-                               break;\r
-                       case 8 * 1024:\r
-                               lpc2000_info->cmd51_max_buffer = 1024;\r
-                               num_sectors = 2;\r
-                               break;\r
-                       case 16 * 1024:\r
-                               num_sectors = 4;\r
-                               break;\r
-                       case 32 * 1024:\r
-                               num_sectors = 8;\r
-                               break;\r
-                       case 64 * 1024:\r
-                               num_sectors = 9;\r
-                               break;\r
-                       case 128 * 1024:\r
-                               num_sectors = 11;\r
-                               break;\r
-                       case 256 * 1024:\r
-                               num_sectors = 15;\r
-                               break;\r
-                       case 512 * 1024:\r
-                       case 500 * 1024:\r
-                               num_sectors = 27;\r
-                               break;\r
-                       default:\r
-                               ERROR("BUG: unknown bank->size encountered");\r
-                               exit(-1);\r
-                               break;\r
-               }\r
-               \r
-               bank->num_sectors = num_sectors;\r
-               bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);\r
-               \r
-               for (i = 0; i < num_sectors; i++)\r
-               {\r
-                       if ((i >= 0) && (i < 8))\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 4 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-                       if ((i >= 8) && (i < 22))\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 32 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-                       if ((i >= 22) && (i < 27))\r
-                       {\r
-                               bank->sectors[i].offset = offset;\r
-                               bank->sectors[i].size = 4 * 1024;\r
-                               offset += bank->sectors[i].size;\r
-                               bank->sectors[i].is_erased = -1;\r
-                               bank->sectors[i].is_protected = 1;\r
-                       }\r
-               }\r
-       }\r
-       else\r
-       {\r
-               ERROR("BUG: unknown lpc2000_info->variant encountered");\r
-               exit(-1);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-/* call LPC2000 IAP function\r
- * uses 172 bytes working area\r
- * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)\r
- * 0x8 to 0x1f: command parameter table\r
- * 0x20 to 0x2b: command result table\r
- * 0x2c to 0xac: stack (only 128b needed)\r
- */\r
-int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 result_table[2])\r
-{\r
-       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-       mem_param_t mem_params[2];\r
-       reg_param_t reg_params[5];\r
-       armv4_5_algorithm_t armv4_5_info;\r
-       u32 status_code;\r
-       \r
-       /* regrab previously allocated working_area, or allocate a new one */\r
-       if (!lpc2000_info->iap_working_area)\r
-       {\r
-               u8 jump_gate[8];\r
-               \r
-               /* make sure we have a working area */\r
-               if (target_alloc_working_area(target, 172, &lpc2000_info->iap_working_area) != ERROR_OK)\r
-               {\r
-                       ERROR("no working area specified, can't write LPC2000 internal flash");\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-               }\r
-               \r
-               /* write IAP code to working area */\r
-               target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));\r
-               target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));\r
-               target->type->write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate);\r
-       }\r
-       \r
-       armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;\r
-       armv4_5_info.core_mode = ARMV4_5_MODE_SVC;\r
-       armv4_5_info.core_state = ARMV4_5_STATE_ARM;\r
-       \r
-       /* command parameter table */\r
-       init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 4 * 6, PARAM_OUT);\r
-       target_buffer_set_u32(target, mem_params[0].value, code);\r
-       target_buffer_set_u32(target, mem_params[0].value + 0x4, param_table[0]);\r
-       target_buffer_set_u32(target, mem_params[0].value + 0x8, param_table[1]);\r
-       target_buffer_set_u32(target, mem_params[0].value + 0xc, param_table[2]);\r
-       target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);\r
-       target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);\r
-       \r
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);\r
-       buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x8);\r
-       \r
-       /* command result table */\r
-       init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, PARAM_IN);\r
-       \r
-       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);\r
-       buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);\r
-       \r
-       /* IAP entry point */\r
-       init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);\r
-       buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);\r
-       \r
-       /* IAP stack */\r
-       init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);\r
-       buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xac);\r
-\r
-       /* return address */\r
-       init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);\r
-       buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x4);\r
-       \r
-       target->type->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);\r
-       \r
-       status_code = buf_get_u32(mem_params[1].value, 0, 32);\r
-       result_table[0] = target_buffer_get_u32(target, mem_params[1].value);\r
-       result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 4);\r
-       \r
-       destroy_mem_param(&mem_params[0]);\r
-       destroy_mem_param(&mem_params[1]);\r
-       \r
-       destroy_reg_param(&reg_params[0]);\r
-       destroy_reg_param(&reg_params[1]);\r
-       destroy_reg_param(&reg_params[2]);\r
-       destroy_reg_param(&reg_params[3]);\r
-       destroy_reg_param(&reg_params[4]);\r
-       \r
-       return status_code;\r
-}\r
-\r
-int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)\r
-{\r
-       u32 param_table[5];\r
-       u32 result_table[2];\r
-       int status_code;\r
-       int i;\r
-       \r
-       if ((first < 0) || (last > bank->num_sectors))\r
-               return ERROR_FLASH_SECTOR_INVALID;\r
-       \r
-       for (i = first; i <= last; i++)\r
-       {\r
-               /* check single sector */\r
-               param_table[0] = param_table[1] = i;\r
-               status_code = lpc2000_iap_call(bank, 53, param_table, result_table);\r
-               \r
-               switch (status_code)\r
-               {\r
-                       case ERROR_FLASH_OPERATION_FAILED:\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-                       case LPC2000_CMD_SUCCESS:\r
-                               bank->sectors[i].is_erased = 1;\r
-                               break;\r
-                       case LPC2000_SECTOR_NOT_BLANK:\r
-                               bank->sectors[i].is_erased = 0;\r
-                               break;\r
-                       case LPC2000_INVALID_SECTOR:\r
-                               bank->sectors[i].is_erased = 0;\r
-                               break;\r
-                       case LPC2000_BUSY:\r
-                               return ERROR_FLASH_BUSY;\r
-                               break;\r
-                       default:\r
-                               ERROR("BUG: unknown LPC2000 status code");\r
-                               exit(-1);\r
-               }\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-/* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]\r
- */\r
-int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
-{\r
-       lpc2000_flash_bank_t *lpc2000_info;\r
-       \r
-       if (argc < 8)\r
-       {\r
-               WARNING("incomplete flash_bank lpc2000 configuration");\r
-               return ERROR_FLASH_BANK_INVALID;\r
-       }\r
-       \r
-       lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));\r
-       bank->driver_priv = lpc2000_info;\r
-       \r
-       if (strcmp(args[6], "lpc2000_v1") == 0)\r
-       {\r
-               lpc2000_info->variant = 1;\r
-               lpc2000_info->cmd51_dst_boundary = 512;\r
-               lpc2000_info->cmd51_can_256b = 0;\r
-               lpc2000_info->cmd51_can_8192b = 1;\r
-       }\r
-       else if (strcmp(args[6], "lpc2000_v2") == 0)\r
-       {\r
-               lpc2000_info->variant = 2;\r
-               lpc2000_info->cmd51_dst_boundary = 256;\r
-               lpc2000_info->cmd51_can_256b = 1;\r
-               lpc2000_info->cmd51_can_8192b = 0;\r
-       }\r
-       else\r
-       {\r
-               ERROR("unknown LPC2000 variant");\r
-               free(lpc2000_info);\r
-               return ERROR_FLASH_BANK_INVALID;\r
-       }\r
-       \r
-       lpc2000_info->iap_working_area = NULL;\r
-       lpc2000_info->cclk = strtoul(args[7], NULL, 0);\r
-       lpc2000_info->calc_checksum = 0;\r
-       lpc2000_build_sector_list(bank);\r
-               \r
-       if (argc >= 9)\r
-       {\r
-               if (strcmp(args[8], "calc_checksum") == 0)\r
-                       lpc2000_info->calc_checksum = 1;\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_erase(struct flash_bank_s *bank, int first, int last)\r
-{\r
-       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;\r
-       u32 param_table[5];\r
-       u32 result_table[2];\r
-       int status_code;\r
-       \r
-       param_table[0] = first;\r
-       param_table[1] = last;\r
-       param_table[2] = lpc2000_info->cclk;\r
-       \r
-       /* Prepare sectors */\r
-       status_code = lpc2000_iap_call(bank, 50, param_table, result_table);\r
-       switch (status_code)\r
-       {\r
-               case ERROR_FLASH_OPERATION_FAILED:\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-               case LPC2000_CMD_SUCCESS:\r
-                       break;\r
-               case LPC2000_INVALID_SECTOR:\r
-                       return ERROR_FLASH_SECTOR_INVALID;\r
-                       break;\r
-               default:\r
-                       WARNING("lpc2000 prepare sectors returned %i", status_code);\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       /* Erase sectors */\r
-       status_code = lpc2000_iap_call(bank, 52, param_table, result_table);\r
-       switch (status_code)\r
-       {\r
-               case ERROR_FLASH_OPERATION_FAILED:\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-               case LPC2000_CMD_SUCCESS:\r
-                       break;\r
-               case LPC2000_INVALID_SECTOR:\r
-                       return ERROR_FLASH_SECTOR_INVALID;\r
-                       break;\r
-               default:\r
-                       WARNING("lpc2000 erase sectors returned %i", status_code);\r
-                       return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)\r
-{\r
-       /* can't protect/unprotect on the lpc2000 */\r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
-{\r
-       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;\r
-       target_t *target = bank->target;\r
-       u32 dst_min_alignment;\r
-       u32 bytes_remaining = count;\r
-       u32 bytes_written = 0;\r
-       int first_sector = 0;\r
-       int last_sector = 0;\r
-       u32 param_table[5];\r
-       u32 result_table[2];\r
-       int status_code;\r
-       int i;\r
-       working_area_t *download_area;\r
-                \r
-       /* allocate a working area */\r
-       if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK)\r
-       {\r
-               ERROR("no working area specified, can't write LPC2000 internal flash");\r
-               return ERROR_FLASH_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (offset + count > bank->size)\r
-               return ERROR_FLASH_DST_OUT_OF_BANK;\r
-       \r
-       if (lpc2000_info->cmd51_can_256b)\r
-               dst_min_alignment = 256;\r
-       else\r
-               dst_min_alignment = 512;\r
-       \r
-       if (offset % dst_min_alignment)\r
-       {\r
-               WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);\r
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
-       }\r
-       \r
-       for (i = 0; i < bank->num_sectors; i++)\r
-       {\r
-               if (offset >= bank->sectors[i].offset)\r
-                       first_sector = i;\r
-               if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)\r
-                       last_sector = i;\r
-       }\r
-       \r
-       DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);\r
-\r
-       /* check if exception vectors should be flashed */\r
-       if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)\r
-       {\r
-               u32 checksum = 0;\r
-               int i = 0;\r
-               for (i = 0; i < 8; i++)\r
-               {\r
-                       DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));\r
-                       if (i != 5)\r
-                               checksum += buf_get_u32(buffer + (i * 4), 0, 32);\r
-               }\r
-               checksum = 0 - checksum;\r
-               DEBUG("checksum: 0x%8.8x", checksum);\r
-               buf_set_u32(buffer + 0x14, 0, 32, checksum);\r
-       }\r
-       \r
-       while (bytes_remaining > 0)\r
-       {\r
-               u32 thisrun_bytes;\r
-               if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)\r
-                       thisrun_bytes = lpc2000_info->cmd51_max_buffer;\r
-               else if (bytes_remaining >= 1024)\r
-                       thisrun_bytes = 1024;\r
-               else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))\r
-                       thisrun_bytes = 512;\r
-               else\r
-                       thisrun_bytes = 256;\r
-               \r
-               /* Prepare sectors */\r
-               param_table[0] = first_sector;\r
-               param_table[1] = last_sector;\r
-               status_code = lpc2000_iap_call(bank, 50, param_table, result_table);\r
-               switch (status_code)\r
-               {\r
-                       case ERROR_FLASH_OPERATION_FAILED:\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-                       case LPC2000_CMD_SUCCESS:\r
-                               break;\r
-                       case LPC2000_INVALID_SECTOR:\r
-                               return ERROR_FLASH_SECTOR_INVALID;\r
-                               break;\r
-                       default:\r
-                               WARNING("lpc2000 prepare sectors returned %i", status_code);\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-               }\r
-               \r
-               if (bytes_remaining >= thisrun_bytes)\r
-               {\r
-                       if (target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written) != ERROR_OK)\r
-                       {\r
-                               target_free_working_area(target, download_area);\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       u8 *last_buffer = malloc(thisrun_bytes);\r
-                       int i;\r
-                       memcpy(last_buffer, buffer + bytes_written, bytes_remaining);\r
-                       for (i = bytes_remaining; i < thisrun_bytes; i++)\r
-                               last_buffer[i] = 0xff;\r
-                       target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);\r
-                       free(last_buffer);\r
-               }\r
-               \r
-               DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes, bank->base + offset + bytes_written);\r
-               \r
-               /* Write data */\r
-               param_table[0] = bank->base + offset + bytes_written;\r
-               param_table[1] = download_area->address;\r
-               param_table[2] = thisrun_bytes;\r
-               param_table[3] = lpc2000_info->cclk;\r
-               status_code = lpc2000_iap_call(bank, 51, param_table, result_table);\r
-               switch (status_code)\r
-               {\r
-                       case ERROR_FLASH_OPERATION_FAILED:\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-                       case LPC2000_CMD_SUCCESS:\r
-                               break;\r
-                       case LPC2000_INVALID_SECTOR:\r
-                               return ERROR_FLASH_SECTOR_INVALID;\r
-                               break;\r
-                       default:\r
-                               WARNING("lpc2000 returned %i", status_code);\r
-                               return ERROR_FLASH_OPERATION_FAILED;\r
-               }\r
-               \r
-               if (bytes_remaining > thisrun_bytes)\r
-                       bytes_remaining -= thisrun_bytes;\r
-               else\r
-                       bytes_remaining = 0;\r
-               bytes_written += thisrun_bytes;\r
-       }\r
-       \r
-       target_free_working_area(target, download_area);\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_probe(struct flash_bank_s *bank)\r
-{\r
-       /* we can't probe on an lpc2000 \r
-        * if this is an lpc2xxx, it has the configured flash\r
-        */\r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_erase_check(struct flash_bank_s *bank)\r
-{\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-       \r
-       return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);\r
-}\r
-\r
-int lpc2000_protect_check(struct flash_bank_s *bank)\r
-{\r
-       /* sectors are always protected */\r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
-{\r
-       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;\r
-\r
-       snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
-       flash_bank_t *bank;\r
-       u32 param_table[5];\r
-       u32 result_table[2];\r
-       int status_code;\r
-       lpc2000_flash_bank_t *lpc2000_info;\r
-\r
-       if (argc < 1)\r
-       {\r
+/***************************************************************************
+ *   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.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lpc2000.h"
+
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* flash programming support for Philips 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
+ */
+
+int lpc2000_register_commands(struct command_context_s *cmd_ctx);
+int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
+int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
+int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int lpc2000_probe(struct flash_bank_s *bank);
+int lpc2000_erase_check(struct flash_bank_s *bank);
+int lpc2000_protect_check(struct flash_bank_s *bank);
+int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
+       
+int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+flash_driver_t lpc2000_flash =
+{
+       .name = "lpc2000",
+       .register_commands = lpc2000_register_commands,
+       .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
+};
+
+int lpc2000_register_commands(struct command_context_s *cmd_ctx)
+{
+       command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);
+       
+       register_command(cmd_ctx, lpc2000_cmd, "part_id", lpc2000_handle_part_id_command, COMMAND_EXEC,
+                                        "print part id of lpc2000 flash bank <num>");
+       
+       return ERROR_OK;
+}
+
+int lpc2000_build_sector_list(struct flash_bank_s *bank)
+{
+       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+       
+       /* default to a 4096 write buffer */
+       lpc2000_info->cmd51_max_buffer = 4096;
+       
+       if (lpc2000_info->variant == 1)
+       {
+               int i = 0;
+               u32 offset = 0;
+               
+               /* variant 1 has different layout for 128kb and 256kb flashes */
+               if (bank->size == 128 * 1024)
+               {
+                       bank->num_sectors = 16;
+                       bank->sectors = malloc(sizeof(flash_sector_t) * 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(flash_sector_t) * 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
+               {
+                       ERROR("BUG: unknown bank->size encountered");
+                       exit(-1);
+               }
+       }
+       else if (lpc2000_info->variant == 2)
+       {
+               int num_sectors;
+               int i;
+               u32 offset = 0;
+       
+               /* variant 2 has a uniform layout, only number of sectors differs */
+               switch (bank->size)
+               {
+                       case 4 * 1024:
+                               lpc2000_info->cmd51_max_buffer = 1024;
+                               num_sectors = 1;
+                               break;
+                       case 8 * 1024:
+                               lpc2000_info->cmd51_max_buffer = 1024;
+                               num_sectors = 2;
+                               break;
+                       case 16 * 1024:
+                               num_sectors = 4;
+                               break;
+                       case 32 * 1024:
+                               num_sectors = 8;
+                               break;
+                       case 64 * 1024:
+                               num_sectors = 9;
+                               break;
+                       case 128 * 1024:
+                               num_sectors = 11;
+                               break;
+                       case 256 * 1024:
+                               num_sectors = 15;
+                               break;
+                       case 512 * 1024:
+                       case 500 * 1024:
+                               num_sectors = 27;
+                               break;
+                       default:
+                               ERROR("BUG: unknown bank->size encountered");
+                               exit(-1);
+                               break;
+               }
+               
+               bank->num_sectors = num_sectors;
+               bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+               
+               for (i = 0; i < 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
+       {
+               ERROR("BUG: unknown lpc2000_info->variant encountered");
+               exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+/* call LPC2000 IAP function
+ * uses 172 bytes working area
+ * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
+ * 0x8 to 0x1f: command parameter table
+ * 0x20 to 0x2b: command result table
+ * 0x2c to 0xac: stack (only 128b needed)
+ */
+int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 result_table[2])
+{
+       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+       target_t *target = bank->target;
+       mem_param_t mem_params[2];
+       reg_param_t reg_params[5];
+       armv4_5_algorithm_t armv4_5_info;
+       u32 status_code;
+       
+       /* regrab previously allocated working_area, or allocate a new one */
+       if (!lpc2000_info->iap_working_area)
+       {
+               u8 jump_gate[8];
+               
+               /* make sure we have a working area */
+               if (target_alloc_working_area(target, 172, &lpc2000_info->iap_working_area) != ERROR_OK)
+               {
+                       ERROR("no working area specified, can't write LPC2000 internal flash");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               
+               /* write IAP code to working area */
+               target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
+               target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
+               target->type->write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate);
+       }
+       
+       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;
+       
+       /* command parameter table */
+       init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 4 * 6, PARAM_OUT);
+       target_buffer_set_u32(target, mem_params[0].value, code);
+       target_buffer_set_u32(target, mem_params[0].value + 0x4, param_table[0]);
+       target_buffer_set_u32(target, mem_params[0].value + 0x8, param_table[1]);
+       target_buffer_set_u32(target, mem_params[0].value + 0xc, 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 + 0x8);
+       
+       /* command result table */
+       init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, 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, 0x7ffffff1);
+       
+       /* 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 + 0xac);
+
+       /* 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 + 0x4);
+       
+       target->type->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);
+       
+       status_code = buf_get_u32(mem_params[1].value, 0, 32);
+       result_table[0] = target_buffer_get_u32(target, mem_params[1].value);
+       result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 4);
+       
+       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;
+}
+
+int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
+{
+       u32 param_table[5];
+       u32 result_table[2];
+       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:
+                               ERROR("BUG: unknown LPC2000 status code");
+                               exit(-1);
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+/* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
+ */
+int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+       lpc2000_flash_bank_t *lpc2000_info;
+       
+       if (argc < 8)
+       {
+               WARNING("incomplete flash_bank lpc2000 configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       
+       lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
+       bank->driver_priv = lpc2000_info;
+       
+       if (strcmp(args[6], "lpc2000_v1") == 0)
+       {
+               lpc2000_info->variant = 1;
+               lpc2000_info->cmd51_dst_boundary = 512;
+               lpc2000_info->cmd51_can_256b = 0;
+               lpc2000_info->cmd51_can_8192b = 1;
+       }
+       else if (strcmp(args[6], "lpc2000_v2") == 0)
+       {
+               lpc2000_info->variant = 2;
+               lpc2000_info->cmd51_dst_boundary = 256;
+               lpc2000_info->cmd51_can_256b = 1;
+               lpc2000_info->cmd51_can_8192b = 0;
+       }
+       else
+       {
+               ERROR("unknown LPC2000 variant");
+               free(lpc2000_info);
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       
+       lpc2000_info->iap_working_area = NULL;
+       lpc2000_info->cclk = strtoul(args[7], NULL, 0);
+       lpc2000_info->calc_checksum = 0;
+       lpc2000_build_sector_list(bank);
+               
+       if (argc >= 9)
+       {
+               if (strcmp(args[8], "calc_checksum") == 0)
+                       lpc2000_info->calc_checksum = 1;
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
+{
+       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+       u32 param_table[5];
+       u32 result_table[2];
+       int status_code;
+       
+       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:
+                       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:
+                       WARNING("lpc2000 erase sectors returned %i", status_code);
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+       /* can't protect/unprotect on the lpc2000 */
+       return ERROR_OK;
+}
+
+int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+       target_t *target = bank->target;
+       u32 dst_min_alignment;
+       u32 bytes_remaining = count;
+       u32 bytes_written = 0;
+       int first_sector = 0;
+       int last_sector = 0;
+       u32 param_table[5];
+       u32 result_table[2];
+       int status_code;
+       int i;
+       working_area_t *download_area;
+                
+       /* allocate a working area */
+       if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK)
+       {
+               ERROR("no working area specified, can't write LPC2000 internal flash");
+               return ERROR_FLASH_OPERATION_FAILED;
+       }
+       
+       if (offset + count > bank->size)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+       
+       if (lpc2000_info->cmd51_can_256b)
+               dst_min_alignment = 256;
+       else
+               dst_min_alignment = 512;
+       
+       if (offset % dst_min_alignment)
+       {
+               WARNING("offset 0x%x breaks required alignment 0x%x", 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 + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
+                       last_sector = i;
+       }
+       
+       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)
+       {
+               u32 checksum = 0;
+               int i = 0;
+               for (i = 0; i < 8; i++)
+               {
+                       DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
+                       if (i != 5)
+                               checksum += buf_get_u32(buffer + (i * 4), 0, 32);
+               }
+               checksum = 0 - checksum;
+               DEBUG("checksum: 0x%8.8x", checksum);
+               buf_set_u32(buffer + 0x14, 0, 32, checksum);
+       }
+       
+       while (bytes_remaining > 0)
+       {
+               u32 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:
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       case LPC2000_CMD_SUCCESS:
+                               break;
+                       case LPC2000_INVALID_SECTOR:
+                               return ERROR_FLASH_SECTOR_INVALID;
+                               break;
+                       default:
+                               WARNING("lpc2000 prepare sectors returned %i", status_code);
+                               return ERROR_FLASH_OPERATION_FAILED;
+               }
+               
+               if (bytes_remaining >= thisrun_bytes)
+               {
+                       if (target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written) != ERROR_OK)
+                       {
+                               target_free_working_area(target, download_area);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       u8 *last_buffer = malloc(thisrun_bytes);
+                       int i;
+                       memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
+                       for (i = bytes_remaining; i < thisrun_bytes; i++)
+                               last_buffer[i] = 0xff;
+                       target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
+                       free(last_buffer);
+               }
+               
+               DEBUG("writing 0x%x bytes to address 0x%x", 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:
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       case LPC2000_CMD_SUCCESS:
+                               break;
+                       case LPC2000_INVALID_SECTOR:
+                               return ERROR_FLASH_SECTOR_INVALID;
+                               break;
+                       default:
+                               WARNING("lpc2000 returned %i", status_code);
+                               return ERROR_FLASH_OPERATION_FAILED;
+               }
+               
+               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 ERROR_OK;
+}
+
+int lpc2000_probe(struct flash_bank_s *bank)
+{
+       /* we can't probe on an lpc2000 
+        * if this is an lpc2xxx, it has the configured flash
+        */
+       return ERROR_OK;
+}
+
+int lpc2000_erase_check(struct flash_bank_s *bank)
+{
+       if (bank->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+int lpc2000_protect_check(struct flash_bank_s *bank)
+{
+       /* sectors are always protected */
+       return ERROR_OK;
+}
+
+int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+       lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+
+       snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);
+       
+       return ERROR_OK;
+}
+
+int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       flash_bank_t *bank;
+       u32 param_table[5];
+       u32 result_table[2];
+       int status_code;
+       lpc2000_flash_bank_t *lpc2000_info;
+
+       if (argc < 1)
+       {
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }\r
-       \r
-       bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
-       if (!bank)\r
-       {\r
-               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
-               return ERROR_OK;\r
-       }\r
-\r
-       lpc2000_info = bank->driver_priv;\r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-       \r
-       if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)\r
-       {\r
-               if (status_code == ERROR_FLASH_OPERATION_FAILED)\r
-               {\r
-                       command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");\r
-                       return ERROR_OK;\r
-               }\r
-               command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);\r
-       }\r
-       else\r
-       {\r
-               command_print(cmd_ctx, "lpc2000 part id: 0x%8.8x", result_table[0]);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
+       }
+       
+       bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+       if (!bank)
+       {
+               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+               return ERROR_OK;
+       }
+
+       lpc2000_info = bank->driver_priv;
+       if (bank->target->state != TARGET_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.8x", result_table[0]);
+       }
+       
+       return ERROR_OK;
+}
index 4e1fd2e..2874f62 100644 (file)
-/***************************************************************************\r
- *   Copyright (C) 2007 by Dominic Rath                                    *\r
- *   Dominic.Rath@gmx.de                                                   *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
- ***************************************************************************/\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "lpc3180_nand_controller.h"\r
-\r
-#include "replacements.h"\r
-#include "log.h"\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#include "nand.h"\r
-#include "target.h"\r
-\r
-int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);\r
-int lpc3180_register_commands(struct command_context_s *cmd_ctx);\r
-int lpc3180_init(struct nand_device_s *device);\r
-int lpc3180_reset(struct nand_device_s *device);\r
-int lpc3180_command(struct nand_device_s *device, u8 command);\r
-int lpc3180_address(struct nand_device_s *device, u8 address);\r
-int lpc3180_write_data(struct nand_device_s *device, u16 data);\r
-int lpc3180_read_data(struct nand_device_s *device, void *data);\r
-int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);\r
-int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);\r
-int lpc3180_controller_ready(struct nand_device_s *device, int timeout);\r
-int lpc3180_nand_ready(struct nand_device_s *device, int timeout);\r
-\r
-int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-\r
-nand_flash_controller_t lpc3180_nand_controller =\r
-{\r
-       .name = "lpc3180",\r
-       .nand_device_command = lpc3180_nand_device_command,\r
-       .register_commands = lpc3180_register_commands,\r
-       .init = lpc3180_init,\r
-       .reset = lpc3180_reset,\r
-       .command = lpc3180_command,\r
-       .address = lpc3180_address,\r
-       .write_data = lpc3180_write_data,\r
-       .read_data = lpc3180_read_data,\r
-       .write_page = lpc3180_write_page,\r
-       .read_page = lpc3180_read_page,\r
-       .controller_ready = lpc3180_controller_ready,\r
-       .nand_ready = lpc3180_nand_ready,\r
-};\r
-\r
-/* nand device lpc3180 <target#> <oscillator_frequency>\r
- */\r
-int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info;\r
-               \r
-       if (argc < 3)\r
-       {\r
-               WARNING("incomplete 'lpc3180' nand flash configuration");\r
-               return ERROR_FLASH_BANK_INVALID;\r
-       }\r
-       \r
-       lpc3180_info = malloc(sizeof(lpc3180_nand_controller_t));\r
-       device->controller_priv = lpc3180_info;\r
-\r
-       lpc3180_info->target = get_target_by_num(strtoul(args[1], NULL, 0));\r
-       if (!lpc3180_info->target)\r
-       {\r
-               ERROR("no target '%s' configured", args[1]);\r
-               return ERROR_NAND_DEVICE_INVALID;\r
-       }\r
-\r
-       lpc3180_info->osc_freq = strtoul(args[2], NULL, 0);\r
-       if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))\r
-       {\r
-               WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); \r
-       }\r
-       lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER;\r
-       lpc3180_info->sw_write_protection = 0;\r
-       lpc3180_info->sw_wp_lower_bound = 0x0;\r
-       lpc3180_info->sw_wp_upper_bound = 0x0;\r
-               \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_register_commands(struct command_context_s *cmd_ctx)\r
-{\r
-       command_t *lpc3180_cmd = register_command(cmd_ctx, NULL, "lpc3180", NULL, COMMAND_ANY, "commands specific to the LPC3180 NAND flash controllers");\r
-       \r
-       register_command(cmd_ctx, lpc3180_cmd, "select", handle_lpc3180_select_command, COMMAND_EXEC, "select <'mlc'|'slc'> controller (default is mlc)");\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_pll(int fclkin, u32 pll_ctrl)\r
-{\r
-       int bypass = (pll_ctrl & 0x8000) >> 15;\r
-       int direct = (pll_ctrl & 0x4000) >> 14;\r
-       int feedback = (pll_ctrl & 0x2000) >> 13;\r
-       int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2);\r
-       int n = ((pll_ctrl & 0x0600) >> 9) + 1;\r
-       int m = ((pll_ctrl & 0x01fe) >> 1) + 1;\r
-       int lock = (pll_ctrl & 0x1);\r
-\r
-       if (!lock)\r
-               WARNING("PLL is not locked");\r
-       \r
-       if (!bypass && direct)  /* direct mode */\r
-               return (m * fclkin) / n;\r
-       \r
-       if (bypass && !direct)  /* bypass mode */\r
-               return fclkin / (2 * p);\r
-               \r
-       if (bypass & direct)    /* direct bypass mode */\r
-               return fclkin;\r
-       \r
-       if (feedback)                   /* integer mode */\r
-               return m * (fclkin / n);\r
-       else                                    /* non-integer mode */\r
-               return (m / (2 * p)) * (fclkin / n); \r
-}\r
-\r
-float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)\r
-{\r
-       target_t *target = lpc3180_info->target;\r
-       u32 sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;\r
-       int sysclk;\r
-       int hclk;\r
-       int hclk_pll;\r
-       float cycle;\r
-       \r
-       /* calculate timings */\r
-       \r
-       /* determine current SYSCLK (13'MHz or main oscillator) */ \r
-       target_read_u32(target, 0x40004050, &sysclk_ctrl);\r
-       \r
-       if ((sysclk_ctrl & 1) == 0)\r
-               sysclk = lpc3180_info->osc_freq;\r
-       else\r
-               sysclk = 13000;\r
-       \r
-       /* determine selected HCLK source */\r
-       target_read_u32(target, 0x40004044, &pwr_ctrl);\r
-       \r
-       if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */\r
-       {\r
-               hclk = sysclk;\r
-       }\r
-       else\r
-       {\r
-               target_read_u32(target, 0x40004058, &hclkpll_ctrl);\r
-               hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl);\r
-\r
-               target_read_u32(target, 0x40004040, &hclkdiv_ctrl);\r
-               \r
-               if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */\r
-               {\r
-                       hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1);\r
-               }\r
-               else /* HCLK uses HCLK_PLL */\r
-               {\r
-                       hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); \r
-               }\r
-       }\r
-       \r
-       DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk);\r
-       \r
-       cycle = (1.0 / hclk) * 1000000.0;\r
-       \r
-       return cycle;\r
-}\r
-\r
-int lpc3180_init(struct nand_device_s *device)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       int bus_width = (device->bus_width) ? (device->bus_width) : 8;\r
-       int address_cycles = (device->address_cycles) ? (device->address_cycles) : 3;\r
-       int page_size = (device->page_size) ? (device->page_size) : 512;\r
-               \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       /* sanitize arguments */\r
-       if ((bus_width != 8) && (bus_width != 16))\r
-       {\r
-               ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width);\r
-               return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-       }\r
-       \r
-       /* The LPC3180 only brings out 8 bit NAND data bus, but the controller\r
-        * would support 16 bit, too, so we just warn about this for now\r
-        */\r
-       if (bus_width == 16)\r
-       {\r
-               WARNING("LPC3180 only supports 8 bit bus width");\r
-       }\r
-       \r
-       /* inform calling code about selected bus width */\r
-       device->bus_width = bus_width;\r
-       \r
-       if ((address_cycles != 3) && (address_cycles != 4))\r
-       {\r
-               ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles);\r
-               return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-       }\r
-       \r
-       if ((page_size != 512) && (page_size != 2048))\r
-       {\r
-               ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size);\r
-               return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-       }\r
-       \r
-       /* select MLC controller if none is currently selected */\r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'");\r
-               lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               u32 mlc_icr_value = 0x0;\r
-               float cycle;\r
-               int twp, twh, trp, treh, trhz, trbwb, tcea;\r
-               \r
-               /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */\r
-               target_write_u32(target, 0x400040c8, 0x22);\r
-               \r
-               /* MLC_CEH = 0x0 (Force nCE assert) */\r
-               target_write_u32(target, 0x200b804c, 0x0);\r
-               \r
-               /* MLC_LOCK = 0xa25e (unlock protected registers) */\r
-               target_write_u32(target, 0x200b8044, 0xa25e);\r
-               \r
-               /* MLC_ICR = configuration */\r
-               if (lpc3180_info->sw_write_protection)\r
-                       mlc_icr_value |= 0x8;\r
-               if (page_size == 2048)\r
-                       mlc_icr_value |= 0x4;\r
-               if (address_cycles == 4)\r
-                       mlc_icr_value |= 0x2;\r
-               if (bus_width == 16)\r
-                       mlc_icr_value |= 0x1;\r
-               target_write_u32(target, 0x200b8030, mlc_icr_value);\r
-               \r
-               /* calculate NAND controller timings */\r
-               cycle = lpc3180_cycle_time(lpc3180_info);\r
-               \r
-               twp = ((40 / cycle) + 1);\r
-               twh = ((20 / cycle) + 1);\r
-               trp = ((30 / cycle) + 1);\r
-               treh = ((15 / cycle) + 1);\r
-               trhz = ((30 / cycle) + 1);\r
-               trbwb = ((100 / cycle) + 1);\r
-               tcea = ((45 / cycle) + 1);\r
-                               \r
-               /* MLC_LOCK = 0xa25e (unlock protected registers) */\r
-               target_write_u32(target, 0x200b8044, 0xa25e);\r
-       \r
-               /* MLC_TIME_REG */\r
-               target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | \r
-                       ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | \r
-                       ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); \r
-\r
-               lpc3180_reset(device);\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               float cycle;\r
-               int r_setup, r_hold, r_width, r_rdy;\r
-               int w_setup, w_hold, w_width, w_rdy;\r
-               \r
-               /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */\r
-               target_write_u32(target, 0x400040c8, 0x05);\r
-               \r
-               /* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */\r
-               target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0);\r
-               \r
-               /* calculate NAND controller timings */\r
-               cycle = lpc3180_cycle_time(lpc3180_info);\r
-               \r
-               r_setup = w_setup = 0;\r
-               r_hold = w_hold = 10 / cycle;\r
-               r_width = 30 / cycle;\r
-               w_width = 40 / cycle;\r
-               r_rdy = w_rdy = 100 / cycle;\r
-               \r
-               /* SLC_TAC: SLC timing arcs register */\r
-               target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) |\r
-                       ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) |  ((w_setup & 0xf) << 16) |\r
-                       ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); \r
-               \r
-               lpc3180_reset(device);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_reset(struct nand_device_s *device)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               /* MLC_CMD = 0xff (reset controller and NAND device) */\r
-               target_write_u32(target, 0x200b8000, 0xff);\r
-\r
-               if (!lpc3180_controller_ready(device, 100))\r
-               {\r
-                       ERROR("LPC3180 NAND controller timed out after reset");\r
-                       return ERROR_NAND_OPERATION_TIMEOUT;\r
-               }\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */\r
-               target_write_u32(target, 0x20020010, 0x6);\r
-               \r
-               if (!lpc3180_controller_ready(device, 100))\r
-               {\r
-                       ERROR("LPC3180 NAND controller timed out after reset");\r
-                       return ERROR_NAND_OPERATION_TIMEOUT;\r
-               }\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_command(struct nand_device_s *device, u8 command)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               /* MLC_CMD = command */\r
-               target_write_u32(target, 0x200b8000, command);\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               /* SLC_CMD = command */\r
-               target_write_u32(target, 0x20020008, command);\r
-       }       \r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_address(struct nand_device_s *device, u8 address)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               /* MLC_ADDR = address */\r
-               target_write_u32(target, 0x200b8004, address);\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               /* SLC_ADDR = address */\r
-               target_write_u32(target, 0x20020004, address);\r
-       }\r
-               \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_write_data(struct nand_device_s *device, u16 data)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               /* MLC_DATA = data */\r
-               target_write_u32(target, 0x200b0000, data);\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               /* SLC_DATA = data */\r
-               target_write_u32(target, 0x20020000, data);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_read_data(struct nand_device_s *device, void *data)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               /* data = MLC_DATA, use sized access */\r
-               if (device->bus_width == 8)\r
-               {\r
-                       u8 *data8 = data;\r
-                       target_read_u8(target, 0x200b0000, data8);\r
-               }\r
-               else if (device->bus_width == 16)\r
-               {\r
-                       u16 *data16 = data;\r
-                       target_read_u16(target, 0x200b0000, data16);\r
-               }\r
-               else\r
-               {\r
-                       ERROR("BUG: bus_width neither 8 nor 16 bit");\r
-                       return ERROR_NAND_OPERATION_FAILED;\r
-               }\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               u32 data32;\r
-\r
-               /* data = SLC_DATA, must use 32-bit access */\r
-               target_read_u32(target, 0x20020000, &data32);\r
-               \r
-               if (device->bus_width == 8)\r
-               {\r
-                       u8 *data8 = data;\r
-                       *data8 = data32 & 0xff;\r
-               }\r
-               else if (device->bus_width == 16)\r
-               {\r
-                       u16 *data16 = data;\r
-                       *data16 = data32 & 0xffff;\r
-               }\r
-               else\r
-               {\r
-                       ERROR("BUG: bus_width neither 8 nor 16 bit");\r
-                       return ERROR_NAND_OPERATION_FAILED;\r
-               }\r
-       }       \r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       int retval;\r
-       u8 status;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               u8 *page_buffer;\r
-               u8 *oob_buffer;\r
-               int quarter, num_quarters;\r
-               \r
-               if (!data && oob)\r
-               {\r
-                       ERROR("LPC3180 MLC controller can't write OOB data only");\r
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-               }\r
-               \r
-               if (oob && (oob_size > 6))\r
-               {\r
-                       ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data");\r
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-               }\r
-               \r
-               if (data_size > device->page_size)\r
-               {\r
-                       ERROR("data size exceeds page size");\r
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-               }\r
-               \r
-               /* MLC_CMD = sequential input */\r
-               target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN);\r
-\r
-               page_buffer = malloc(512);\r
-               oob_buffer = malloc(6);         \r
-\r
-               if (device->page_size == 512)\r
-               {\r
-                       /* MLC_ADDR = 0x0 (one column cycle) */\r
-                       target_write_u32(target, 0x200b8004, 0x0);\r
-\r
-                       /* MLC_ADDR = row */\r
-                       target_write_u32(target, 0x200b8004, page & 0xff);\r
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
-                       \r
-                       if (device->address_cycles == 4)\r
-                               target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);\r
-               }\r
-               else\r
-               {\r
-                       /* MLC_ADDR = 0x0 (two column cycles) */\r
-                       target_write_u32(target, 0x200b8004, 0x0);\r
-                       target_write_u32(target, 0x200b8004, 0x0);\r
-\r
-                       /* MLC_ADDR = row */\r
-                       target_write_u32(target, 0x200b8004, page & 0xff);\r
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
-               }\r
-               \r
-               /* when using the MLC controller, we have to treat a large page device\r
-                * as being made out of four quarters, each the size of a small page device\r
-                */\r
-               num_quarters = (device->page_size == 2048) ? 4 : 1;\r
-                \r
-               for (quarter = 0; quarter < num_quarters; quarter++)\r
-               {\r
-                       int thisrun_data_size = (data_size > 512) ? 512 : data_size;\r
-                       int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size;\r
-                       \r
-                       memset(page_buffer, 0xff, 512);\r
-                       if (data)\r
-                       {\r
-                               memcpy(page_buffer, data, thisrun_data_size);\r
-                               data_size -= thisrun_data_size;\r
-                               data += thisrun_data_size;\r
-                       }\r
-                       \r
-                       memset(oob_buffer, 0xff, (device->page_size == 512) ? 6 : 24);\r
-                       if (oob)\r
-                       {\r
-                               memcpy(page_buffer, oob, thisrun_oob_size);\r
-                               oob_size -= thisrun_oob_size;\r
-                               oob += thisrun_oob_size;\r
-                       }\r
-                       \r
-                       /* write MLC_ECC_ENC_REG to start encode cycle */\r
-                       target_write_u32(target, 0x200b8008, 0x0);\r
-                       \r
-                       target->type->write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));\r
-                       target->type->write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));\r
-                       \r
-                       /* write MLC_ECC_AUTO_ENC_REG to start auto encode */\r
-                       target_write_u32(target, 0x200b8010, 0x0);\r
-                       \r
-                       if (!lpc3180_controller_ready(device, 1000))\r
-                       {\r
-                               ERROR("timeout while waiting for completion of auto encode cycle");\r
-                               return ERROR_NAND_OPERATION_FAILED;\r
-                       }\r
-               }\r
-               \r
-               /* MLC_CMD = auto program command */\r
-               target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG);\r
-               \r
-               if ((retval = nand_read_status(device, &status)) != ERROR_OK)\r
-               {\r
-                       ERROR("couldn't read status");\r
-                       return ERROR_NAND_OPERATION_FAILED;\r
-               }\r
-                       \r
-               if (status & NAND_STATUS_FAIL)\r
-               {\r
-                       ERROR("write operation didn't pass, status: 0x%2.2x", status);\r
-                       return ERROR_NAND_OPERATION_FAILED;\r
-               }\r
-       \r
-               free(page_buffer);\r
-               free(oob_buffer);\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
-       {\r
-               return nand_write_page_raw(device, page, data, data_size, oob, oob_size);\r
-       }\r
-       \r
-       return ERROR_OK;\r
-}\r
-\r
-int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
-{\r
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
-       target_t *target = lpc3180_info->target;\r
-       \r
-       if (target->state != TARGET_HALTED)\r
-       {\r
-               ERROR("target must be halted to use LPC3180 NAND flash controller");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       \r
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
-       {\r
-               ERROR("BUG: no LPC3180 NAND flash controller selected");\r
-               return ERROR_NAND_OPERATION_FAILED;\r
-       }\r
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
-       {\r
-               u8 *page_buffer;\r
-               u8 *oob_buffer;\r
-               u32 page_bytes_done = 0;\r
-               u32 oob_bytes_done = 0;\r
-               u32 mlc_isr;\r
-\r
-#if 0\r
-               if (oob && (oob_size > 6))\r
-               {\r
-                       ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data");\r
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-               }\r
-#endif\r
-               \r
-               if (data_size > device->page_size)\r
-               {\r
-                       ERROR("data size exceeds page size");\r
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
-               }\r
-               \r
-               if (device->page_size == 2048)\r
-               {\r
-                       page_buffer = malloc(2048);\r
-                       oob_buffer = malloc(64);\r
-               }\r
-               else\r
-               {\r
-                       page_buffer = malloc(512);\r
-                       oob_buffer = malloc(16);\r
-               }\r
-               \r
-               if (!data && oob)\r
-               {\r
-                       /* MLC_CMD = Read OOB \r
-                        * we can use the READOOB command on both small and large page devices,\r
-                        * as the controller translates the 0x50 command to a 0x0 with appropriate\r
-                        * positioning of the serial buffer read pointer\r
-                        */\r
-                       target_write_u32(target, 0x200b8000, NAND_CMD_READOOB);\r
-               }\r
-               else\r
-               {\r
-                       /* MLC_CMD = Read0 */\r
-                       target_write_u32(target, 0x200b8000, NAND_CMD_READ0);\r
-               }\r
-               \r
-               if (device->page_size == 512)\r
-               {\r
-                       /* small page device */\r
-                       /* MLC_ADDR = 0x0 (one column cycle) */\r
-                       target_write_u32(target, 0x200b8004, 0x0);\r
-\r
-                       /* MLC_ADDR = row */\r
-                       target_write_u32(target, 0x200b8004, page & 0xff);\r
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
-                       \r
-                       if (device->address_cycles == 4)\r
-                               target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);\r
-               }