- "flash write_binary" is now "flash write_bank" to clarify the focus of the
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 25 Feb 2008 07:32:52 +0000 (07:32 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 25 Feb 2008 07:32:52 +0000 (07:32 +0000)
 command and reduce confusion with "flash write_image".
- retired deprecated "flash erase" & "flash write".
- added flash_driver_protect/write/erase() that are wafer thin frontend
 functions to low level driver functions. They implement checks
 that were inconsistently handled by the drivers, e.g. check for
 target halted was done in a spotty fashion.
- use return ERROR_COMMAND_SYNTAX_ERROR to print out
 syntax of command instead of having lots of inlined replicas of
 the command line syntax(some of which were wrong).
- use logging instead of dubious translation of error values to
 human understandable explanations of why things failed.
 The lower levels log the precise reason and the higher
 levels can ammend context as the error propagates up
 the call stack.
- simplified flash API slightly with logging instead of
 allocating and returning information that the caller then
 has to translate into print statements.

git-svn-id: svn://svn.berlios.de/openocd/trunk@337 b42882b7-edfa-0310-969c-e2dbd0fdcd60

15 files changed:
src/flash/at91sam7.c
src/flash/cfi.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
src/target/target.h

index f552900d70e0cff9c5af485a95e03187e79f364f..3e920e3d7e58cf2087a4824f2a533ef090bdc3fc 100644 (file)
-/***************************************************************************
- *   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 (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 (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
-       {
-               command_print(cmd_ctx, "usage: at91sam7 gpnvm <num> <bit> <set|clear>");
-               return ERROR_OK;
-       }
-
-       /* 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;
-}
+/***************************************************************************\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
+               command_print(cmd_ctx, "usage: at91sam7 gpnvm <num> <bit> <set|clear>");\r
+               return ERROR_OK;\r
+       }\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
index 66a1c6565ade4e3991e7f3ae96319ac0ea0d247c..82120d8d2e16d7896e0d9b00031c04df27c38505 100644 (file)
@@ -1375,11 +1375,11 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
                }\r
 \r
                /* allocate working area */\r
-               if (target_alloc_working_area(target, 24 * 4,\r
-                       &cfi_info->write_algorithm) != ERROR_OK)\r
+               retval=target_alloc_working_area(target, 24 * 4,\r
+                               &cfi_info->write_algorithm);\r
+               if (retval != ERROR_OK)\r
                {\r
-                       WARNING("no working area available, can't do block memory writes");\r
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+                       return retval;\r
                }\r
 \r
                /* write algorithm code to working area */\r
@@ -1645,11 +1645,6 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
        int i;\r
        int retval;\r
 \r
-       if (bank->target->state != TARGET_HALTED)\r
-       {\r
-               return ERROR_TARGET_NOT_HALTED;\r
-       }\r
-\r
        if (offset + count > bank->size)\r
                return ERROR_FLASH_DST_OUT_OF_BANK;\r
 \r
index dc87f5dd3d1ae5261d668220d09fcc4f9e7c2f9b..416cac44c5fdf826c0f936bdfef6f7107c6bf591 100644 (file)
-/***************************************************************************
- *   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_binary_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;
-
-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", handle_flash_erase_command, COMMAND_EXEC,
-                                                "DEPRECATED, use 'erase_sector' instead");
-               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", handle_flash_write_binary_command, COMMAND_EXEC,
-                                                "DEPRECATED, use 'write_binary' instead");
-               register_command(cmd_ctx, flash_cmd, "write_binary", handle_flash_write_binary_command, COMMAND_EXEC,
-                                                "write binary <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;
-               }
-       }
-       
-       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)
-       {
-               command_print(cmd_ctx, "usage: flash info <num>");
-               return ERROR_OK;
-       }
-       
-       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)
-       {
-               command_print(cmd_ctx, "usage: flash probe <num>");
-               return ERROR_OK;
-       }
-       
-       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)
-       {
-               command_print(cmd_ctx, "usage: flash erase_check <num>");
-               return ERROR_OK;
-       }
-       
-       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);
-               }
-       }
-       else
-       {
-               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
-       }
-       
-       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)
-       {
-               command_print(cmd_ctx, "usage: flash erase_address <address> <length>");
-               return ERROR_OK;
-       }
-       
-       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_INVALID_ARGUMENTS;
-       }
-
-       p = get_flash_bank_by_addr(target, address);
-       if (p == NULL)
-       {
-               command_print(cmd_ctx, "No flash at that address");
-               return ERROR_INVALID_ARGUMENTS;
-       }
-       
-       /* 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)
-       {
-               switch (retval)
-               {
-                       case ERROR_TARGET_NOT_HALTED:
-                               command_print(cmd_ctx, "can't work with this flash while target is running");
-                               break;
-                       case ERROR_INVALID_ARGUMENTS:
-                               command_print(cmd_ctx, "usage: flash erase_address <address> <length>");
-                               break;
-                       case ERROR_FLASH_BANK_INVALID:
-                               command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
-                               break;
-                       case ERROR_FLASH_OPERATION_FAILED:
-                               command_print(cmd_ctx, "flash erase error");
-                               break;
-                       case ERROR_FLASH_SECTOR_INVALID:
-                               command_print(cmd_ctx, "sector number(s) invalid");
-                               break;
-                       default:
-                               command_print(cmd_ctx, "unknown error");
-               }
-       }
-       else
-       {
-               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)
-       {
-               command_print(cmd_ctx, "usage: flash protect_check <num>");
-               return ERROR_OK;
-       }
-       
-       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
-       {
-               command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
-       }
-       
-       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)
-               {
-                       command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
-                       return ERROR_OK;
-               }
-               
-               if ((retval = p->driver->erase(p, first, last)) != ERROR_OK)
-               {
-                       switch (retval)
-                       {
-                               case ERROR_TARGET_NOT_HALTED:
-                                       command_print(cmd_ctx, "can't work with this flash while target is running");
-                                       break;
-                               case ERROR_INVALID_ARGUMENTS:
-                                       command_print(cmd_ctx, "usage: flash_erase <bank> <first> <last>");
-                                       break;
-                               case ERROR_FLASH_BANK_INVALID:
-                                       command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
-                                       break;
-                               case ERROR_FLASH_OPERATION_FAILED:
-                                       command_print(cmd_ctx, "flash erase error");
-                                       break;
-                               case ERROR_FLASH_SECTOR_INVALID:
-                                       command_print(cmd_ctx, "sector number(s) invalid");
-                                       break;
-                               case ERROR_OK:
-                                       command_print(cmd_ctx, "erased flash sectors %i to %i", first, last);
-                                       break;
-                               default:
-                                       command_print(cmd_ctx, "unknown error");
-                       }
-               }
-               else
-               {
-                       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
-       {
-               command_print(cmd_ctx, "usage: flash erase <bank> <first> <last>");
-       }
-
-       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
-               {
-                       command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
-                       return ERROR_OK;
-               }
-               
-               if ((retval = p->driver->protect(p, set, first, last)) != ERROR_OK)
-               {
-                       switch (retval)
-                       {
-                               case ERROR_TARGET_NOT_HALTED:
-                                       command_print(cmd_ctx, "can't work with this flash while target is running");
-                                       break;
-                               case ERROR_INVALID_ARGUMENTS:
-                                       command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
-                                       break;
-                               case ERROR_FLASH_BANK_INVALID:
-                                       command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
-                                       break;
-                               case ERROR_FLASH_OPERATION_FAILED:
-                                       command_print(cmd_ctx, "flash program error");
-                                       break;
-                               case ERROR_FLASH_SECTOR_INVALID:
-                                       command_print(cmd_ctx, "sector number(s) invalid");
-                                       break;
-                               case ERROR_OK:
-                                       command_print(cmd_ctx, "protection of flash sectors %i to %i turned %s", first, last, args[3]);
-                                       break;
-                               default:
-                                       command_print(cmd_ctx, "unknown error");
-                       }
-               }
-               else
-               {
-                       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
-       {
-               command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
-       }
-
-       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;
-       char *error_str;
-       int *failed;
-       
-       int i;
-       
-       duration_t duration;
-       char *duration_text;
-       
-       int retval;
-
-       if (argc < 1)
-       {
-               command_print(cmd_ctx, "usage: flash %s <file> [offset] [type]", cmd);
-               return ERROR_INVALID_ARGUMENTS;
-       }
-       
-       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;
-       }
-       
-       failed = malloc(sizeof(int) * image.num_sections);
-
-       error_str = NULL;
-               
-       retval = flash_write(target, &image, &written, &error_str, failed, auto_erase);
-       
-       if (retval != ERROR_OK)
-       {
-               if (error_str)
-               {
-                       command_print(cmd_ctx, "failed writing image %s: %s", args[0], error_str);
-                       free(error_str);
-               }
-               image_close(&image);
-               free(failed);
-               return retval;
-       }
-       
-       for (i = 0; i < image.num_sections; i++)
-       {
-               if (failed[i])
-               {
-                       command_print(cmd_ctx, "didn't write section at 0x%8.8x, size 0x%8.8x",
-                                       image.sections[i].base_address, image.sections[i].size);
-               }
-       }
-       
-       duration_stop_measure(&duration, &duration_text);
-       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);
-       free(failed);
-
-       image_close(&image);
-       
-       return ERROR_OK;
-}
-
-int handle_flash_write_binary_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)
-       {
-               command_print(cmd_ctx, "usage: flash write_binary <bank> <file> <offset>");
-               return ERROR_OK;
-       }
-       
-       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;
-       }
-       
-       if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK)
-       {
-               command_print(cmd_ctx, "failed writing file %s to flash bank %i at offset 0x%8.8x",
-                       args[1], strtoul(args[0], NULL, 0), strtoul(args[2], NULL, 0));
-               
-               switch (retval)
-               {
-                       case ERROR_TARGET_NOT_HALTED:
-                               command_print(cmd_ctx, "can't work with this flash while target is running");
-                               break;
-                       case ERROR_INVALID_ARGUMENTS:
-                               command_print(cmd_ctx, "usage: flash write <bank> <file> <offset>");
-                               break;
-                       case ERROR_FLASH_BANK_INVALID:
-                               command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
-                               break;
-                       case ERROR_FLASH_OPERATION_FAILED:
-                               command_print(cmd_ctx, "flash program error");
-                               break;
-                       case ERROR_FLASH_DST_BREAKS_ALIGNMENT:
-                               command_print(cmd_ctx, "offset breaks required alignment");
-                               break;
-                       case ERROR_FLASH_DST_OUT_OF_BANK:
-                               command_print(cmd_ctx, "destination is out of flash bank (offset and/or file too large)");
-                               break;
-                       case ERROR_FLASH_SECTOR_NOT_ERASED:
-                               command_print(cmd_ctx, "destination sector(s) not erased");
-                               break;
-                       default:
-                               command_print(cmd_ctx, "unknown error");
-               }
-       }
-
-       free(buffer);
-       
-       duration_stop_measure(&duration, &duration_text);
-       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 ERROR_OK;
-}
-
-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;
-       }
-
-       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 c->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 c->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, char **error_str, int *failed, int erase)
-{
-       int retval;
-       int i;
-
-       int section;
-       u32 section_offset;
-       flash_bank_t *c;
-       
-       section = 0;
-       section_offset = 0;
-
-       if (written)
-               *written = 0;
-       
-       if (failed != NULL)
-               for (i = 0; i < image->num_sections; i++)
-                       failed[i] = 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)
-               {
-                       if (failed == NULL)
-                       {
-                               if (error_str == NULL)
-                                       return ERROR_FLASH_DST_OUT_OF_BANK; /* abort operation */
-                               *error_str = malloc(FLASH_MAX_ERROR_STR);
-                               snprintf(*error_str, FLASH_MAX_ERROR_STR, "no flash mapped at requested address");
-                               return ERROR_FLASH_DST_OUT_OF_BANK; /* abort operation */
-                       }
-                       failed[section] = ERROR_FLASH_DST_OUT_OF_BANK; /* mark the section as failed */
-                       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);
-                               
-                               if (error_str == NULL)
-                                       return ERROR_IMAGE_TEMPORARILY_UNAVAILABLE;
-                               
-                               *error_str = malloc(FLASH_MAX_ERROR_STR);
-                               
-                               /* if image_read_section returned an error there's an error string we can pass on */
-                               if (retval != ERROR_OK)
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "error reading from image: %s", image->error_str);
-                               else
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "error reading from image");
-                               
-                               return ERROR_IMAGE_TEMPORARILY_UNAVAILABLE;
-                       }
-
-                       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 = c->driver->write(c, buffer, run_address - c->base, run_size);
-               }
-               
-               free(buffer);
-
-               if (retval != ERROR_OK)
-               {
-                       if (error_str == NULL)
-                               return retval; /* abort operation */
-
-                       *error_str = malloc(FLASH_MAX_ERROR_STR);
-                       switch (retval)
-                       {
-                               case ERROR_TARGET_NOT_HALTED:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "can't flash image while target is running");
-                                       break;
-                               case ERROR_INVALID_ARGUMENTS:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "flash driver can't fulfill request");
-                                       break;
-                               case ERROR_FLASH_OPERATION_FAILED:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "flash program error");
-                                       break;
-                               case ERROR_FLASH_DST_BREAKS_ALIGNMENT:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "offset breaks required alignment");
-                                       break;
-                               case ERROR_FLASH_DST_OUT_OF_BANK:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "no flash mapped at requested address");
-                                       break;
-                               case ERROR_FLASH_SECTOR_NOT_ERASED:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "destination sector(s) not erased");
-                                       break;
-                               default:
-                                       snprintf(*error_str, FLASH_MAX_ERROR_STR, "unknown error: %i", retval);
-                       }
-
-                       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)
-       {
-               command_print(cmd_ctx, "usage: flash auto_erase <on|off>");
-               return ERROR_OK;
-       }
-       
-       if (strcmp(args[0], "on") == 0)
-               auto_erase = 1;
-       else if (strcmp(args[0], "off") == 0)
-               auto_erase = 0;
-       
-       return ERROR_OK;
-}
+/***************************************************************************\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
index 1ef74c8909f79282fa6a05fbda3216e1a982aa0a..e8262efa63aff831911a58a22c26126ad7793c27 100644 (file)
@@ -1,86 +1,97 @@
-/***************************************************************************
- *   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);
-       int (*erase)(struct flash_bank_s *bank, int first, int last);
-       int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
-       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, char **error, int *failed, 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 */
+/***************************************************************************\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
index 1f689cc5305e2bd5fd12e6b769158f89b4f42e67..da79ea73b8543637a85a9b791214541febd867f5 100644 (file)
-/***************************************************************************
- *   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;
-       
-       if (bank->target->state != TARGET_HALTED)
-       {
-               return ERROR_TARGET_NOT_HALTED;
-       }
-       
-       if ((first < 0) || (last < first) || (last >= bank->num_sectors))
-       {
-               return ERROR_FLASH_SECTOR_INVALID;
-       }
-       
-       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;
-                
-       if (bank->target->state != TARGET_HALTED)
-       {
-               return ERROR_TARGET_NOT_HALTED;
-       }
-       
-       /* 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)
-       {
-               command_print(cmd_ctx, "usage: lpc2000 part_id <num>");
-               return ERROR_OK;
-       }
-       
-       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;
-}
+/***************************************************************************\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
+       if (bank->target->state != TARGET_HALTED)\r
+       {\r
+               return ERROR_TARGET_NOT_HALTED;\r
+       }\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
+               command_print(cmd_ctx, "usage: lpc2000 part_id <num>");\r
+               return ERROR_OK;\r
+       }\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
index 2ef6f40b6cdc361a6f43d16dec6f4e8a8f9d1f34..4e1fd2e7881a9413f4f5e4c08bedd8c7c326712c 100644 (file)
-/***************************************************************************
- *   Copyright (C) 2007 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "lpc3180_nand_controller.h"
-
-#include "replacements.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "nand.h"
-#include "target.h"
-
-int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
-int lpc3180_register_commands(struct command_context_s *cmd_ctx);
-int lpc3180_init(struct nand_device_s *device);
-int lpc3180_reset(struct nand_device_s *device);
-int lpc3180_command(struct nand_device_s *device, u8 command);
-int lpc3180_address(struct nand_device_s *device, u8 address);
-int lpc3180_write_data(struct nand_device_s *device, u16 data);
-int lpc3180_read_data(struct nand_device_s *device, void *data);
-int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-int lpc3180_controller_ready(struct nand_device_s *device, int timeout);
-int lpc3180_nand_ready(struct nand_device_s *device, int timeout);
-
-int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-nand_flash_controller_t lpc3180_nand_controller =
-{
-       .name = "lpc3180",
-       .nand_device_command = lpc3180_nand_device_command,
-       .register_commands = lpc3180_register_commands,
-       .init = lpc3180_init,
-       .reset = lpc3180_reset,
-       .command = lpc3180_command,
-       .address = lpc3180_address,
-       .write_data = lpc3180_write_data,
-       .read_data = lpc3180_read_data,
-       .write_page = lpc3180_write_page,
-       .read_page = lpc3180_read_page,
-       .controller_ready = lpc3180_controller_ready,
-       .nand_ready = lpc3180_nand_ready,
-};
-
-/* nand device lpc3180 <target#> <oscillator_frequency>
- */
-int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)
-{
-       lpc3180_nand_controller_t *lpc3180_info;
-               
-       if (argc < 3)
-       {
-               WARNING("incomplete 'lpc3180' nand flash configuration");
-               return ERROR_FLASH_BANK_INVALID;
-       }
-       
-       lpc3180_info = malloc(sizeof(lpc3180_nand_controller_t));
-       device->controller_priv = lpc3180_info;
-
-       lpc3180_info->target = get_target_by_num(strtoul(args[1], NULL, 0));
-       if (!lpc3180_info->target)
-       {
-               ERROR("no target '%s' configured", args[1]);
-               return ERROR_NAND_DEVICE_INVALID;
-       }
-
-       lpc3180_info->osc_freq = strtoul(args[2], NULL, 0);
-       if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))
-       {
-               WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); 
-       }
-       lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER;
-       lpc3180_info->sw_write_protection = 0;
-       lpc3180_info->sw_wp_lower_bound = 0x0;
-       lpc3180_info->sw_wp_upper_bound = 0x0;
-               
-       return ERROR_OK;
-}
-
-int lpc3180_register_commands(struct command_context_s *cmd_ctx)
-{
-       command_t *lpc3180_cmd = register_command(cmd_ctx, NULL, "lpc3180", NULL, COMMAND_ANY, "commands specific to the LPC3180 NAND flash controllers");
-       
-       register_command(cmd_ctx, lpc3180_cmd, "select", handle_lpc3180_select_command, COMMAND_EXEC, "select <'mlc'|'slc'> controller (default is mlc)");
-       
-       return ERROR_OK;
-}
-
-int lpc3180_pll(int fclkin, u32 pll_ctrl)
-{
-       int bypass = (pll_ctrl & 0x8000) >> 15;
-       int direct = (pll_ctrl & 0x4000) >> 14;
-       int feedback = (pll_ctrl & 0x2000) >> 13;
-       int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2);
-       int n = ((pll_ctrl & 0x0600) >> 9) + 1;
-       int m = ((pll_ctrl & 0x01fe) >> 1) + 1;
-       int lock = (pll_ctrl & 0x1);
-
-       if (!lock)
-               WARNING("PLL is not locked");
-       
-       if (!bypass && direct)  /* direct mode */
-               return (m * fclkin) / n;
-       
-       if (bypass && !direct)  /* bypass mode */
-               return fclkin / (2 * p);
-               
-       if (bypass & direct)    /* direct bypass mode */
-               return fclkin;
-       
-       if (feedback)                   /* integer mode */
-               return m * (fclkin / n);
-       else                                    /* non-integer mode */
-               return (m / (2 * p)) * (fclkin / n); 
-}
-
-float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
-{
-       target_t *target = lpc3180_info->target;
-       u32 sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
-       int sysclk;
-       int hclk;
-       int hclk_pll;
-       float cycle;
-       
-       /* calculate timings */
-       
-       /* determine current SYSCLK (13'MHz or main oscillator) */ 
-       target_read_u32(target, 0x40004050, &sysclk_ctrl);
-       
-       if ((sysclk_ctrl & 1) == 0)
-               sysclk = lpc3180_info->osc_freq;
-       else
-               sysclk = 13000;
-       
-       /* determine selected HCLK source */
-       target_read_u32(target, 0x40004044, &pwr_ctrl);
-       
-       if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */
-       {
-               hclk = sysclk;
-       }
-       else
-       {
-               target_read_u32(target, 0x40004058, &hclkpll_ctrl);
-               hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl);
-
-               target_read_u32(target, 0x40004040, &hclkdiv_ctrl);
-               
-               if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */
-               {
-                       hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1);
-               }
-               else /* HCLK uses HCLK_PLL */
-               {
-                       hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); 
-               }
-       }
-       
-       DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk);
-       
-       cycle = (1.0 / hclk) * 1000000.0;
-       
-       return cycle;
-}
-
-int lpc3180_init(struct nand_device_s *device)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       int bus_width = (device->bus_width) ? (device->bus_width) : 8;
-       int address_cycles = (device->address_cycles) ? (device->address_cycles) : 3;
-       int page_size = (device->page_size) ? (device->page_size) : 512;
-               
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       /* sanitize arguments */
-       if ((bus_width != 8) && (bus_width != 16))
-       {
-               ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width);
-               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-       }
-       
-       /* The LPC3180 only brings out 8 bit NAND data bus, but the controller
-        * would support 16 bit, too, so we just warn about this for now
-        */
-       if (bus_width == 16)
-       {
-               WARNING("LPC3180 only supports 8 bit bus width");
-       }
-       
-       /* inform calling code about selected bus width */
-       device->bus_width = bus_width;
-       
-       if ((address_cycles != 3) && (address_cycles != 4))
-       {
-               ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles);
-               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-       }
-       
-       if ((page_size != 512) && (page_size != 2048))
-       {
-               ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size);
-               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-       }
-       
-       /* select MLC controller if none is currently selected */
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'");
-               lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               u32 mlc_icr_value = 0x0;
-               float cycle;
-               int twp, twh, trp, treh, trhz, trbwb, tcea;
-               
-               /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */
-               target_write_u32(target, 0x400040c8, 0x22);
-               
-               /* MLC_CEH = 0x0 (Force nCE assert) */
-               target_write_u32(target, 0x200b804c, 0x0);
-               
-               /* MLC_LOCK = 0xa25e (unlock protected registers) */
-               target_write_u32(target, 0x200b8044, 0xa25e);
-               
-               /* MLC_ICR = configuration */
-               if (lpc3180_info->sw_write_protection)
-                       mlc_icr_value |= 0x8;
-               if (page_size == 2048)
-                       mlc_icr_value |= 0x4;
-               if (address_cycles == 4)
-                       mlc_icr_value |= 0x2;
-               if (bus_width == 16)
-                       mlc_icr_value |= 0x1;
-               target_write_u32(target, 0x200b8030, mlc_icr_value);
-               
-               /* calculate NAND controller timings */
-               cycle = lpc3180_cycle_time(lpc3180_info);
-               
-               twp = ((40 / cycle) + 1);
-               twh = ((20 / cycle) + 1);
-               trp = ((30 / cycle) + 1);
-               treh = ((15 / cycle) + 1);
-               trhz = ((30 / cycle) + 1);
-               trbwb = ((100 / cycle) + 1);
-               tcea = ((45 / cycle) + 1);
-                               
-               /* MLC_LOCK = 0xa25e (unlock protected registers) */
-               target_write_u32(target, 0x200b8044, 0xa25e);
-       
-               /* MLC_TIME_REG */
-               target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | 
-                       ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | 
-                       ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); 
-
-               lpc3180_reset(device);
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               float cycle;
-               int r_setup, r_hold, r_width, r_rdy;
-               int w_setup, w_hold, w_width, w_rdy;
-               
-               /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */
-               target_write_u32(target, 0x400040c8, 0x05);
-               
-               /* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */
-               target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0);
-               
-               /* calculate NAND controller timings */
-               cycle = lpc3180_cycle_time(lpc3180_info);
-               
-               r_setup = w_setup = 0;
-               r_hold = w_hold = 10 / cycle;
-               r_width = 30 / cycle;
-               w_width = 40 / cycle;
-               r_rdy = w_rdy = 100 / cycle;
-               
-               /* SLC_TAC: SLC timing arcs register */
-               target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) |
-                       ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) |  ((w_setup & 0xf) << 16) |
-                       ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); 
-               
-               lpc3180_reset(device);
-       }
-       
-       return ERROR_OK;
-}
-
-int lpc3180_reset(struct nand_device_s *device)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               /* MLC_CMD = 0xff (reset controller and NAND device) */
-               target_write_u32(target, 0x200b8000, 0xff);
-
-               if (!lpc3180_controller_ready(device, 100))
-               {
-                       ERROR("LPC3180 NAND controller timed out after reset");
-                       return ERROR_NAND_OPERATION_TIMEOUT;
-               }
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */
-               target_write_u32(target, 0x20020010, 0x6);
-               
-               if (!lpc3180_controller_ready(device, 100))
-               {
-                       ERROR("LPC3180 NAND controller timed out after reset");
-                       return ERROR_NAND_OPERATION_TIMEOUT;
-               }
-       }
-       
-       return ERROR_OK;
-}
-
-int lpc3180_command(struct nand_device_s *device, u8 command)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               /* MLC_CMD = command */
-               target_write_u32(target, 0x200b8000, command);
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               /* SLC_CMD = command */
-               target_write_u32(target, 0x20020008, command);
-       }       
-       
-       return ERROR_OK;
-}
-
-int lpc3180_address(struct nand_device_s *device, u8 address)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               /* MLC_ADDR = address */
-               target_write_u32(target, 0x200b8004, address);
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               /* SLC_ADDR = address */
-               target_write_u32(target, 0x20020004, address);
-       }
-               
-       return ERROR_OK;
-}
-
-int lpc3180_write_data(struct nand_device_s *device, u16 data)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               /* MLC_DATA = data */
-               target_write_u32(target, 0x200b0000, data);
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               /* SLC_DATA = data */
-               target_write_u32(target, 0x20020000, data);
-       }
-       
-       return ERROR_OK;
-}
-
-int lpc3180_read_data(struct nand_device_s *device, void *data)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               /* data = MLC_DATA, use sized access */
-               if (device->bus_width == 8)
-               {
-                       u8 *data8 = data;
-                       target_read_u8(target, 0x200b0000, data8);
-               }
-               else if (device->bus_width == 16)
-               {
-                       u16 *data16 = data;
-                       target_read_u16(target, 0x200b0000, data16);
-               }
-               else
-               {
-                       ERROR("BUG: bus_width neither 8 nor 16 bit");
-                       return ERROR_NAND_OPERATION_FAILED;
-               }
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               u32 data32;
-
-               /* data = SLC_DATA, must use 32-bit access */
-               target_read_u32(target, 0x20020000, &data32);
-               
-               if (device->bus_width == 8)
-               {
-                       u8 *data8 = data;
-                       *data8 = data32 & 0xff;
-               }
-               else if (device->bus_width == 16)
-               {
-                       u16 *data16 = data;
-                       *data16 = data32 & 0xffff;
-               }
-               else
-               {
-                       ERROR("BUG: bus_width neither 8 nor 16 bit");
-                       return ERROR_NAND_OPERATION_FAILED;
-               }
-       }       
-       
-       return ERROR_OK;
-}
-
-int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       int retval;
-       u8 status;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               u8 *page_buffer;
-               u8 *oob_buffer;
-               int quarter, num_quarters;
-               
-               if (!data && oob)
-               {
-                       ERROR("LPC3180 MLC controller can't write OOB data only");
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-               }
-               
-               if (oob && (oob_size > 6))
-               {
-                       ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data");
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-               }
-               
-               if (data_size > device->page_size)
-               {
-                       ERROR("data size exceeds page size");
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-               }
-               
-               /* MLC_CMD = sequential input */
-               target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN);
-
-               page_buffer = malloc(512);
-               oob_buffer = malloc(6);         
-
-               if (device->page_size == 512)
-               {
-                       /* MLC_ADDR = 0x0 (one column cycle) */
-                       target_write_u32(target, 0x200b8004, 0x0);
-
-                       /* MLC_ADDR = row */
-                       target_write_u32(target, 0x200b8004, page & 0xff);
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
-                       
-                       if (device->address_cycles == 4)
-                               target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
-               }
-               else
-               {
-                       /* MLC_ADDR = 0x0 (two column cycles) */
-                       target_write_u32(target, 0x200b8004, 0x0);
-                       target_write_u32(target, 0x200b8004, 0x0);
-
-                       /* MLC_ADDR = row */
-                       target_write_u32(target, 0x200b8004, page & 0xff);
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
-               }
-               
-               /* when using the MLC controller, we have to treat a large page device
-                * as being made out of four quarters, each the size of a small page device
-                */
-               num_quarters = (device->page_size == 2048) ? 4 : 1;
-                
-               for (quarter = 0; quarter < num_quarters; quarter++)
-               {
-                       int thisrun_data_size = (data_size > 512) ? 512 : data_size;
-                       int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size;
-                       
-                       memset(page_buffer, 0xff, 512);
-                       if (data)
-                       {
-                               memcpy(page_buffer, data, thisrun_data_size);
-                               data_size -= thisrun_data_size;
-                               data += thisrun_data_size;
-                       }
-                       
-                       memset(oob_buffer, 0xff, (device->page_size == 512) ? 6 : 24);
-                       if (oob)
-                       {
-                               memcpy(page_buffer, oob, thisrun_oob_size);
-                               oob_size -= thisrun_oob_size;
-                               oob += thisrun_oob_size;
-                       }
-                       
-                       /* write MLC_ECC_ENC_REG to start encode cycle */
-                       target_write_u32(target, 0x200b8008, 0x0);
-                       
-                       target->type->write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));
-                       target->type->write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));
-                       
-                       /* write MLC_ECC_AUTO_ENC_REG to start auto encode */
-                       target_write_u32(target, 0x200b8010, 0x0);
-                       
-                       if (!lpc3180_controller_ready(device, 1000))
-                       {
-                               ERROR("timeout while waiting for completion of auto encode cycle");
-                               return ERROR_NAND_OPERATION_FAILED;
-                       }
-               }
-               
-               /* MLC_CMD = auto program command */
-               target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG);
-               
-               if ((retval = nand_read_status(device, &status)) != ERROR_OK)
-               {
-                       ERROR("couldn't read status");
-                       return ERROR_NAND_OPERATION_FAILED;
-               }
-                       
-               if (status & NAND_STATUS_FAIL)
-               {
-                       ERROR("write operation didn't pass, status: 0x%2.2x", status);
-                       return ERROR_NAND_OPERATION_FAILED;
-               }
-       
-               free(page_buffer);
-               free(oob_buffer);
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
-       }
-       
-       return ERROR_OK;
-}
-
-int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       
-       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
-       {
-               ERROR("BUG: no LPC3180 NAND flash controller selected");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-       {
-               u8 *page_buffer;
-               u8 *oob_buffer;
-               u32 page_bytes_done = 0;
-               u32 oob_bytes_done = 0;
-               u32 mlc_isr;
-
-#if 0
-               if (oob && (oob_size > 6))
-               {
-                       ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data");
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-               }
-#endif
-               
-               if (data_size > device->page_size)
-               {
-                       ERROR("data size exceeds page size");
-                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
-               }
-               
-               if (device->page_size == 2048)
-               {
-                       page_buffer = malloc(2048);
-                       oob_buffer = malloc(64);
-               }
-               else
-               {
-                       page_buffer = malloc(512);
-                       oob_buffer = malloc(16);
-               }
-               
-               if (!data && oob)
-               {
-                       /* MLC_CMD = Read OOB 
-                        * we can use the READOOB command on both small and large page devices,
-                        * as the controller translates the 0x50 command to a 0x0 with appropriate
-                        * positioning of the serial buffer read pointer
-                        */
-                       target_write_u32(target, 0x200b8000, NAND_CMD_READOOB);
-               }
-               else
-               {
-                       /* MLC_CMD = Read0 */
-                       target_write_u32(target, 0x200b8000, NAND_CMD_READ0);
-               }
-               
-               if (device->page_size == 512)
-               {
-                       /* small page device */
-                       /* MLC_ADDR = 0x0 (one column cycle) */
-                       target_write_u32(target, 0x200b8004, 0x0);
-
-                       /* MLC_ADDR = row */
-                       target_write_u32(target, 0x200b8004, page & 0xff);
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
-                       
-                       if (device->address_cycles == 4)
-                               target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
-               }
-               else
-               {
-                       /* large page device */
-                       /* MLC_ADDR = 0x0 (two column cycles) */
-                       target_write_u32(target, 0x200b8004, 0x0);
-                       target_write_u32(target, 0x200b8004, 0x0);
-
-                       /* MLC_ADDR = row */
-                       target_write_u32(target, 0x200b8004, page & 0xff);
-                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
-                       
-                       /* MLC_CMD = Read Start */
-                       target_write_u32(target, 0x200b8000, NAND_CMD_READSTART);
-               }
-               
-               while (page_bytes_done < device->page_size)
-               {
-                       /* MLC_ECC_AUTO_DEC_REG = dummy */
-                       target_write_u32(target, 0x200b8014, 0xaa55aa55);
-                       
-                       if (!lpc3180_controller_ready(device, 1000))
-                       {
-                               ERROR("timeout while waiting for completion of auto decode cycle");
-                               return ERROR_NAND_OPERATION_FAILED;
-                       }
-               
-                       target_read_u32(target, 0x200b8048, &mlc_isr);
-                       
-                       if (mlc_isr & 0x8)
-                       {
-                               if (mlc_isr & 0x40)
-                               {
-                                       ERROR("uncorrectable error detected: 0x%2.2x", mlc_isr);
-                                       return ERROR_NAND_OPERATION_FAILED;
-                               }
-                               
-                               WARNING("%i symbol error detected and corrected", ((mlc_isr & 0x30) >> 4) + 1);
-                       }
-                       
-                       if (data)
-                       {
-                               target->type->read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done);
-                       }
-                       
-                       if (oob)
-                       {
-                               target->type->read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done);
-                       }
-
-                       page_bytes_done += 512;
-                       oob_bytes_done += 16;
-               }
-               
-               if (data)
-                       memcpy(data, page_buffer, data_size);
-               
-               if (oob)
-                       memcpy(oob, oob_buffer, oob_size);
-               
-               free(page_buffer);
-               free(oob_buffer);
-       }
-       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-       {
-               return nand_read_page_raw(device, page, data, data_size, oob, oob_size);
-       }
-       
-       return ERROR_OK;
-}
-
-int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       u8 status = 0x0;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-                       
-       do
-       {
-               if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-               {
-                       /* Read MLC_ISR, wait for controller to become ready */
-                       target_read_u8(target, 0x200b8048, &status);
-                       
-                       if (status & 2)
-                               return 1;
-               }
-               else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-               {
-                       /* we pretend that the SLC controller is always ready */
-                       return 1;
-               }
-
-               usleep(1000);
-       } while (timeout-- > 0);
-       
-       return 0;
-}
-
-int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
-{
-       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
-       target_t *target = lpc3180_info->target;
-       
-       if (target->state != TARGET_HALTED)
-       {
-               ERROR("target must be halted to use LPC3180 NAND flash controller");
-               return ERROR_NAND_OPERATION_FAILED;
-       }
-                       
-       do
-       {
-               if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
-               {       
-                       u8 status = 0x0;
-                       
-                       /* Read MLC_ISR, wait for NAND flash device to become ready */
-                       target_read_u8(target, 0x200b8048, &status);
-                       
-                       if (status & 1)
-                               return 1;
-               }
-               else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
-               {
-                       u32 status = 0x0;
-                       
-                       /* Read SLC_STAT and check READY bit */
-                       target_read_u32(target, 0x20020018, &status);
-                       
-                       if (status & 1)
-                               return 1;
-               }
-               
-               usleep(1000);
-       } while (timeout-- > 0);
-       
-       return 0;       
-}
-
-int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       nand_device_t *device = NULL;
-       lpc3180_nand_controller_t *lpc3180_info = NULL;
-       char *selected[] = 
-       {
-               "no", "mlc", "slc"
-       };
-       
-       if ((argc < 1) || (argc > 2))
-       {
-               command_print(cmd_ctx, "usage: lpc3180 select <num> <'mlc'|'slc'>");
-               return ERROR_OK;
-       }
-       
-       device = get_nand_device_by_num(strtoul(args[0], NULL, 0));
-       if (!device)
-       {
-               command_print(cmd_ctx, "nand device '#%s' is out of bounds", args[0]);
-               return ERROR_OK;
-       }
-       
-       lpc3180_info = device->controller_priv;
-       
-       if (argc == 2)
-       {
-               if (strcmp(args[1], "mlc") == 0)
-               {
-                       lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
-               }
-               else if (strcmp(args[1], "slc") == 0)
-               {
-                       lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;
-               }
-               else
-               {
-                       command_print(cmd_ctx, "usage: lpc3180 select <'mlc'|'slc'>");
-               }
-       }
-       
-       command_print(cmd_ctx, "%s controller selected", selected[lpc3180_info->selected_controller]);
-       
-       return ERROR_OK;
-}
+/***************************************************************************\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
+&nb