-/***************************************************************************
- * 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
}\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
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
-/***************************************************************************
- * 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
-/***************************************************************************
- * 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
-/***************************************************************************
- * 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(®_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(®_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(®_params[2], "r12", 32, PARAM_OUT);
- buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
-
- /* IAP stack */
- init_reg_param(®_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(®_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(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_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(®_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(®_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(®_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(®_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(®_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(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ destroy_reg_param(®_params[3]);\r
+ destroy_reg_param(®_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
-/***************************************************************************
- * 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
+ \r
+ /* determine selected HCLK source */\r
+ target_read_u32(target, 0x40004044, &pwr_ctrl);\r
+ \r
+ if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */\r
+ {\r
+ hclk = sysclk;\r
+ }\r
+ else\r
+ {\r
+ target_read_u32(target, 0x40004058, &hclkpll_ctrl);\r
+ hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl);\r
+\r
+ target_read_u32(target, 0x40004040, &hclkdiv_ctrl);\r
+ \r
+ if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */\r
+ {\r
+ hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1);\r
+ }\r
+ else /* HCLK uses HCLK_PLL */\r
+ {\r
+ hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); \r
+ }\r
+ }\r
+ \r
+ DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk);\r
+ \r
+ cycle = (1.0 / hclk) * 1000000.0;\r
+ \r
+ return cycle;\r
+}\r
+\r
+int lpc3180_init(struct nand_device_s *device)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ int bus_width = (device->bus_width) ? (device->bus_width) : 8;\r
+ int address_cycles = (device->address_cycles) ? (device->address_cycles) : 3;\r
+ int page_size = (device->page_size) ? (device->page_size) : 512;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ /* sanitize arguments */\r
+ if ((bus_width != 8) && (bus_width != 16))\r
+ {\r
+ ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width);\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ /* The LPC3180 only brings out 8 bit NAND data bus, but the controller\r
+ * would support 16 bit, too, so we just warn about this for now\r
+ */\r
+ if (bus_width == 16)\r
+ {\r
+ WARNING("LPC3180 only supports 8 bit bus width");\r
+ }\r
+ \r
+ /* inform calling code about selected bus width */\r
+ device->bus_width = bus_width;\r
+ \r
+ if ((address_cycles != 3) && (address_cycles != 4))\r
+ {\r
+ ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles);\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ if ((page_size != 512) && (page_size != 2048))\r
+ {\r
+ ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size);\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ /* select MLC controller if none is currently selected */\r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'");\r
+ lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ u32 mlc_icr_value = 0x0;\r
+ float cycle;\r
+ int twp, twh, trp, treh, trhz, trbwb, tcea;\r
+ \r
+ /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */\r
+ target_write_u32(target, 0x400040c8, 0x22);\r
+ \r
+ /* MLC_CEH = 0x0 (Force nCE assert) */\r
+ target_write_u32(target, 0x200b804c, 0x0);\r
+ \r
+ /* MLC_LOCK = 0xa25e (unlock protected registers) */\r
+ target_write_u32(target, 0x200b8044, 0xa25e);\r
+ \r
+ /* MLC_ICR = configuration */\r
+ if (lpc3180_info->sw_write_protection)\r
+ mlc_icr_value |= 0x8;\r
+ if (page_size == 2048)\r
+ mlc_icr_value |= 0x4;\r
+ if (address_cycles == 4)\r
+ mlc_icr_value |= 0x2;\r
+ if (bus_width == 16)\r
+ mlc_icr_value |= 0x1;\r
+ target_write_u32(target, 0x200b8030, mlc_icr_value);\r
+ \r
+ /* calculate NAND controller timings */\r
+ cycle = lpc3180_cycle_time(lpc3180_info);\r
+ \r
+ twp = ((40 / cycle) + 1);\r
+ twh = ((20 / cycle) + 1);\r
+ trp = ((30 / cycle) + 1);\r
+ treh = ((15 / cycle) + 1);\r
+ trhz = ((30 / cycle) + 1);\r
+ trbwb = ((100 / cycle) + 1);\r
+ tcea = ((45 / cycle) + 1);\r
+ \r
+ /* MLC_LOCK = 0xa25e (unlock protected registers) */\r
+ target_write_u32(target, 0x200b8044, 0xa25e);\r
+ \r
+ /* MLC_TIME_REG */\r
+ target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | \r
+ ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | \r
+ ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); \r
+\r
+ lpc3180_reset(device);\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ float cycle;\r
+ int r_setup, r_hold, r_width, r_rdy;\r
+ int w_setup, w_hold, w_width, w_rdy;\r
+ \r
+ /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */\r
+ target_write_u32(target, 0x400040c8, 0x05);\r
+ \r
+ /* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */\r
+ target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0);\r
+ \r
+ /* calculate NAND controller timings */\r
+ cycle = lpc3180_cycle_time(lpc3180_info);\r
+ \r
+ r_setup = w_setup = 0;\r
+ r_hold = w_hold = 10 / cycle;\r
+ r_width = 30 / cycle;\r
+ w_width = 40 / cycle;\r
+ r_rdy = w_rdy = 100 / cycle;\r
+ \r
+ /* SLC_TAC: SLC timing arcs register */\r
+ target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) |\r
+ ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) |\r
+ ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); \r
+ \r
+ lpc3180_reset(device);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_reset(struct nand_device_s *device)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ /* MLC_CMD = 0xff (reset controller and NAND device) */\r
+ target_write_u32(target, 0x200b8000, 0xff);\r
+\r
+ if (!lpc3180_controller_ready(device, 100))\r
+ {\r
+ ERROR("LPC3180 NAND controller timed out after reset");\r
+ return ERROR_NAND_OPERATION_TIMEOUT;\r
+ }\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */\r
+ target_write_u32(target, 0x20020010, 0x6);\r
+ \r
+ if (!lpc3180_controller_ready(device, 100))\r
+ {\r
+ ERROR("LPC3180 NAND controller timed out after reset");\r
+ return ERROR_NAND_OPERATION_TIMEOUT;\r
+ }\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_command(struct nand_device_s *device, u8 command)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ /* MLC_CMD = command */\r
+ target_write_u32(target, 0x200b8000, command);\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ /* SLC_CMD = command */\r
+ target_write_u32(target, 0x20020008, command);\r
+ } \r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_address(struct nand_device_s *device, u8 address)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ /* MLC_ADDR = address */\r
+ target_write_u32(target, 0x200b8004, address);\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ /* SLC_ADDR = address */\r
+ target_write_u32(target, 0x20020004, address);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_write_data(struct nand_device_s *device, u16 data)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ /* MLC_DATA = data */\r
+ target_write_u32(target, 0x200b0000, data);\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ /* SLC_DATA = data */\r
+ target_write_u32(target, 0x20020000, data);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_read_data(struct nand_device_s *device, void *data)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ /* data = MLC_DATA, use sized access */\r
+ if (device->bus_width == 8)\r
+ {\r
+ u8 *data8 = data;\r
+ target_read_u8(target, 0x200b0000, data8);\r
+ }\r
+ else if (device->bus_width == 16)\r
+ {\r
+ u16 *data16 = data;\r
+ target_read_u16(target, 0x200b0000, data16);\r
+ }\r
+ else\r
+ {\r
+ ERROR("BUG: bus_width neither 8 nor 16 bit");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ u32 data32;\r
+\r
+ /* data = SLC_DATA, must use 32-bit access */\r
+ target_read_u32(target, 0x20020000, &data32);\r
+ \r
+ if (device->bus_width == 8)\r
+ {\r
+ u8 *data8 = data;\r
+ *data8 = data32 & 0xff;\r
+ }\r
+ else if (device->bus_width == 16)\r
+ {\r
+ u16 *data16 = data;\r
+ *data16 = data32 & 0xffff;\r
+ }\r
+ else\r
+ {\r
+ ERROR("BUG: bus_width neither 8 nor 16 bit");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ } \r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ int retval;\r
+ u8 status;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ u8 *page_buffer;\r
+ u8 *oob_buffer;\r
+ int quarter, num_quarters;\r
+ \r
+ if (!data && oob)\r
+ {\r
+ ERROR("LPC3180 MLC controller can't write OOB data only");\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ if (oob && (oob_size > 6))\r
+ {\r
+ ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data");\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ if (data_size > device->page_size)\r
+ {\r
+ ERROR("data size exceeds page size");\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ /* MLC_CMD = sequential input */\r
+ target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN);\r
+\r
+ page_buffer = malloc(512);\r
+ oob_buffer = malloc(6); \r
+\r
+ if (device->page_size == 512)\r
+ {\r
+ /* MLC_ADDR = 0x0 (one column cycle) */\r
+ target_write_u32(target, 0x200b8004, 0x0);\r
+\r
+ /* MLC_ADDR = row */\r
+ target_write_u32(target, 0x200b8004, page & 0xff);\r
+ target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
+ \r
+ if (device->address_cycles == 4)\r
+ target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);\r
+ }\r
+ else\r
+ {\r
+ /* MLC_ADDR = 0x0 (two column cycles) */\r
+ target_write_u32(target, 0x200b8004, 0x0);\r
+ target_write_u32(target, 0x200b8004, 0x0);\r
+\r
+ /* MLC_ADDR = row */\r
+ target_write_u32(target, 0x200b8004, page & 0xff);\r
+ target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
+ }\r
+ \r
+ /* when using the MLC controller, we have to treat a large page device\r
+ * as being made out of four quarters, each the size of a small page device\r
+ */\r
+ num_quarters = (device->page_size == 2048) ? 4 : 1;\r
+ \r
+ for (quarter = 0; quarter < num_quarters; quarter++)\r
+ {\r
+ int thisrun_data_size = (data_size > 512) ? 512 : data_size;\r
+ int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size;\r
+ \r
+ memset(page_buffer, 0xff, 512);\r
+ if (data)\r
+ {\r
+ memcpy(page_buffer, data, thisrun_data_size);\r
+ data_size -= thisrun_data_size;\r
+ data += thisrun_data_size;\r
+ }\r
+ \r
+ memset(oob_buffer, 0xff, (device->page_size == 512) ? 6 : 24);\r
+ if (oob)\r
+ {\r
+ memcpy(page_buffer, oob, thisrun_oob_size);\r
+ oob_size -= thisrun_oob_size;\r
+ oob += thisrun_oob_size;\r
+ }\r
+ \r
+ /* write MLC_ECC_ENC_REG to start encode cycle */\r
+ target_write_u32(target, 0x200b8008, 0x0);\r
+ \r
+ target->type->write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));\r
+ target->type->write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));\r
+ \r
+ /* write MLC_ECC_AUTO_ENC_REG to start auto encode */\r
+ target_write_u32(target, 0x200b8010, 0x0);\r
+ \r
+ if (!lpc3180_controller_ready(device, 1000))\r
+ {\r
+ ERROR("timeout while waiting for completion of auto encode cycle");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ /* MLC_CMD = auto program command */\r
+ target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG);\r
+ \r
+ if ((retval = nand_read_status(device, &status)) != ERROR_OK)\r
+ {\r
+ ERROR("couldn't read status");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (status & NAND_STATUS_FAIL)\r
+ {\r
+ ERROR("write operation didn't pass, status: 0x%2.2x", status);\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ free(page_buffer);\r
+ free(oob_buffer);\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ return nand_write_page_raw(device, page, data, data_size, oob, oob_size);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)\r
+ {\r
+ ERROR("BUG: no LPC3180 NAND flash controller selected");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ u8 *page_buffer;\r
+ u8 *oob_buffer;\r
+ u32 page_bytes_done = 0;\r
+ u32 oob_bytes_done = 0;\r
+ u32 mlc_isr;\r
+\r
+#if 0\r
+ if (oob && (oob_size > 6))\r
+ {\r
+ ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data");\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+#endif\r
+ \r
+ if (data_size > device->page_size)\r
+ {\r
+ ERROR("data size exceeds page size");\r
+ return ERROR_NAND_OPERATION_NOT_SUPPORTED;\r
+ }\r
+ \r
+ if (device->page_size == 2048)\r
+ {\r
+ page_buffer = malloc(2048);\r
+ oob_buffer = malloc(64);\r
+ }\r
+ else\r
+ {\r
+ page_buffer = malloc(512);\r
+ oob_buffer = malloc(16);\r
+ }\r
+ \r
+ if (!data && oob)\r
+ {\r
+ /* MLC_CMD = Read OOB \r
+ * we can use the READOOB command on both small and large page devices,\r
+ * as the controller translates the 0x50 command to a 0x0 with appropriate\r
+ * positioning of the serial buffer read pointer\r
+ */\r
+ target_write_u32(target, 0x200b8000, NAND_CMD_READOOB);\r
+ }\r
+ else\r
+ {\r
+ /* MLC_CMD = Read0 */\r
+ target_write_u32(target, 0x200b8000, NAND_CMD_READ0);\r
+ }\r
+ \r
+ if (device->page_size == 512)\r
+ {\r
+ /* small page device */\r
+ /* MLC_ADDR = 0x0 (one column cycle) */\r
+ target_write_u32(target, 0x200b8004, 0x0);\r
+\r
+ /* MLC_ADDR = row */\r
+ target_write_u32(target, 0x200b8004, page & 0xff);\r
+ target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
+ \r
+ if (device->address_cycles == 4)\r
+ target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);\r
+ }\r
+ else\r
+ {\r
+ /* large page device */\r
+ /* MLC_ADDR = 0x0 (two column cycles) */\r
+ target_write_u32(target, 0x200b8004, 0x0);\r
+ target_write_u32(target, 0x200b8004, 0x0);\r
+\r
+ /* MLC_ADDR = row */\r
+ target_write_u32(target, 0x200b8004, page & 0xff);\r
+ target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);\r
+ \r
+ /* MLC_CMD = Read Start */\r
+ target_write_u32(target, 0x200b8000, NAND_CMD_READSTART);\r
+ }\r
+ \r
+ while (page_bytes_done < device->page_size)\r
+ {\r
+ /* MLC_ECC_AUTO_DEC_REG = dummy */\r
+ target_write_u32(target, 0x200b8014, 0xaa55aa55);\r
+ \r
+ if (!lpc3180_controller_ready(device, 1000))\r
+ {\r
+ ERROR("timeout while waiting for completion of auto decode cycle");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ target_read_u32(target, 0x200b8048, &mlc_isr);\r
+ \r
+ if (mlc_isr & 0x8)\r
+ {\r
+ if (mlc_isr & 0x40)\r
+ {\r
+ ERROR("uncorrectable error detected: 0x%2.2x", mlc_isr);\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ WARNING("%i symbol error detected and corrected", ((mlc_isr & 0x30) >> 4) + 1);\r
+ }\r
+ \r
+ if (data)\r
+ {\r
+ target->type->read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done);\r
+ }\r
+ \r
+ if (oob)\r
+ {\r
+ target->type->read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done);\r
+ }\r
+\r
+ page_bytes_done += 512;\r
+ oob_bytes_done += 16;\r
+ }\r
+ \r
+ if (data)\r
+ memcpy(data, page_buffer, data_size);\r
+ \r
+ if (oob)\r
+ memcpy(oob, oob_buffer, oob_size);\r
+ \r
+ free(page_buffer);\r
+ free(oob_buffer);\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ return nand_read_page_raw(device, page, data, data_size, oob, oob_size);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int lpc3180_controller_ready(struct nand_device_s *device, int timeout)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ u8 status = 0x0;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ do\r
+ {\r
+ if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ {\r
+ /* Read MLC_ISR, wait for controller to become ready */\r
+ target_read_u8(target, 0x200b8048, &status);\r
+ \r
+ if (status & 2)\r
+ return 1;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ /* we pretend that the SLC controller is always ready */\r
+ return 1;\r
+ }\r
+\r
+ usleep(1000);\r
+ } while (timeout-- > 0);\r
+ \r
+ return 0;\r
+}\r
+\r
+int lpc3180_nand_ready(struct nand_device_s *device, int timeout)\r
+{\r
+ lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;\r
+ target_t *target = lpc3180_info->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ ERROR("target must be halted to use LPC3180 NAND flash controller");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ do\r
+ {\r
+ if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)\r
+ { \r
+ u8 status = 0x0;\r
+ \r
+ /* Read MLC_ISR, wait for NAND flash device to become ready */\r
+ target_read_u8(target, 0x200b8048, &status);\r
+ \r
+ if (status & 1)\r
+ return 1;\r
+ }\r
+ else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)\r
+ {\r
+ u32 status = 0x0;\r
+ \r
+ /* Read SLC_STAT and check READY bit */\r
+ target_read_u32(target, 0x20020018, &status);\r
+ \r
+ if (status & 1)\r
+ return 1;\r
+ }\r
+ \r
+ usleep(1000);\r
+ } while (timeout-- > 0);\r
+ \r
+ return 0; \r
+}\r
+\r
+int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *device = NULL;\r
+ lpc3180_nand_controller_t *lpc3180_info = NULL;\r
+ char *selected[] = \r
+ {\r
+ "no", "mlc", "slc"\r
+ };\r
+ \r
+ if ((argc < 1) || (argc > 2))\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+ }\r
+ \r
+ device = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (!device)\r
+ {\r
+ command_print(cmd_ctx, "nand device '#%s' is out of bounds", args[0]);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ lpc3180_info = device->controller_priv;\r
+ \r
+ if (argc == 2)\r
+ {\r
+ if (strcmp(args[1], "mlc") == 0)\r
+ {\r
+ lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;\r
+ }\r
+ else if (strcmp(args[1], "slc") == 0)\r
+ {\r
+ lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;\r
+ }\r
+ else\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+ }\r
+ }\r
+ \r
+ command_print(cmd_ctx, "%s controller selected", selected[lpc3180_info->selected_controller]);\r
+ \r
+ return ERROR_OK;\r
+}\r
-/***************************************************************************
- * Copyright (C) 2007 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * partially based on *
- * drivers/mtd/nand_ids.c *
- * *
- * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.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 "replacements.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include <errno.h>
-
-#include "nand.h"
-#include "flash.h"
-#include "time_support.h"
-#include "fileio.h"
-#include "image.h"
-
-int nand_register_commands(struct command_context_s *cmd_ctx);
-int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size);
-
-int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-
-/* NAND flash controller
- */
-extern nand_flash_controller_t lpc3180_nand_controller;
-extern nand_flash_controller_t s3c2410_nand_controller;
-extern nand_flash_controller_t s3c2412_nand_controller;
-extern nand_flash_controller_t s3c2440_nand_controller;
-extern nand_flash_controller_t s3c2443_nand_controller;
-
-/* extern nand_flash_controller_t boundary_scan_nand_controller; */
-
-nand_flash_controller_t *nand_flash_controllers[] =
-{
- &lpc3180_nand_controller,
- &s3c2410_nand_controller,
- &s3c2412_nand_controller,
- &s3c2440_nand_controller,
- &s3c2443_nand_controller,
-/* &boundary_scan_nand_controller, */
- NULL
-};
-
-/* configured NAND devices and NAND Flash command handler */
-nand_device_t *nand_devices = NULL;
-static command_t *nand_cmd;
-
-/* Chip ID list
- *
- * Name, ID code, pagesize, chipsize in MegaByte, eraseblock size,
- * options
- *
- * Pagesize; 0, 256, 512
- * 0 get this information from the extended chip ID
- * 256 256 Byte page size
- * 512 512 Byte page size
- */
-nand_info_t nand_flash_ids[] =
-{
- {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
- {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
- {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
- {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
- {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
- {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
- {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
-
- {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
- {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
- {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
- {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
-
- {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
- {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
- {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
- {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
- {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
- {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
- {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
- {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
- {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
- {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
-
- {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
- {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
- {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
- {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
-
- {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
- {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
- {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
- {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
-
- {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
- {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
- {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
- {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
-
- {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
- {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
- {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
- {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
-
- {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
- {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
- {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
- {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
-
- {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
- {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
- {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
- {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
-
- {NULL, 0,}
-};
-
-/* Manufacturer ID list
- */
-nand_manufacturer_t nand_manuf_ids[] =
-{
- {0x0, "unknown"},
- {NAND_MFR_TOSHIBA, "Toshiba"},
- {NAND_MFR_SAMSUNG, "Samsung"},
- {NAND_MFR_FUJITSU, "Fujitsu"},
- {NAND_MFR_NATIONAL, "National"},
- {NAND_MFR_RENESAS, "Renesas"},
- {NAND_MFR_STMICRO, "ST Micro"},
- {NAND_MFR_HYNIX, "Hynix"},
- {0x0, NULL},
-};
-
-/* nand device <nand_controller> [controller options]
- */
-int handle_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int i;
- int retval;
-
- if (argc < 1)
- {
- WARNING("incomplete flash device nand configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- for (i = 0; nand_flash_controllers[i]; i++)
- {
- nand_device_t *p, *c;
-
- if (strcmp(args[0], nand_flash_controllers[i]->name) == 0)
- {
- /* register flash specific commands */
- if (nand_flash_controllers[i]->register_commands(cmd_ctx) != ERROR_OK)
- {
- ERROR("couldn't register '%s' commands", args[0]);
- exit(-1);
- }
-
- c = malloc(sizeof(nand_device_t));
-
- c->controller = nand_flash_controllers[i];
- c->controller_priv = NULL;
- c->manufacturer = NULL;
- c->device = NULL;
- c->bus_width = 0;
- c->address_cycles = 0;
- c->page_size = 0;
- c->use_raw = 0;
- c->next = NULL;
-
- if ((retval = nand_flash_controllers[i]->nand_device_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)
- {
- ERROR("'%s' driver rejected nand flash", c->controller->name);
- free(c);
- return ERROR_OK;
- }
-
- /* put NAND device in linked list */
- if (nand_devices)
- {
- /* find last flash device */
- for (p = nand_devices; p && p->next; p = p->next);
- if (p)
- p->next = c;
- }
- else
- {
- nand_devices = c;
- }
-
- return ERROR_OK;
- }
- }
-
- /* no valid NAND controller was found (i.e. the configuration option,
- * didn't match one of the compiled-in controllers)
- */
- ERROR("No valid NAND flash controller found (%s)", args[0]);
- ERROR("compiled-in NAND flash controllers:");
- for (i = 0; nand_flash_controllers[i]; i++)
- {
- ERROR("%i: %s", i, nand_flash_controllers[i]->name);
- }
-
- return ERROR_OK;
-}
-
-int nand_register_commands(struct command_context_s *cmd_ctx)
-{
- nand_cmd = register_command(cmd_ctx, NULL, "nand", NULL, COMMAND_ANY, "NAND specific commands");
-
- register_command(cmd_ctx, nand_cmd, "device", handle_nand_device_command, COMMAND_CONFIG, NULL);
-
- return ERROR_OK;
-}
-
-int nand_init(struct command_context_s *cmd_ctx)
-{
- if (nand_devices)
- {
- register_command(cmd_ctx, nand_cmd, "list", handle_nand_list_command, COMMAND_EXEC,
- "list configured NAND flash devices");
- register_command(cmd_ctx, nand_cmd, "info", handle_nand_info_command, COMMAND_EXEC,
- "print info about NAND flash device <num>");
- register_command(cmd_ctx, nand_cmd, "probe", handle_nand_probe_command, COMMAND_EXEC,
- "identify NAND flash device <num>");
- register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC,
- "check NAND flash device <num> for bad blocks [<first> <last>]");
- register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC,
- "erase blocks on NAND flash device <num> <first> <last>");
- register_command(cmd_ctx, nand_cmd, "copy", handle_nand_copy_command, COMMAND_EXEC,
- "copy from NAND flash device <num> <offset> <length> <ram-address>");
- register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC,
- "dump from NAND flash device <num> <filename> <offset> <size> [options]");
- register_command(cmd_ctx, nand_cmd, "write", handle_nand_write_command, COMMAND_EXEC,
- "write to NAND flash device <num> <filename> <offset> [options]");
- register_command(cmd_ctx, nand_cmd, "raw_access", handle_nand_raw_access_command, COMMAND_EXEC,
- "raw access to NAND flash device <num> ['enable'|'disable']");
- }
-
- return ERROR_OK;
-}
-
-nand_device_t *get_nand_device_by_num(int num)
-{
- nand_device_t *p;
- int i = 0;
-
- for (p = nand_devices; p; p = p->next)
- {
- if (i++ == num)
- {
- return p;
- }
- }
-
- return NULL;
-}
-
-int nand_build_bbt(struct nand_device_s *device, int first, int last)
-{
- u32 page = 0x0;
- int i;
- u8 *oob;
-
- oob = malloc(6);
-
- if ((first < 0) || (first >= device->num_blocks))
- first = 0;
-
- if ((last >= device->num_blocks) || (last == -1))
- last = device->num_blocks - 1;
-
- for (i = first; i < last; i++)
- {
- nand_read_page(device, page, NULL, 0, oob, 6);
-
- if (((device->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
- || (((device->page_size == 512) && (oob[5] != 0xff)) ||
- ((device->page_size == 2048) && (oob[0] != 0xff))))
- {
- WARNING("invalid block: %i", i);
- device->blocks[i].is_bad = 1;
- }
- else
- {
- device->blocks[i].is_bad = 0;
- }
-
- page += (device->erase_size / device->page_size);
- }
-
- return ERROR_OK;
-}
-
-int nand_read_status(struct nand_device_s *device, u8 *status)
-{
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- /* Send read status command */
- device->controller->command(device, NAND_CMD_STATUS);
-
- usleep(1000);
-
- /* read status */
- if (device->device->options & NAND_BUSWIDTH_16)
- {
- u16 data;
- device->controller->read_data(device, &data);
- *status = data & 0xff;
- }
- else
- {
- device->controller->read_data(device, status);
- }
-
- return ERROR_OK;
-}
-
-int nand_probe(struct nand_device_s *device)
-{
- u8 manufacturer_id, device_id;
- u8 id_buff[5];
- int retval;
- int i;
-
- /* clear device data */
- device->device = NULL;
- device->manufacturer = NULL;
-
- /* clear device parameters */
- device->bus_width = 0;
- device->address_cycles = 0;
- device->page_size = 0;
- device->erase_size = 0;
-
- /* initialize controller (device parameters are zero, use controller default) */
- if ((retval = device->controller->init(device) != ERROR_OK))
- {
- switch (retval)
- {
- case ERROR_NAND_OPERATION_FAILED:
- DEBUG("controller initialization failed");
- return ERROR_NAND_OPERATION_FAILED;
- case ERROR_NAND_OPERATION_NOT_SUPPORTED:
- ERROR("BUG: controller reported that it doesn't support default parameters");
- return ERROR_NAND_OPERATION_FAILED;
- default:
- ERROR("BUG: unknown controller initialization failure");
- return ERROR_NAND_OPERATION_FAILED;
- }
- }
-
- device->controller->command(device, NAND_CMD_RESET);
- device->controller->reset(device);
-
- device->controller->command(device, NAND_CMD_READID);
- device->controller->address(device, 0x0);
-
- if (device->bus_width == 8)
- {
- device->controller->read_data(device, &manufacturer_id);
- device->controller->read_data(device, &device_id);
- }
- else
- {
- u16 data_buf;
- device->controller->read_data(device, &data_buf);
- manufacturer_id = data_buf & 0xff;
- device->controller->read_data(device, &data_buf);
- device_id = data_buf & 0xff;
- }
-
- for (i = 0; nand_flash_ids[i].name; i++)
- {
- if (nand_flash_ids[i].id == device_id)
- {
- device->device = &nand_flash_ids[i];
- break;
- }
- }
-
- for (i = 0; nand_manuf_ids[i].name; i++)
- {
- if (nand_manuf_ids[i].id == manufacturer_id)
- {
- device->manufacturer = &nand_manuf_ids[i];
- break;
- }
- }
-
- if (!device->manufacturer)
- {
- device->manufacturer = &nand_manuf_ids[0];
- device->manufacturer->id = manufacturer_id;
- }
-
- if (!device->device)
- {
- ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
- manufacturer_id, device_id);
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- DEBUG("found %s (%s)", device->device->name, device->manufacturer->name);
-
- /* initialize device parameters */
-
- /* bus width */
- if (device->device->options & NAND_BUSWIDTH_16)
- device->bus_width = 16;
- else
- device->bus_width = 8;
-
- /* Do we need extended device probe information? */
- if (device->device->page_size == 0 ||
- device->device->erase_size == 0)
- {
- if (device->bus_width == 8)
- {
- device->controller->read_data(device, id_buff+3);
- device->controller->read_data(device, id_buff+4);
- device->controller->read_data(device, id_buff+5);
- }
- else
- {
- u16 data_buf;
-
- device->controller->read_data(device, &data_buf);
- id_buff[3] = data_buf;
-
- device->controller->read_data(device, &data_buf);
- id_buff[4] = data_buf;
-
- device->controller->read_data(device, &data_buf);
- id_buff[5] = data_buf >> 8;
- }
- }
-
- /* page size */
- if (device->device->page_size == 0)
- {
- device->page_size = 1 << (10 + (id_buff[4] & 3));
- }
- else if (device->device->page_size == 256)
- {
- ERROR("NAND flashes with 256 byte pagesize are not supported");
- return ERROR_NAND_OPERATION_FAILED;
- }
- else
- {
- device->page_size = device->device->page_size;
- }
-
- /* number of address cycles */
- if (device->page_size <= 512)
- {
- /* small page devices */
- if (device->device->chip_size <= 32)
- device->address_cycles = 3;
- else if (device->device->chip_size <= 8*1024)
- device->address_cycles = 4;
- else
- {
- ERROR("BUG: small page NAND device with more than 8 GiB encountered");
- device->address_cycles = 5;
- }
- }
- else
- {
- /* large page devices */
- if (device->device->chip_size <= 128)
- device->address_cycles = 4;
- else if (device->device->chip_size <= 32*1024)
- device->address_cycles = 5;
- else
- {
- ERROR("BUG: small page NAND device with more than 32 GiB encountered");
- device->address_cycles = 6;
- }
- }
-
- /* erase size */
- if (device->device->erase_size == 0)
- {
- switch ((id_buff[4] >> 4) & 3) {
- case 0:
- device->erase_size = 64 << 10;
- break;
- case 1:
- device->erase_size = 128 << 10;
- break;
- case 2:
- device->erase_size = 256 << 10;
- break;
- case 3:
- device->erase_size =512 << 10;
- break;
- }
- }
- else
- {
- device->erase_size = device->device->erase_size;
- }
-
- /* initialize controller, but leave parameters at the controllers default */
- if ((retval = device->controller->init(device) != ERROR_OK))
- {
- switch (retval)
- {
- case ERROR_NAND_OPERATION_FAILED:
- DEBUG("controller initialization failed");
- return ERROR_NAND_OPERATION_FAILED;
- case ERROR_NAND_OPERATION_NOT_SUPPORTED:
- ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
- device->bus_width, device->address_cycles, device->page_size);
- return ERROR_NAND_OPERATION_FAILED;
- default:
- ERROR("BUG: unknown controller initialization failure");
- return ERROR_NAND_OPERATION_FAILED;
- }
- }
-
- device->num_blocks = (device->device->chip_size * 1024) / (device->erase_size / 1024);
- device->blocks = malloc(sizeof(nand_block_t) * device->num_blocks);
-
- for (i = 0; i < device->num_blocks; i++)
- {
- device->blocks[i].size = device->erase_size;
- device->blocks[i].offset = i * device->erase_size;
- device->blocks[i].is_erased = -1;
- device->blocks[i].is_bad = -1;
- }
-
- return ERROR_OK;
-}
-
-int nand_erase(struct nand_device_s *device, int first_block, int last_block)
-{
- int i;
- u32 page;
- u8 status;
- int retval;
-
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- if ((first_block < 0) || (last_block > device->num_blocks))
- return ERROR_INVALID_ARGUMENTS;
-
- /* make sure we know if a block is bad before erasing it */
- for (i = first_block; i <= last_block; i++)
- {
- if (device->blocks[i].is_bad == -1)
- {
- nand_build_bbt(device, i, last_block);
- break;
- }
- }
-
- for (i = first_block; i <= last_block; i++)
- {
- /* Send erase setup command */
- device->controller->command(device, NAND_CMD_ERASE1);
-
- page = i * (device->erase_size / device->page_size);
-
- /* Send page address */
- if (device->page_size <= 512)
- {
- /* row */
- device->controller->address(device, page & 0xff);
- device->controller->address(device, (page >> 8) & 0xff);
-
- /* 3rd cycle only on devices with more than 32 MiB */
- if (device->address_cycles >= 4)
- device->controller->address(device, (page >> 16) & 0xff);
-
- /* 4th cycle only on devices with more than 8 GiB */
- if (device->address_cycles >= 5)
- device->controller->address(device, (page >> 24) & 0xff);
- }
- else
- {
- /* row */
- device->controller->address(device, page & 0xff);
- device->controller->address(device, (page >> 8) & 0xff);
-
- /* 3rd cycle only on devices with more than 128 MiB */
- if (device->address_cycles >= 5)
- device->controller->address(device, (page >> 16) & 0xff);
- }
-
- /* Send erase confirm command */
- device->controller->command(device, NAND_CMD_ERASE2);
-
- if (!device->controller->nand_ready(device, 1000))
- {
- ERROR("timeout waiting for NAND flash block erase to complete");
- return ERROR_NAND_OPERATION_TIMEOUT;
- }
-
- if ((retval = nand_read_status(device, &status)) != ERROR_OK)
- {
- ERROR("couldn't read status");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- if (status & 0x1)
- {
- ERROR("erase operation didn't pass, status: 0x%2.2x", status);
- return ERROR_NAND_OPERATION_FAILED;
- }
- }
-
- return ERROR_OK;
-}
-
-int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)
-{
- u8 *page;
-
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- if (address % device->page_size)
- {
- ERROR("reads need to be page aligned");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- page = malloc(device->page_size);
-
- while (data_size > 0 )
- {
- u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
- u32 page_address;
-
-
- page_address = address / device->page_size;
-
- nand_read_page(device, page_address, page, device->page_size, NULL, 0);
-
- memcpy(data, page, thisrun_size);
-
- address += thisrun_size;
- data += thisrun_size;
- data_size -= thisrun_size;
- }
-
- free(page);
-
- return ERROR_OK;
-}
-
-int nand_write_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)
-{
- u8 *page;
-
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- if (address % device->page_size)
- {
- ERROR("writes need to be page aligned");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- page = malloc(device->page_size);
-
- while (data_size > 0 )
- {
- u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
- u32 page_address;
-
- memset(page, 0xff, device->page_size);
- memcpy(page, data, thisrun_size);
-
- page_address = address / device->page_size;
-
- nand_write_page(device, page_address, page, device->page_size, NULL, 0);
-
- address += thisrun_size;
- data += thisrun_size;
- data_size -= thisrun_size;
- }
-
- free(page);
-
- return ERROR_OK;
-}
-
-int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
-{
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- if (device->use_raw || device->controller->write_page == NULL)
- return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
- else
- return device->controller->write_page(device, page, data, data_size, oob, oob_size);
-}
-
-int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
-{
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- if (device->use_raw || device->controller->read_page == NULL)
- return nand_read_page_raw(device, page, data, data_size, oob, oob_size);
- else
- return device->controller->read_page(device, page, data, data_size, oob, oob_size);
-}
-
-int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
-{
- int i;
-
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- if (device->page_size <= 512)
- {
- /* small page device */
- if (data)
- device->controller->command(device, NAND_CMD_READ0);
- else
- device->controller->command(device, NAND_CMD_READOOB);
-
- /* column (always 0, we start at the beginning of a page/OOB area) */
- device->controller->address(device, 0x0);
-
- /* row */
- device->controller->address(device, page & 0xff);
- device->controller->address(device, (page >> 8) & 0xff);
-
- /* 4th cycle only on devices with more than 32 MiB */
- if (device->address_cycles >= 4)
- device->controller->address(device, (page >> 16) & 0xff);
-
- /* 5th cycle only on devices with more than 8 GiB */
- if (device->address_cycles >= 5)
- device->controller->address(device, (page >> 24) & 0xff);
- }
- else
- {
- /* large page device */
- device->controller->command(device, NAND_CMD_READ0);
-
- /* column (0 when we start at the beginning of a page,
- * or 2048 for the beginning of OOB area)
- */
- device->controller->address(device, 0x0);
- device->controller->address(device, 0x8);
-
- /* row */
- device->controller->address(device, page & 0xff);
- device->controller->address(device, (page >> 8) & 0xff);
-
- /* 5th cycle only on devices with more than 128 MiB */
- if (device->address_cycles >= 5)
- device->controller->address(device, (page >> 16) & 0xff);
-
- /* large page devices need a start command */
- device->controller->command(device, NAND_CMD_READSTART);
- }
-
- if (!device->controller->nand_ready(device, 100))
- return ERROR_NAND_OPERATION_TIMEOUT;
-
- if (data)
- {
- if (device->controller->read_block_data != NULL)
- (device->controller->read_block_data)(device, data, data_size);
- else
- {
- for (i = 0; i < data_size;)
- {
- if (device->device->options & NAND_BUSWIDTH_16)
- {
- device->controller->read_data(device, data);
- data += 2;
- i += 2;
- }
- else
- {
- device->controller->read_data(device, data);
- data += 1;
- i += 1;
- }
- }
- }
- }
-
- if (oob)
- {
- if (device->controller->read_block_data != NULL)
- (device->controller->read_block_data)(device, oob, oob_size);
- else
- {
- for (i = 0; i < oob_size;)
- {
- if (device->device->options & NAND_BUSWIDTH_16)
- {
- device->controller->read_data(device, oob);
- oob += 2;
- i += 2;
- }
- else
- {
- device->controller->read_data(device, oob);
- oob += 1;
- i += 1;
- }
- }
- }
- }
-
- return ERROR_OK;
-}
-
-int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
-{
- int i;
- int retval;
- u8 status;
-
- if (!device->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
-
- device->controller->command(device, NAND_CMD_SEQIN);
-
- if (device->page_size <= 512)
- {
- /* column (always 0, we start at the beginning of a page/OOB area) */
- device->controller->address(device, 0x0);
-
- /* row */
- device->controller->address(device, page & 0xff);
- device->controller->address(device, (page >> 8) & 0xff);
-
- /* 4th cycle only on devices with more than 32 MiB */
- if (device->address_cycles >= 4)
- device->controller->address(device, (page >> 16) & 0xff);
-
- /* 5th cycle only on devices with more than 8 GiB */
- if (device->address_cycles >= 5)
- device->controller->address(device, (page >> 24) & 0xff);
- }
- else
- {
- /* column (0 when we start at the beginning of a page,
- * or 2048 for the beginning of OOB area)
- */
- device->controller->address(device, 0x0);
- device->controller->address(device, 0x8);
-
- /* row */
- device->controller->address(device, page & 0xff);
- device->controller->address(device, (page >> 8) & 0xff);
-
- /* 5th cycle only on devices with more than 128 MiB */
- if (device->address_cycles >= 5)
- device->controller->address(device, (page >> 16) & 0xff);
- }
-
- if (data)
- {
- if (device->controller->write_block_data != NULL)
- (device->controller->write_block_data)(device, data, data_size);
- else
- {
- for (i = 0; i < data_size;)
- {
- if (device->device->options & NAND_BUSWIDTH_16)
- {
- u16 data_buf = le_to_h_u16(data);
- device->controller->write_data(device, data_buf);
- data += 2;
- i += 2;
- }
- else
- {
- device->controller->write_data(device, *data);
- data += 1;
- i += 1;
- }
- }
- }
- }
-
- if (oob)
- {
- if (device->controller->write_block_data != NULL)
- (device->controller->write_block_data)(device, oob, oob_size);
- else
- {
- for (i = 0; i < oob_size;)
- {
- if (device->device->options & NAND_BUSWIDTH_16)
- {
- u16 oob_buf = le_to_h_u16(data);
- device->controller->write_data(device, oob_buf);
- oob += 2;
- i += 2;
- }
- else
- {
- device->controller->write_data(device, *oob);
- oob += 1;
- i += 1;
- }
- }
- }
- }
-
- device->controller->command(device, NAND_CMD_PAGEPROG);
-
- if (!device->controller->nand_ready(device, 100))
- return ERROR_NAND_OPERATION_TIMEOUT;
-
- 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;
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
- int i = 0;
-
- if (!nand_devices)
- {
- command_print(cmd_ctx, "no NAND flash devices configured");
- return ERROR_OK;
- }
-
- for (p = nand_devices; p; p = p->next)
- {
- if (p->device)
- command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
- i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
- else
- command_print(cmd_ctx, "#%i: not probed");
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
- int i = 0;
- int j = 0;
- int first = -1;
- int last = -1;
-
- if ((argc < 1) || (argc > 3))
- {
- command_print(cmd_ctx, "usage: nand info <num> [<first> <last>]");
- return ERROR_OK;
- }
-
- if (argc == 2)
- {
- first = last = strtoul(args[1], NULL, 0);
- }
- else if (argc == 3)
- {
- first = strtoul(args[1], NULL, 0);
- last = strtoul(args[2], NULL, 0);
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- if (p->device)
- {
- if (first >= p->num_blocks)
- first = p->num_blocks - 1;
-
- if (last >= p->num_blocks)
- last = p->num_blocks - 1;
-
- command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
- i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
-
- for (j = first; j <= last; j++)
- {
- char *erase_state, *bad_state;
-
- if (p->blocks[j].is_erased == 0)
- erase_state = "not erased";
- else if (p->blocks[j].is_erased == 1)
- erase_state = "erased";
- else
- erase_state = "erase state unknown";
-
- if (p->blocks[j].is_bad == 0)
- bad_state = "";
- else if (p->blocks[j].is_bad == 1)
- bad_state = " (marked bad)";
- else
- bad_state = " (block condition unknown)";
-
- command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s%s",
- j, p->blocks[j].offset, p->blocks[j].size / 1024,
- erase_state, bad_state);
- }
- }
- else
- {
- command_print(cmd_ctx, "#%i: not probed");
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
- int retval;
-
- if (argc != 1)
- {
- command_print(cmd_ctx, "usage: nand probe <num>");
- return ERROR_OK;
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- if ((retval = nand_probe(p)) == ERROR_OK)
- {
- command_print(cmd_ctx, "NAND flash device '%s' found", p->device->name);
- }
- else if (retval == ERROR_NAND_OPERATION_FAILED)
- {
- command_print(cmd_ctx, "probing failed for NAND flash device");
- }
- else
- {
- command_print(cmd_ctx, "unknown error when probing NAND flash device");
- }
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
- int retval;
-
- if (argc != 3)
- {
- command_print(cmd_ctx, "usage: nand erase <num> <first> <last>");
- return ERROR_OK;
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- int first = strtoul(args[1], NULL, 0);
- int last = strtoul(args[2], NULL, 0);
-
- if ((retval = nand_erase(p, first, last)) == ERROR_OK)
- {
- command_print(cmd_ctx, "successfully erased blocks %i to %i on NAND flash device '%s'", first, last, p->device->name);
- }
- else if (retval == ERROR_NAND_OPERATION_FAILED)
- {
- command_print(cmd_ctx, "erase failed");
- }
- else
- {
- command_print(cmd_ctx, "unknown error when erasing NAND flash device");
- }
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
- int retval;
- int first = -1;
- int last = -1;
-
- if ((argc < 1) || (argc > 3) || (argc == 2))
- {
- command_print(cmd_ctx, "usage: nand check_bad_blocks <num> [<first> <last>]");
- return ERROR_OK;
- }
-
- if (argc == 3)
- {
- first = strtoul(args[1], NULL, 0);
- last = strtoul(args[2], NULL, 0);
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- if ((retval = nand_build_bbt(p, first, last)) == ERROR_OK)
- {
- command_print(cmd_ctx, "checked NAND flash device for bad blocks, use \"nand info\" command to list blocks", p->device->name);
- }
- else if (retval == ERROR_NAND_OPERATION_FAILED)
- {
- command_print(cmd_ctx, "error when checking for bad blocks on NAND flash device");
- }
- else
- {
- command_print(cmd_ctx, "unknown error when checking for bad blocks on NAND flash device");
- }
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
-
- if (argc != 4)
- {
- command_print(cmd_ctx, "usage: nand copy <num> <offset> <length> <ram-address>");
- return ERROR_OK;
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
-
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u32 offset;
- u32 binary_size;
- u32 buf_cnt;
- enum oob_formats oob_format = NAND_OOB_NONE;
-
- fileio_t fileio;
-
- duration_t duration;
- char *duration_text;
-
- nand_device_t *p;
-
- if (argc < 3)
- {
- command_print(cmd_ctx, "usage: nand write <num> <file> <offset> [options]");
- return ERROR_OK;
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- u8 *page = NULL;
- u32 page_size = 0;
- u8 *oob = NULL;
- u32 oob_size = 0;
-
- duration_start_measure(&duration);
- offset = strtoul(args[2], NULL, 0);
-
- if (argc > 3)
- {
- int i;
- for (i = 3; i < argc; i++)
- {
- if (!strcmp(args[i], "oob_raw"))
- oob_format |= NAND_OOB_RAW;
- else if (!strcmp(args[i], "oob_only"))
- oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
- else
- {
- command_print(cmd_ctx, "unknown option: %s", args[i]);
- }
- }
- }
-
- if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
- {
- command_print(cmd_ctx, "file open error: %s", fileio.error_str);
- return ERROR_OK;
- }
-
- buf_cnt = binary_size = fileio.size;
-
- if (!(oob_format & NAND_OOB_ONLY))
- {
- page_size = p->page_size;
- page = malloc(p->page_size);
- }
-
- if (oob_format & NAND_OOB_RAW)
- {
- if (p->page_size == 512)
- oob_size = 16;
- else if (p->page_size == 2048)
- oob_size = 64;
- oob = malloc(oob_size);
- }
-
- if (offset % p->page_size)
- {
- command_print(cmd_ctx, "only page size aligned offsets and sizes are supported");
- return ERROR_OK;
- }
-
- while (buf_cnt > 0)
- {
- u32 size_read;
-
- if (page)
- {
- fileio_read(&fileio, page_size, page, &size_read);
- buf_cnt -= size_read;
- if (size_read < page_size)
- {
- memset(page + size_read, 0xff, page_size - size_read);
- }
- }
-
- if (oob)
- {
- fileio_read(&fileio, oob_size, oob, &size_read);
- buf_cnt -= size_read;
- if (size_read < oob_size)
- {
- memset(oob + size_read, 0xff, oob_size - size_read);
- }
- }
-
- if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK)
- {
- command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x",
- args[1], args[0], offset);
- return ERROR_OK;
- }
- offset += page_size;
- }
-
- fileio_close(&fileio);
-
- duration_stop_measure(&duration, &duration_text);
- command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s",
- args[1], args[0], offset, duration_text);
- free(duration_text);
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
-
- if (argc < 4)
- {
- command_print(cmd_ctx, "usage: nand dump <num> <filename> <address> <size> [options]");
- return ERROR_OK;
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- if (p->device)
- {
- fileio_t fileio;
- duration_t duration;
- char *duration_text;
- int retval;
-
- u8 *page = NULL;
- u32 page_size = 0;
- u8 *oob = NULL;
- u32 oob_size = 0;
- u32 address = strtoul(args[2], NULL, 0);
- u32 size = strtoul(args[3], NULL, 0);
- u32 bytes_done = 0;
- enum oob_formats oob_format = NAND_OOB_NONE;
-
- if (argc > 4)
- {
- int i;
- for (i = 4; i < argc; i++)
- {
- if (!strcmp(args[i], "oob_raw"))
- oob_format |= NAND_OOB_RAW;
- else if (!strcmp(args[i], "oob_only"))
- oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
- else
- command_print(cmd_ctx, "unknown option: '%s'", args[i]);
- }
- }
-
- if ((address % p->page_size) || (size % p->page_size))
- {
- command_print(cmd_ctx, "only page size aligned addresses and sizes are supported");
- return ERROR_OK;
- }
-
- if (!(oob_format & NAND_OOB_ONLY))
- {
- page_size = p->page_size;
- page = malloc(p->page_size);
- }
-
- if (oob_format & NAND_OOB_RAW)
- {
- if (p->page_size == 512)
- oob_size = 16;
- else if (p->page_size == 2048)
- oob_size = 64;
- oob = malloc(oob_size);
- }
-
- if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
- {
- command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);
- return ERROR_OK;
- }
-
- duration_start_measure(&duration);
-
- while (size > 0)
- {
- u32 size_written;
- if ((retval = nand_read_page(p, address / p->page_size, page, page_size, oob, oob_size)) != ERROR_OK)
- {
- command_print(cmd_ctx, "reading NAND flash page failed");
- return ERROR_OK;
- }
-
- if (page)
- {
- fileio_write(&fileio, page_size, page, &size_written);
- bytes_done += page_size;
- }
-
- if (oob)
- {
- fileio_write(&fileio, oob_size, oob, &size_written);
- bytes_done += oob_size;
- }
-
- size -= p->page_size;
- address += p->page_size;
- }
-
- if (page)
- free(page);
-
- if (oob)
- free(oob);
-
- fileio_close(&fileio);
-
- duration_stop_measure(&duration, &duration_text);
- command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text);
- free(duration_text);
- }
- else
- {
- command_print(cmd_ctx, "#%i: not probed");
- }
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
-int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- nand_device_t *p;
-
- if ((argc < 1) || (argc > 2))
- {
- command_print(cmd_ctx, "usage: nand raw_access <num> ['enable'|'disable']");
- return ERROR_OK;
- }
-
- p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
- if (p)
- {
- if (p->device)
- {
- if (argc == 2)
- {
- if (strcmp("enable", args[1]) == 0)
- {
- p->use_raw = 1;
- }
- else if (strcmp("disable", args[1]) == 0)
- {
- p->use_raw = 0;
- }
- else
- {
- command_print(cmd_ctx, "usage: nand raw_access ['enable'|disable']");
- }
- }
-
- command_print(cmd_ctx, "raw access is %s", (p->use_raw) ? "enabled" : "disabled");
- }
- else
- {
- command_print(cmd_ctx, "#%i: not probed");
- }
- }
- else
- {
- command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
- }
-
- return ERROR_OK;
-}
-
+/***************************************************************************\r
+ * Copyright (C) 2007 by Dominic Rath *\r
+ * Dominic.Rath@gmx.de *\r
+ * *\r
+ * partially based on *\r
+ * drivers/mtd/nand_ids.c *\r
+ * *\r
+ * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.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 "replacements.h"\r
+#include "log.h"\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <inttypes.h>\r
+\r
+#include <errno.h>\r
+\r
+#include "nand.h"\r
+#include "flash.h"\r
+#include "time_support.h"\r
+#include "fileio.h"\r
+#include "image.h"\r
+\r
+int nand_register_commands(struct command_context_s *cmd_ctx);\r
+int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);\r
+int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);\r
+int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size);\r
+\r
+int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);\r
+int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);\r
+\r
+/* NAND flash controller\r
+ */\r
+extern nand_flash_controller_t lpc3180_nand_controller;\r
+extern nand_flash_controller_t s3c2410_nand_controller;\r
+extern nand_flash_controller_t s3c2412_nand_controller;\r
+extern nand_flash_controller_t s3c2440_nand_controller;\r
+extern nand_flash_controller_t s3c2443_nand_controller;\r
+\r
+/* extern nand_flash_controller_t boundary_scan_nand_controller; */\r
+\r
+nand_flash_controller_t *nand_flash_controllers[] =\r
+{\r
+ &lpc3180_nand_controller,\r
+ &s3c2410_nand_controller,\r
+ &s3c2412_nand_controller,\r
+ &s3c2440_nand_controller,\r
+ &s3c2443_nand_controller,\r
+/* &boundary_scan_nand_controller, */\r
+ NULL\r
+};\r
+\r
+/* configured NAND devices and NAND Flash command handler */\r
+nand_device_t *nand_devices = NULL;\r
+static command_t *nand_cmd;\r
+\r
+/* Chip ID list\r
+ *\r
+ * Name, ID code, pagesize, chipsize in MegaByte, eraseblock size,\r
+ * options\r
+ *\r
+ * Pagesize; 0, 256, 512\r
+ * 0 get this information from the extended chip ID\r
+ * 256 256 Byte page size\r
+ * 512 512 Byte page size\r
+ */\r
+nand_info_t nand_flash_ids[] =\r
+{\r
+ {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},\r
+ {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},\r
+ {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},\r
+ {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},\r
+ {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},\r
+ {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},\r
+ {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},\r
+ {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},\r
+ {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},\r
+ {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},\r
+\r
+ {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},\r
+ {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},\r
+ {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},\r
+ {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},\r
+\r
+ {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},\r
+ {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},\r
+ {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},\r
+ {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},\r
+\r
+ {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},\r
+ {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},\r
+ {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},\r
+ {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},\r
+\r
+ {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},\r
+ {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},\r
+ {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},\r
+ {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},\r
+\r
+ {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},\r
+ {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},\r
+ {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},\r
+ {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},\r
+ {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},\r
+ {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},\r
+ {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},\r
+\r
+ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},\r
+\r
+ {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},\r
+ {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},\r
+ {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},\r
+ {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},\r
+\r
+ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},\r
+ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},\r
+ {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},\r
+ {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},\r
+\r
+ {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},\r
+ {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},\r
+ {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},\r
+ {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},\r
+\r
+ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},\r
+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},\r
+ {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},\r
+ {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},\r
+\r
+ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},\r
+ {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},\r
+ {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},\r
+ {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},\r
+\r
+ {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},\r
+ {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},\r
+ {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},\r
+ {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},\r
+\r
+ {NULL, 0,}\r
+};\r
+\r
+/* Manufacturer ID list\r
+ */\r
+nand_manufacturer_t nand_manuf_ids[] =\r
+{\r
+ {0x0, "unknown"},\r
+ {NAND_MFR_TOSHIBA, "Toshiba"},\r
+ {NAND_MFR_SAMSUNG, "Samsung"},\r
+ {NAND_MFR_FUJITSU, "Fujitsu"},\r
+ {NAND_MFR_NATIONAL, "National"},\r
+ {NAND_MFR_RENESAS, "Renesas"},\r
+ {NAND_MFR_STMICRO, "ST Micro"},\r
+ {NAND_MFR_HYNIX, "Hynix"},\r
+ {0x0, NULL},\r
+};\r
+\r
+/* nand device <nand_controller> [controller options]\r
+ */\r
+int handle_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ int i;\r
+ int retval;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ WARNING("incomplete flash device nand configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ for (i = 0; nand_flash_controllers[i]; i++)\r
+ {\r
+ nand_device_t *p, *c;\r
+ \r
+ if (strcmp(args[0], nand_flash_controllers[i]->name) == 0)\r
+ {\r
+ /* register flash specific commands */\r
+ if (nand_flash_controllers[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(nand_device_t));\r
+\r
+ c->controller = nand_flash_controllers[i];\r
+ c->controller_priv = NULL;\r
+ c->manufacturer = NULL;\r
+ c->device = NULL;\r
+ c->bus_width = 0;\r
+ c->address_cycles = 0;\r
+ c->page_size = 0;\r
+ c->use_raw = 0;\r
+ c->next = NULL;\r
+\r
+ if ((retval = nand_flash_controllers[i]->nand_device_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)\r
+ {\r
+ ERROR("'%s' driver rejected nand flash", c->controller->name);\r
+ free(c);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ /* put NAND device in linked list */\r
+ if (nand_devices)\r
+ {\r
+ /* find last flash device */\r
+ for (p = nand_devices; p && p->next; p = p->next);\r
+ if (p)\r
+ p->next = c;\r
+ }\r
+ else\r
+ {\r
+ nand_devices = c;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+ }\r
+ }\r
+\r
+ /* no valid NAND controller was found (i.e. the configuration option,\r
+ * didn't match one of the compiled-in controllers)\r
+ */\r
+ ERROR("No valid NAND flash controller found (%s)", args[0]);\r
+ ERROR("compiled-in NAND flash controllers:");\r
+ for (i = 0; nand_flash_controllers[i]; i++)\r
+ {\r
+ ERROR("%i: %s", i, nand_flash_controllers[i]->name);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ nand_cmd = register_command(cmd_ctx, NULL, "nand", NULL, COMMAND_ANY, "NAND specific commands");\r
+ \r
+ register_command(cmd_ctx, nand_cmd, "device", handle_nand_device_command, COMMAND_CONFIG, NULL);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_init(struct command_context_s *cmd_ctx)\r
+{\r
+ if (nand_devices)\r
+ {\r
+ register_command(cmd_ctx, nand_cmd, "list", handle_nand_list_command, COMMAND_EXEC,\r
+ "list configured NAND flash devices");\r
+ register_command(cmd_ctx, nand_cmd, "info", handle_nand_info_command, COMMAND_EXEC,\r
+ "print info about NAND flash device <num>");\r
+ register_command(cmd_ctx, nand_cmd, "probe", handle_nand_probe_command, COMMAND_EXEC,\r
+ "identify NAND flash device <num>");\r
+ register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC,\r
+ "check NAND flash device <num> for bad blocks [<first> <last>]");\r
+ register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC,\r
+ "erase blocks on NAND flash device <num> <first> <last>");\r
+ register_command(cmd_ctx, nand_cmd, "copy", handle_nand_copy_command, COMMAND_EXEC,\r
+ "copy from NAND flash device <num> <offset> <length> <ram-address>");\r
+ register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC,\r
+ "dump from NAND flash device <num> <filename> <offset> <size> [options]");\r
+ register_command(cmd_ctx, nand_cmd, "write", handle_nand_write_command, COMMAND_EXEC,\r
+ "write to NAND flash device <num> <filename> <offset> [options]");\r
+ register_command(cmd_ctx, nand_cmd, "raw_access", handle_nand_raw_access_command, COMMAND_EXEC,\r
+ "raw access to NAND flash device <num> ['enable'|'disable']");\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+nand_device_t *get_nand_device_by_num(int num)\r
+{\r
+ nand_device_t *p;\r
+ int i = 0;\r
+\r
+ for (p = nand_devices; p; p = p->next)\r
+ {\r
+ if (i++ == num)\r
+ {\r
+ return p;\r
+ }\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+int nand_build_bbt(struct nand_device_s *device, int first, int last)\r
+{\r
+ u32 page = 0x0;\r
+ int i;\r
+ u8 *oob;\r
+ \r
+ oob = malloc(6);\r
+ \r
+ if ((first < 0) || (first >= device->num_blocks))\r
+ first = 0;\r
+ \r
+ if ((last >= device->num_blocks) || (last == -1))\r
+ last = device->num_blocks - 1;\r
+ \r
+ for (i = first; i < last; i++)\r
+ {\r
+ nand_read_page(device, page, NULL, 0, oob, 6);\r
+ \r
+ if (((device->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))\r
+ || (((device->page_size == 512) && (oob[5] != 0xff)) ||\r
+ ((device->page_size == 2048) && (oob[0] != 0xff))))\r
+ {\r
+ WARNING("invalid block: %i", i);\r
+ device->blocks[i].is_bad = 1;\r
+ }\r
+ else\r
+ {\r
+ device->blocks[i].is_bad = 0;\r
+ }\r
+ \r
+ page += (device->erase_size / device->page_size);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_read_status(struct nand_device_s *device, u8 *status)\r
+{\r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+ \r
+ /* Send read status command */\r
+ device->controller->command(device, NAND_CMD_STATUS);\r
+ \r
+ usleep(1000);\r
+ \r
+ /* read status */\r
+ if (device->device->options & NAND_BUSWIDTH_16)\r
+ {\r
+ u16 data;\r
+ device->controller->read_data(device, &data);\r
+ *status = data & 0xff;\r
+ }\r
+ else\r
+ {\r
+ device->controller->read_data(device, status);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_probe(struct nand_device_s *device)\r
+{\r
+ u8 manufacturer_id, device_id;\r
+ u8 id_buff[5];\r
+ int retval;\r
+ int i;\r
+\r
+ /* clear device data */\r
+ device->device = NULL;\r
+ device->manufacturer = NULL;\r
+ \r
+ /* clear device parameters */\r
+ device->bus_width = 0;\r
+ device->address_cycles = 0;\r
+ device->page_size = 0;\r
+ device->erase_size = 0;\r
+ \r
+ /* initialize controller (device parameters are zero, use controller default) */\r
+ if ((retval = device->controller->init(device) != ERROR_OK))\r
+ {\r
+ switch (retval)\r
+ {\r
+ case ERROR_NAND_OPERATION_FAILED:\r
+ DEBUG("controller initialization failed");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ case ERROR_NAND_OPERATION_NOT_SUPPORTED:\r
+ ERROR("BUG: controller reported that it doesn't support default parameters");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ default:\r
+ ERROR("BUG: unknown controller initialization failure");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ device->controller->command(device, NAND_CMD_RESET);\r
+ device->controller->reset(device);\r
+\r
+ device->controller->command(device, NAND_CMD_READID);\r
+ device->controller->address(device, 0x0);\r
+ \r
+ if (device->bus_width == 8)\r
+ {\r
+ device->controller->read_data(device, &manufacturer_id);\r
+ device->controller->read_data(device, &device_id);\r
+ }\r
+ else\r
+ {\r
+ u16 data_buf;\r
+ device->controller->read_data(device, &data_buf);\r
+ manufacturer_id = data_buf & 0xff;\r
+ device->controller->read_data(device, &data_buf);\r
+ device_id = data_buf & 0xff;\r
+ }\r
+ \r
+ for (i = 0; nand_flash_ids[i].name; i++)\r
+ {\r
+ if (nand_flash_ids[i].id == device_id)\r
+ {\r
+ device->device = &nand_flash_ids[i];\r
+ break;\r
+ }\r
+ }\r
+ \r
+ for (i = 0; nand_manuf_ids[i].name; i++)\r
+ {\r
+ if (nand_manuf_ids[i].id == manufacturer_id)\r
+ {\r
+ device->manufacturer = &nand_manuf_ids[i];\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if (!device->manufacturer)\r
+ {\r
+ device->manufacturer = &nand_manuf_ids[0];\r
+ device->manufacturer->id = manufacturer_id;\r
+ }\r
+ \r
+ if (!device->device)\r
+ {\r
+ ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",\r
+ manufacturer_id, device_id);\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ DEBUG("found %s (%s)", device->device->name, device->manufacturer->name);\r
+ \r
+ /* initialize device parameters */\r
+ \r
+ /* bus width */ \r
+ if (device->device->options & NAND_BUSWIDTH_16)\r
+ device->bus_width = 16;\r
+ else\r
+ device->bus_width = 8;\r
+\r
+ /* Do we need extended device probe information? */\r
+ if (device->device->page_size == 0 ||\r
+ device->device->erase_size == 0)\r
+ {\r
+ if (device->bus_width == 8)\r
+ {\r
+ device->controller->read_data(device, id_buff+3);\r
+ device->controller->read_data(device, id_buff+4);\r
+ device->controller->read_data(device, id_buff+5);\r
+ }\r
+ else\r
+ {\r
+ u16 data_buf;\r
+\r
+ device->controller->read_data(device, &data_buf);\r
+ id_buff[3] = data_buf;\r
+\r
+ device->controller->read_data(device, &data_buf);\r
+ id_buff[4] = data_buf;\r
+\r
+ device->controller->read_data(device, &data_buf);\r
+ id_buff[5] = data_buf >> 8;\r
+ }\r
+ }\r
+ \r
+ /* page size */\r
+ if (device->device->page_size == 0)\r
+ {\r
+ device->page_size = 1 << (10 + (id_buff[4] & 3));\r
+ }\r
+ else if (device->device->page_size == 256)\r
+ {\r
+ ERROR("NAND flashes with 256 byte pagesize are not supported");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ else\r
+ {\r
+ device->page_size = device->device->page_size;\r
+ }\r
+ \r
+ /* number of address cycles */\r
+ if (device->page_size <= 512)\r
+ {\r
+ /* small page devices */\r
+ if (device->device->chip_size <= 32)\r
+ device->address_cycles = 3;\r
+ else if (device->device->chip_size <= 8*1024)\r
+ device->address_cycles = 4;\r
+ else\r
+ {\r
+ ERROR("BUG: small page NAND device with more than 8 GiB encountered");\r
+ device->address_cycles = 5;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* large page devices */\r
+ if (device->device->chip_size <= 128)\r
+ device->address_cycles = 4;\r
+ else if (device->device->chip_size <= 32*1024)\r
+ device->address_cycles = 5;\r
+ else\r
+ {\r
+ ERROR("BUG: small page NAND device with more than 32 GiB encountered");\r
+ device->address_cycles = 6;\r
+ }\r
+ }\r
+ \r
+ /* erase size */\r
+ if (device->device->erase_size == 0)\r
+ {\r
+ switch ((id_buff[4] >> 4) & 3) {\r
+ case 0:\r
+ device->erase_size = 64 << 10;\r
+ break;\r
+ case 1:\r
+ device->erase_size = 128 << 10;\r
+ break;\r
+ case 2:\r
+ device->erase_size = 256 << 10;\r
+ break;\r
+ case 3:\r
+ device->erase_size =512 << 10;\r
+ break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ device->erase_size = device->device->erase_size;\r
+ }\r
+ \r
+ /* initialize controller, but leave parameters at the controllers default */\r
+ if ((retval = device->controller->init(device) != ERROR_OK))\r
+ {\r
+ switch (retval)\r
+ {\r
+ case ERROR_NAND_OPERATION_FAILED:\r
+ DEBUG("controller initialization failed");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ case ERROR_NAND_OPERATION_NOT_SUPPORTED:\r
+ ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",\r
+ device->bus_width, device->address_cycles, device->page_size);\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ default:\r
+ ERROR("BUG: unknown controller initialization failure");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ device->num_blocks = (device->device->chip_size * 1024) / (device->erase_size / 1024);\r
+ device->blocks = malloc(sizeof(nand_block_t) * device->num_blocks);\r
+ \r
+ for (i = 0; i < device->num_blocks; i++)\r
+ {\r
+ device->blocks[i].size = device->erase_size;\r
+ device->blocks[i].offset = i * device->erase_size;\r
+ device->blocks[i].is_erased = -1;\r
+ device->blocks[i].is_bad = -1;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_erase(struct nand_device_s *device, int first_block, int last_block)\r
+{\r
+ int i;\r
+ u32 page;\r
+ u8 status;\r
+ int retval;\r
+ \r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+ \r
+ if ((first_block < 0) || (last_block > device->num_blocks))\r
+ return ERROR_INVALID_ARGUMENTS;\r
+ \r
+ /* make sure we know if a block is bad before erasing it */\r
+ for (i = first_block; i <= last_block; i++)\r
+ {\r
+ if (device->blocks[i].is_bad == -1)\r
+ {\r
+ nand_build_bbt(device, i, last_block);\r
+ break;\r
+ }\r
+ }\r
+ \r
+ for (i = first_block; i <= last_block; i++)\r
+ {\r
+ /* Send erase setup command */\r
+ device->controller->command(device, NAND_CMD_ERASE1);\r
+ \r
+ page = i * (device->erase_size / device->page_size);\r
+ \r
+ /* Send page address */\r
+ if (device->page_size <= 512)\r
+ {\r
+ /* row */\r
+ device->controller->address(device, page & 0xff);\r
+ device->controller->address(device, (page >> 8) & 0xff);\r
+ \r
+ /* 3rd cycle only on devices with more than 32 MiB */\r
+ if (device->address_cycles >= 4)\r
+ device->controller->address(device, (page >> 16) & 0xff);\r
+ \r
+ /* 4th cycle only on devices with more than 8 GiB */\r
+ if (device->address_cycles >= 5)\r
+ device->controller->address(device, (page >> 24) & 0xff);\r
+ }\r
+ else\r
+ {\r
+ /* row */\r
+ device->controller->address(device, page & 0xff);\r
+ device->controller->address(device, (page >> 8) & 0xff);\r
+ \r
+ /* 3rd cycle only on devices with more than 128 MiB */\r
+ if (device->address_cycles >= 5)\r
+ device->controller->address(device, (page >> 16) & 0xff);\r
+ }\r
+ \r
+ /* Send erase confirm command */\r
+ device->controller->command(device, NAND_CMD_ERASE2);\r
+ \r
+ if (!device->controller->nand_ready(device, 1000))\r
+ {\r
+ ERROR("timeout waiting for NAND flash block erase to complete");\r
+ return ERROR_NAND_OPERATION_TIMEOUT;\r
+ }\r
+ \r
+ if ((retval = nand_read_status(device, &status)) != ERROR_OK)\r
+ {\r
+ ERROR("couldn't read status");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (status & 0x1)\r
+ {\r
+ ERROR("erase operation didn't pass, status: 0x%2.2x", status);\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)\r
+{\r
+ u8 *page;\r
+ \r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+ \r
+ if (address % device->page_size)\r
+ {\r
+ ERROR("reads need to be page aligned");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ page = malloc(device->page_size);\r
+ \r
+ while (data_size > 0 )\r
+ {\r
+ u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;\r
+ u32 page_address;\r
+ \r
+ \r
+ page_address = address / device->page_size;\r
+ \r
+ nand_read_page(device, page_address, page, device->page_size, NULL, 0);\r
+\r
+ memcpy(data, page, thisrun_size);\r
+ \r
+ address += thisrun_size;\r
+ data += thisrun_size;\r
+ data_size -= thisrun_size;\r
+ }\r
+ \r
+ free(page);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_write_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)\r
+{\r
+ u8 *page;\r
+ \r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+ \r
+ if (address % device->page_size)\r
+ {\r
+ ERROR("writes need to be page aligned");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ page = malloc(device->page_size);\r
+ \r
+ while (data_size > 0 )\r
+ {\r
+ u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;\r
+ u32 page_address;\r
+ \r
+ memset(page, 0xff, device->page_size);\r
+ memcpy(page, data, thisrun_size);\r
+ \r
+ page_address = address / device->page_size;\r
+ \r
+ nand_write_page(device, page_address, page, device->page_size, NULL, 0);\r
+ \r
+ address += thisrun_size;\r
+ data += thisrun_size;\r
+ data_size -= thisrun_size;\r
+ }\r
+ \r
+ free(page);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
+{\r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+ \r
+ if (device->use_raw || device->controller->write_page == NULL)\r
+ return nand_write_page_raw(device, page, data, data_size, oob, oob_size);\r
+ else\r
+ return device->controller->write_page(device, page, data, data_size, oob, oob_size);\r
+}\r
+\r
+int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
+{\r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+ \r
+ if (device->use_raw || device->controller->read_page == NULL)\r
+ return nand_read_page_raw(device, page, data, data_size, oob, oob_size);\r
+ else\r
+ return device->controller->read_page(device, page, data, data_size, oob, oob_size);\r
+}\r
+\r
+int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
+{\r
+ int i;\r
+ \r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+\r
+ if (device->page_size <= 512)\r
+ {\r
+ /* small page device */\r
+ if (data)\r
+ device->controller->command(device, NAND_CMD_READ0);\r
+ else\r
+ device->controller->command(device, NAND_CMD_READOOB);\r
+ \r
+ /* column (always 0, we start at the beginning of a page/OOB area) */\r
+ device->controller->address(device, 0x0);\r
+ \r
+ /* row */\r
+ device->controller->address(device, page & 0xff);\r
+ device->controller->address(device, (page >> 8) & 0xff);\r
+ \r
+ /* 4th cycle only on devices with more than 32 MiB */\r
+ if (device->address_cycles >= 4)\r
+ device->controller->address(device, (page >> 16) & 0xff);\r
+\r
+ /* 5th cycle only on devices with more than 8 GiB */\r
+ if (device->address_cycles >= 5)\r
+ device->controller->address(device, (page >> 24) & 0xff);\r
+ }\r
+ else\r
+ {\r
+ /* large page device */\r
+ device->controller->command(device, NAND_CMD_READ0);\r
+ \r
+ /* column (0 when we start at the beginning of a page,\r
+ * or 2048 for the beginning of OOB area)\r
+ */\r
+ device->controller->address(device, 0x0);\r
+ device->controller->address(device, 0x8);\r
+ \r
+ /* row */\r
+ device->controller->address(device, page & 0xff);\r
+ device->controller->address(device, (page >> 8) & 0xff);\r
+\r
+ /* 5th cycle only on devices with more than 128 MiB */\r
+ if (device->address_cycles >= 5)\r
+ device->controller->address(device, (page >> 16) & 0xff);\r
+\r
+ /* large page devices need a start command */\r
+ device->controller->command(device, NAND_CMD_READSTART);\r
+ }\r
+ \r
+ if (!device->controller->nand_ready(device, 100))\r
+ return ERROR_NAND_OPERATION_TIMEOUT;\r
+ \r
+ if (data)\r
+ {\r
+ if (device->controller->read_block_data != NULL)\r
+ (device->controller->read_block_data)(device, data, data_size);\r
+ else\r
+ {\r
+ for (i = 0; i < data_size;)\r
+ {\r
+ if (device->device->options & NAND_BUSWIDTH_16)\r
+ {\r
+ device->controller->read_data(device, data);\r
+ data += 2;\r
+ i += 2;\r
+ }\r
+ else\r
+ {\r
+ device->controller->read_data(device, data);\r
+ data += 1;\r
+ i += 1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (oob)\r
+ {\r
+ if (device->controller->read_block_data != NULL)\r
+ (device->controller->read_block_data)(device, oob, oob_size);\r
+ else\r
+ {\r
+ for (i = 0; i < oob_size;)\r
+ {\r
+ if (device->device->options & NAND_BUSWIDTH_16)\r
+ {\r
+ device->controller->read_data(device, oob);\r
+ oob += 2;\r
+ i += 2;\r
+ }\r
+ else\r
+ {\r
+ device->controller->read_data(device, oob);\r
+ oob += 1;\r
+ i += 1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ return ERROR_OK; \r
+}\r
+\r
+int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)\r
+{\r
+ int i;\r
+ int retval;\r
+ u8 status;\r
+ \r
+ if (!device->device)\r
+ return ERROR_NAND_DEVICE_NOT_PROBED;\r
+\r
+ device->controller->command(device, NAND_CMD_SEQIN);\r
+ \r
+ if (device->page_size <= 512)\r
+ {\r
+ /* column (always 0, we start at the beginning of a page/OOB area) */\r
+ device->controller->address(device, 0x0);\r
+ \r
+ /* row */\r
+ device->controller->address(device, page & 0xff);\r
+ device->controller->address(device, (page >> 8) & 0xff);\r
+ \r
+ /* 4th cycle only on devices with more than 32 MiB */\r
+ if (device->address_cycles >= 4)\r
+ device->controller->address(device, (page >> 16) & 0xff);\r
+\r
+ /* 5th cycle only on devices with more than 8 GiB */\r
+ if (device->address_cycles >= 5)\r
+ device->controller->address(device, (page >> 24) & 0xff);\r
+ }\r
+ else\r
+ {\r
+ /* column (0 when we start at the beginning of a page,\r
+ * or 2048 for the beginning of OOB area)\r
+ */\r
+ device->controller->address(device, 0x0);\r
+ device->controller->address(device, 0x8);\r
+ \r
+ /* row */\r
+ device->controller->address(device, page & 0xff);\r
+ device->controller->address(device, (page >> 8) & 0xff);\r
+\r
+ /* 5th cycle only on devices with more than 128 MiB */\r
+ if (device->address_cycles >= 5)\r
+ device->controller->address(device, (page >> 16) & 0xff);\r
+ }\r
+ \r
+ if (data)\r
+ {\r
+ if (device->controller->write_block_data != NULL)\r
+ (device->controller->write_block_data)(device, data, data_size);\r
+ else\r
+ {\r
+ for (i = 0; i < data_size;)\r
+ {\r
+ if (device->device->options & NAND_BUSWIDTH_16)\r
+ {\r
+ u16 data_buf = le_to_h_u16(data);\r
+ device->controller->write_data(device, data_buf);\r
+ data += 2;\r
+ i += 2;\r
+ }\r
+ else\r
+ {\r
+ device->controller->write_data(device, *data);\r
+ data += 1;\r
+ i += 1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (oob)\r
+ {\r
+ if (device->controller->write_block_data != NULL)\r
+ (device->controller->write_block_data)(device, oob, oob_size);\r
+ else\r
+ {\r
+ for (i = 0; i < oob_size;)\r
+ {\r
+ if (device->device->options & NAND_BUSWIDTH_16)\r
+ {\r
+ u16 oob_buf = le_to_h_u16(data);\r
+ device->controller->write_data(device, oob_buf);\r
+ oob += 2;\r
+ i += 2;\r
+ }\r
+ else\r
+ {\r
+ device->controller->write_data(device, *oob);\r
+ oob += 1;\r
+ i += 1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ device->controller->command(device, NAND_CMD_PAGEPROG);\r
+ \r
+ if (!device->controller->nand_ready(device, 100))\r
+ return ERROR_NAND_OPERATION_TIMEOUT;\r
+ \r
+ if ((retval = nand_read_status(device, &status)) != ERROR_OK)\r
+ {\r
+ ERROR("couldn't read status");\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (status & NAND_STATUS_FAIL)\r
+ {\r
+ ERROR("write operation didn't pass, status: 0x%2.2x", status);\r
+ return ERROR_NAND_OPERATION_FAILED;\r
+ }\r
+ \r
+ return ERROR_OK; \r
+}\r
+\r
+int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ int i = 0;\r
+ \r
+ if (!nand_devices)\r
+ {\r
+ command_print(cmd_ctx, "no NAND flash devices configured");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ for (p = nand_devices; p; p = p->next)\r
+ {\r
+ if (p->device)\r
+ command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",\r
+ i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);\r
+ else\r
+ command_print(cmd_ctx, "#%i: not probed");\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ int i = 0;\r
+ int j = 0;\r
+ int first = -1;\r
+ int last = -1;\r
+ \r
+ if ((argc < 1) || (argc > 3))\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ }\r
+ \r
+ if (argc == 2)\r
+ {\r
+ first = last = strtoul(args[1], NULL, 0);\r
+ }\r
+ else if (argc == 3)\r
+ {\r
+ first = strtoul(args[1], NULL, 0);\r
+ last = strtoul(args[2], NULL, 0);\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ if (p->device)\r
+ {\r
+ if (first >= p->num_blocks)\r
+ first = p->num_blocks - 1;\r
+ \r
+ if (last >= p->num_blocks)\r
+ last = p->num_blocks - 1;\r
+ \r
+ command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",\r
+ i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);\r
+ \r
+ for (j = first; j <= last; j++)\r
+ {\r
+ char *erase_state, *bad_state;\r
+ \r
+ if (p->blocks[j].is_erased == 0)\r
+ erase_state = "not erased";\r
+ else if (p->blocks[j].is_erased == 1)\r
+ erase_state = "erased";\r
+ else\r
+ erase_state = "erase state unknown";\r
+ \r
+ if (p->blocks[j].is_bad == 0)\r
+ bad_state = "";\r
+ else if (p->blocks[j].is_bad == 1)\r
+ bad_state = " (marked bad)";\r
+ else\r
+ bad_state = " (block condition unknown)";\r
+\r
+ command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s%s",\r
+ j, p->blocks[j].offset, p->blocks[j].size / 1024,\r
+ erase_state, bad_state);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "#%i: not probed");\r
+ }\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ int retval;\r
+ \r
+ if (argc != 1)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ if ((retval = nand_probe(p)) == ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '%s' found", p->device->name);\r
+ }\r
+ else if (retval == ERROR_NAND_OPERATION_FAILED)\r
+ {\r
+ command_print(cmd_ctx, "probing failed for NAND flash device");\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "unknown error when probing NAND flash device");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ int retval;\r
+ \r
+ if (argc != 3)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ int first = strtoul(args[1], NULL, 0);\r
+ int last = strtoul(args[2], NULL, 0);\r
+ \r
+ if ((retval = nand_erase(p, first, last)) == ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "successfully erased blocks %i to %i on NAND flash device '%s'", first, last, p->device->name);\r
+ }\r
+ else if (retval == ERROR_NAND_OPERATION_FAILED)\r
+ {\r
+ command_print(cmd_ctx, "erase failed");\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "unknown error when erasing NAND flash device");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ int retval;\r
+ int first = -1;\r
+ int last = -1;\r
+ \r
+ if ((argc < 1) || (argc > 3) || (argc == 2))\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ }\r
+ \r
+ if (argc == 3)\r
+ {\r
+ first = strtoul(args[1], NULL, 0);\r
+ last = strtoul(args[2], NULL, 0);\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ if ((retval = nand_build_bbt(p, first, last)) == ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "checked NAND flash device for bad blocks, use \"nand info\" command to list blocks", p->device->name);\r
+ }\r
+ else if (retval == ERROR_NAND_OPERATION_FAILED)\r
+ {\r
+ command_print(cmd_ctx, "error when checking for bad blocks on NAND flash device");\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "unknown error when checking for bad blocks on NAND flash device");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ \r
+ if (argc != 4)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ u32 offset;\r
+ u32 binary_size;\r
+ u32 buf_cnt;\r
+ enum oob_formats oob_format = NAND_OOB_NONE;\r
+ \r
+ fileio_t fileio;\r
+ \r
+ duration_t duration;\r
+ char *duration_text;\r
+ \r
+ nand_device_t *p;\r
+ \r
+ if (argc < 3)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ u8 *page = NULL;\r
+ u32 page_size = 0;\r
+ u8 *oob = NULL;\r
+ u32 oob_size = 0;\r
+ \r
+ duration_start_measure(&duration);\r
+ offset = strtoul(args[2], NULL, 0);\r
+ \r
+ if (argc > 3)\r
+ {\r
+ int i;\r
+ for (i = 3; i < argc; i++)\r
+ {\r
+ if (!strcmp(args[i], "oob_raw"))\r
+ oob_format |= NAND_OOB_RAW;\r
+ else if (!strcmp(args[i], "oob_only"))\r
+ oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "unknown option: %s", args[i]);\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "file open error: %s", fileio.error_str);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ buf_cnt = binary_size = fileio.size;\r
+ \r
+ if (!(oob_format & NAND_OOB_ONLY))\r
+ {\r
+ page_size = p->page_size;\r
+ page = malloc(p->page_size);\r
+ }\r
+\r
+ if (oob_format & NAND_OOB_RAW)\r
+ {\r
+ if (p->page_size == 512)\r
+ oob_size = 16;\r
+ else if (p->page_size == 2048)\r
+ oob_size = 64;\r
+ oob = malloc(oob_size);\r
+ }\r
+ \r
+ if (offset % p->page_size)\r
+ {\r
+ command_print(cmd_ctx, "only page size aligned offsets and sizes are supported");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ while (buf_cnt > 0)\r
+ {\r
+ u32 size_read;\r
+ \r
+ if (page)\r
+ {\r
+ fileio_read(&fileio, page_size, page, &size_read);\r
+ buf_cnt -= size_read;\r
+ if (size_read < page_size)\r
+ {\r
+ memset(page + size_read, 0xff, page_size - size_read);\r
+ }\r
+ }\r
+ \r
+ if (oob)\r
+ {\r
+ fileio_read(&fileio, oob_size, oob, &size_read);\r
+ buf_cnt -= size_read;\r
+ if (size_read < oob_size)\r
+ {\r
+ memset(oob + size_read, 0xff, oob_size - size_read);\r
+ }\r
+ }\r
+ \r
+ if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x",\r
+ args[1], args[0], offset);\r
+ return ERROR_OK;\r
+ }\r
+ offset += page_size;\r
+ }\r
+\r
+ fileio_close(&fileio);\r
+ \r
+ duration_stop_measure(&duration, &duration_text);\r
+ command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s",\r
+ args[1], args[0], offset, duration_text);\r
+ free(duration_text);\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ \r
+ if (argc < 4)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ if (p->device)\r
+ {\r
+ fileio_t fileio;\r
+ duration_t duration;\r
+ char *duration_text;\r
+ int retval;\r
+ \r
+ u8 *page = NULL;\r
+ u32 page_size = 0;\r
+ u8 *oob = NULL;\r
+ u32 oob_size = 0;\r
+ u32 address = strtoul(args[2], NULL, 0);\r
+ u32 size = strtoul(args[3], NULL, 0);\r
+ u32 bytes_done = 0;\r
+ enum oob_formats oob_format = NAND_OOB_NONE;\r
+ \r
+ if (argc > 4)\r
+ {\r
+ int i;\r
+ for (i = 4; i < argc; i++)\r
+ {\r
+ if (!strcmp(args[i], "oob_raw"))\r
+ oob_format |= NAND_OOB_RAW;\r
+ else if (!strcmp(args[i], "oob_only"))\r
+ oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;\r
+ else\r
+ command_print(cmd_ctx, "unknown option: '%s'", args[i]); \r
+ }\r
+ }\r
+ \r
+ if ((address % p->page_size) || (size % p->page_size))\r
+ {\r
+ command_print(cmd_ctx, "only page size aligned addresses and sizes are supported");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ if (!(oob_format & NAND_OOB_ONLY))\r
+ {\r
+ page_size = p->page_size;\r
+ page = malloc(p->page_size);\r
+ }\r
+\r
+ if (oob_format & NAND_OOB_RAW)\r
+ {\r
+ if (p->page_size == 512)\r
+ oob_size = 16;\r
+ else if (p->page_size == 2048)\r
+ oob_size = 64;\r
+ oob = malloc(oob_size);\r
+ }\r
+ \r
+ if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ duration_start_measure(&duration);\r
+ \r
+ while (size > 0)\r
+ {\r
+ u32 size_written;\r
+ if ((retval = nand_read_page(p, address / p->page_size, page, page_size, oob, oob_size)) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "reading NAND flash page failed");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ if (page)\r
+ {\r
+ fileio_write(&fileio, page_size, page, &size_written);\r
+ bytes_done += page_size;\r
+ }\r
+ \r
+ if (oob)\r
+ {\r
+ fileio_write(&fileio, oob_size, oob, &size_written);\r
+ bytes_done += oob_size;\r
+ }\r
+ \r
+ size -= p->page_size;\r
+ address += p->page_size;\r
+ }\r
+ \r
+ if (page)\r
+ free(page);\r
+ \r
+ if (oob)\r
+ free(oob);\r
+ \r
+ fileio_close(&fileio);\r
+\r
+ duration_stop_measure(&duration, &duration_text);\r
+ command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text);\r
+ free(duration_text);\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "#%i: not probed");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ nand_device_t *p;\r
+ \r
+ if ((argc < 1) || (argc > 2))\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+ }\r
+ \r
+ p = get_nand_device_by_num(strtoul(args[0], NULL, 0));\r
+ if (p)\r
+ {\r
+ if (p->device)\r
+ {\r
+ if (argc == 2)\r
+ {\r
+ if (strcmp("enable", args[1]) == 0)\r
+ {\r
+ p->use_raw = 1;\r
+ }\r
+ else if (strcmp("disable", args[1]) == 0)\r
+ {\r
+ p->use_raw = 0;\r
+ }\r
+ else\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+ }\r
+ }\r
+ \r
+ command_print(cmd_ctx, "raw access is %s", (p->use_raw) ? "enabled" : "disabled");\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "#%i: not probed");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
-/***************************************************************************
- * Copyright (C) 2006 by Magnus Lundin *
- * lundin@mlu.mine.nu *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-
-/***************************************************************************
-* STELLARIS is tested on LM3S811
-*
-*
-*
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "stellaris.h"
-#include "cortex_m3.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>
-
-#define DID0_VER(did0) ((did0>>28)&0x07)
-int stellaris_register_commands(struct command_context_s *cmd_ctx);
-int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int stellaris_erase(struct flash_bank_s *bank, int first, int last);
-int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last);
-int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int stellaris_auto_probe(struct flash_bank_s *bank);
-int stellaris_probe(struct flash_bank_s *bank);
-int stellaris_erase_check(struct flash_bank_s *bank);
-int stellaris_protect_check(struct flash_bank_s *bank);
-int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int stellaris_read_part_info(struct flash_bank_s *bank);
-u32 stellaris_get_flash_status(flash_bank_t *bank);
-void stellaris_set_flash_mode(flash_bank_t *bank,int mode);
-u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);
-
-int stellaris_read_part_info(struct flash_bank_s *bank);
-
-flash_driver_t stellaris_flash =
-{
- .name = "stellaris",
- .register_commands = stellaris_register_commands,
- .flash_bank_command = stellaris_flash_bank_command,
- .erase = stellaris_erase,
- .protect = stellaris_protect,
- .write = stellaris_write,
- .probe = stellaris_probe,
- .auto_probe = stellaris_auto_probe,
- .erase_check = stellaris_erase_check,
- .protect_check = stellaris_protect_check,
- .info = stellaris_info
-};
-
-
-struct {
- u32 partno;
- char *partname;
-} StellarisParts[] =
-{
- {0x01,"LM3S101"},
- {0x02,"LM3S102"},
- {0x19,"LM3S300"},
- {0x11,"LM3S301"},
- {0x12,"LM3S310"},
- {0x1A,"LM3S308"},
- {0x13,"LM3S315"},
- {0x14,"LM3S316"},
- {0x17,"LM3S317"},
- {0x18,"LM3S318"},
- {0x15,"LM3S328"},
- {0x2A,"LM3S600"},
- {0x21,"LM3S601"},
- {0x2B,"LM3S608"},
- {0x22,"LM3S610"},
- {0x23,"LM3S611"},
- {0x24,"LM3S612"},
- {0x25,"LM3S613"},
- {0x26,"LM3S615"},
- {0x28,"LM3S617"},
- {0x29,"LM3S618"},
- {0x27,"LM3S628"},
- {0x38,"LM3S800"},
- {0x31,"LM3S801"},
- {0x39,"LM3S808"},
- {0x32,"LM3S811"},
- {0x33,"LM3S812"},
- {0x34,"LM3S815"},
- {0x36,"LM3S817"},
- {0x37,"LM3S818"},
- {0x35,"LM3S828"},
- {0x51,"LM3S2110"},
- {0x52,"LM3S2739"},
- {0x53,"LM3S2651"},
- {0x54,"LM3S2939"},
- {0x55,"LM3S2965"},
- {0x56,"LM3S2432"},
- {0x57,"LM3S2620"},
- {0x58,"LM3S2950"},
- {0x59,"LM3S2412"},
- {0x5A,"LM3S2533"},
- {0x61,"LM3S8630"},
- {0x62,"LM3S8970"},
- {0x63,"LM3S8730"},
- {0x64,"LM3S8530"},
- {0x65,"LM3S8930"},
- {0x71,"LM3S6610"},
- {0x72,"LM3S6950"},
- {0x73,"LM3S6965"},
- {0x74,"LM3S6110"},
- {0x75,"LM3S6432"},
- {0x76,"LM3S6537"},
- {0x77,"LM3S6753"},
- {0x78,"LM3S6952"},
- {0x82,"LM3S6422"},
- {0x83,"LM3S6633"},
- {0x84,"LM3S2139"},
- {0x85,"LM3S2637"},
- {0x86,"LM3S8738"},
- {0x88,"LM3S8938"},
- {0x89,"LM3S6938"},
- {0x8B,"LM3S6637"},
- {0x8C,"LM3S8933"},
- {0x8D,"LM3S8733"},
- {0x8E,"LM3S8538"},
- {0x8F,"LM3S2948"},
- {0xA1,"LM3S6100"},
- {0xA2,"LM3S2410"},
- {0xA3,"LM3S6730"},
- {0xA4,"LM3S2730"},
- {0xA5,"LM3S6420"},
- {0xA6,"LM3S8962"},
- {0xB3,"LM3S1635"},
- {0xB4,"LM3S1850"},
- {0xB5,"LM3S1960"},
- {0xB7,"LM3S1937"},
- {0xB8,"LM3S1968"},
- {0xB9,"LM3S1751"},
- {0xBA,"LM3S1439"},
- {0xBB,"LM3S1512"},
- {0xBC,"LM3S1435"},
- {0xBD,"LM3S1637"},
- {0xBE,"LM3S1958"},
- {0xBF,"LM3S1110"},
- {0xC0,"LM3S1620"},
- {0xC1,"LM3S1150"},
- {0xC2,"LM3S1165"},
- {0xC3,"LM3S1133"},
- {0xC4,"LM3S1162"},
- {0xC5,"LM3S1138"},
- {0xC6,"LM3S1332"},
- {0xC7,"LM3S1538"},
- {0xD0,"LM3S6815"},
- {0xD1,"LM3S6816"},
- {0xD2,"LM3S6915"},
- {0xD3,"LM3S6916"},
- {0xD4,"LM3S2016"},
- {0xD5,"LM3S1615"},
- {0xD6,"LM3S1616"},
- {0xD7,"LM3S8971"},
- {0xD8,"LM3S1108"},
- {0xD9,"LM3S1101"},
- {0xDA,"LM3S1608"},
- {0xDB,"LM3S1601"},
- {0xDC,"LM3S1918"},
- {0xDD,"LM3S1911"},
- {0xDE,"LM3S2108"},
- {0xDF,"LM3S2101"},
- {0xE0,"LM3S2608"},
- {0xE1,"LM3S2601"},
- {0xE2,"LM3S2918"},
- {0xE3,"LM3S2911"},
- {0xE4,"LM3S6118"},
- {0xE5,"LM3S6111"},
- {0xE6,"LM3S6618"},
- {0xE7,"LM3S6611"},
- {0xE8,"LM3S6918"},
- {0xE9,"LM3S6911"},
- {0,"Unknown part"}
-};
-
-char * StellarisClassname[2] =
-{
- "Sandstorm",
- "Fury"
-};
-
-/***************************************************************************
-* openocd command interface *
-***************************************************************************/
-
-/* flash_bank stellaris <base> <size> 0 0 <target#>
- */
-int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- stellaris_flash_bank_t *stellaris_info;
-
- if (argc < 6)
- {
- WARNING("incomplete flash_bank stellaris configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- stellaris_info = calloc(sizeof(stellaris_flash_bank_t),1);
- bank->base = 0x0;
- bank->driver_priv = stellaris_info;
-
- stellaris_info->target_name = "Unknown target";
-
- /* part wasn't probed for info yet */
- stellaris_info->did1 = 0;
-
- /* TODO Use an optional main oscillator clock rate in kHz from arg[6] */
- return ERROR_OK;
-}
-
-int stellaris_register_commands(struct command_context_s *cmd_ctx)
-{
-/*
- command_t *stellaris_cmd = register_command(cmd_ctx, NULL, "stellaris", NULL, COMMAND_ANY, NULL);
- register_command(cmd_ctx, stellaris_cmd, "gpnvm", stellaris_handle_gpnvm_command, COMMAND_EXEC,
- "stellaris gpnvm <num> <bit> set|clear, set or clear stellaris gpnvm bit");
-*/
- return ERROR_OK;
-}
-
-int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- int printed, device_class;
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
-
- stellaris_read_part_info(bank);
-
- if (stellaris_info->did1 == 0)
- {
- printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");
- buf += printed;
- buf_size -= printed;
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if (DID0_VER(stellaris_info->did0)>0)
- {
- device_class = (stellaris_info->did0>>16)&0xFF;
- }
- else
- {
- device_class = 0;
- }
- printed = snprintf(buf, buf_size, "\nLMI Stellaris information: Chip is class %i(%s) %s v%c.%i\n",
- device_class, StellarisClassname[device_class], stellaris_info->target_name,
- 'A' + (stellaris_info->did0>>8)&0xFF, (stellaris_info->did0)&0xFF);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "did1: 0x%8.8x, arch: 0x%4.4x, eproc: %s, ramsize:%ik, flashsize: %ik\n",
- stellaris_info->did1, stellaris_info->did1, "ARMV7M", (1+(stellaris_info->dc0>>16)&0xFFFF)/4, (1+stellaris_info->dc0&0xFFFF)*2);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz, rcc is 0x%x \n", stellaris_info->mck_freq / 1000, stellaris_info->rcc);
- buf += printed;
- buf_size -= printed;
-
- if (stellaris_info->num_lockbits>0) {
- printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", stellaris_info->pagesize, stellaris_info->num_lockbits, stellaris_info->lockbits,stellaris_info->num_pages/stellaris_info->num_lockbits);
- buf += printed;
- buf_size -= printed;
- }
- return ERROR_OK;
-}
-
-/***************************************************************************
-* chip identification and status *
-***************************************************************************/
-
-u32 stellaris_get_flash_status(flash_bank_t *bank)
-{
- target_t *target = bank->target;
- u32 fmc;
-
- target_read_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, &fmc);
-
- return fmc;
-}
-
-/** Read clock configuration and set stellaris_info->usec_clocks*/
-
-void stellaris_read_clock_info(flash_bank_t *bank)
-{
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 rcc, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
- unsigned long mainfreq;
-
- target_read_u32(target, SCB_BASE|RCC, &rcc);
- DEBUG("Stellaris RCC %x",rcc);
- target_read_u32(target, SCB_BASE|PLLCFG, &pllcfg);
- DEBUG("Stellaris PLLCFG %x",pllcfg);
- stellaris_info->rcc = rcc;
-
- sysdiv = (rcc>>23)&0xF;
- usesysdiv = (rcc>>22)&0x1;
- bypass = (rcc>>11)&0x1;
- oscsrc = (rcc>>4)&0x3;
- /* xtal = (rcc>>6)&0xF; */
- switch (oscsrc)
- {
- case 0:
- mainfreq = 6000000; /* Default xtal */
- break;
- case 1:
- mainfreq = 22500000; /* Internal osc. 15 MHz +- 50% */
- break;
- case 2:
- mainfreq = 5625000; /* Internal osc. / 4 */
- break;
- case 3:
- WARNING("Invalid oscsrc (3) in rcc register");
- mainfreq = 6000000;
- break;
- }
-
- if (!bypass)
- mainfreq = 200000000; /* PLL out frec */
-
- if (usesysdiv)
- stellaris_info->mck_freq = mainfreq/(1+sysdiv);
- else
- stellaris_info->mck_freq = mainfreq;
-
- /* Forget old flash timing */
- stellaris_set_flash_mode(bank,0);
-}
-
-/* Setup the timimg registers */
-void stellaris_set_flash_mode(flash_bank_t *bank,int mode)
-{
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
-
- u32 usecrl = (stellaris_info->mck_freq/1000000ul-1);
- DEBUG("usecrl = %i",usecrl);
- target_write_u32(target, SCB_BASE|USECRL , usecrl);
-
-}
-
-u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
-{
- u32 status;
-
- /* Stellaris waits for cmdbit to clear */
- while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
- {
- DEBUG("status: 0x%x", status);
- usleep(1000);
- }
-
- /* Flash errors are reflected in the FLASH_CRIS register */
-
- return status;
-}
-
-
-/* Send one command to the flash controller */
-int stellaris_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen)
-{
- u32 fmc;
-// stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
-
- fmc = FMC_WRKEY | cmd;
- target_write_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, fmc);
- DEBUG("Flash command: 0x%x", fmc);
-
- if (stellaris_wait_status_busy(bank, cmd, 100))
- {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-/* Read device id register, main clock frequency register and fill in driver info structure */
-int stellaris_read_part_info(struct flash_bank_s *bank)
-{
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 did0,did1, ver, fam, status;
- int i;
-
- /* Read and parse chip identification register */
- target_read_u32(target, SCB_BASE|DID0, &did0);
- target_read_u32(target, SCB_BASE|DID1, &did1);
- target_read_u32(target, SCB_BASE|DC0, &stellaris_info->dc0);
- target_read_u32(target, SCB_BASE|DC1, &stellaris_info->dc1);
- DEBUG("did0 0x%x, did1 0x%x, dc0 0x%x, dc1 0x%x",did0, did1, stellaris_info->dc0,stellaris_info->dc1);
-
- ver = did0 >> 28;
- if((ver != 0) && (ver != 1))
- {
- WARNING("Unknown did0 version, cannot identify target");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- ver = did1 >> 28;
- fam = (did1 >> 24) & 0xF;
- if(((ver != 0) && (ver != 1)) || (fam != 0))
- {
- WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
- }
-
- if (did1 == 0)
- {
- WARNING("Cannot identify target as a Stellaris");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- for (i=0;StellarisParts[i].partno;i++)
- {
- if (StellarisParts[i].partno==((did1>>16)&0xFF))
- break;
- }
-
- stellaris_info->target_name = StellarisParts[i].partname;
-
- stellaris_info->did0 = did0;
- stellaris_info->did1 = did1;
-
- stellaris_info->num_lockbits = 1+stellaris_info->dc0&0xFFFF;
- stellaris_info->num_pages = 2*(1+stellaris_info->dc0&0xFFFF);
- stellaris_info->pagesize = 1024;
- bank->size = 1024*stellaris_info->num_pages;
- stellaris_info->pages_in_lockregion = 2;
- target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);
-
- // Read main and master clock freqency register
- stellaris_read_clock_info(bank);
-
- status = stellaris_get_flash_status(bank);
-
- return ERROR_OK;
-}
-
-/***************************************************************************
-* flash operations *
-***************************************************************************/
-
-int stellaris_erase_check(struct flash_bank_s *bank)
-{
- /*
-
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
- int i;
-
- */
-
- return ERROR_OK;
-}
-
-int stellaris_protect_check(struct flash_bank_s *bank)
-{
- u32 status;
-
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
-
- if (stellaris_info->did1 == 0)
- {
- stellaris_read_part_info(bank);
- }
-
- if (stellaris_info->did1 == 0)
- {
- WARNING("Cannot identify target as an AT91SAM");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- status = stellaris_get_flash_status(bank);
- stellaris_info->lockbits = status >> 16;
-
- return ERROR_OK;
-}
-
-int stellaris_erase(struct flash_bank_s *bank, int first, int last)
-{
- int banknr;
- u32 flash_fmc, flash_cris;
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stellaris_info->did1 == 0)
- {
- stellaris_read_part_info(bank);
- }
-
- if (stellaris_info->did1 == 0)
- {
- WARNING("Cannot identify target as Stellaris");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if ((first < 0) || (last < first) || (last >= stellaris_info->num_pages))
- {
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- /* Configure the flash controller timing */
- stellaris_read_clock_info(bank);
- stellaris_set_flash_mode(bank,0);
-
- /* Clear and disable flash programming interrupts */
- target_write_u32(target, FLASH_CIM, 0);
- target_write_u32(target, FLASH_MISC, PMISC|AMISC);
-
- if ((first == 0) && (last == (stellaris_info->num_pages-1)))
- {
- target_write_u32(target, FLASH_FMA, 0);
- target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
- /* Wait until erase complete */
- do
- {
- target_read_u32(target, FLASH_FMC, &flash_fmc);
- }
- while(flash_fmc & FMC_MERASE);
-
- /* if device has > 128k, then second erase cycle is needed */
- if(stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
- {
- target_write_u32(target, FLASH_FMA, 0x20000);
- target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
- /* Wait until erase complete */
- do
- {
- target_read_u32(target, FLASH_FMC, &flash_fmc);
- }
- while(flash_fmc & FMC_MERASE);
- }
-
- return ERROR_OK;
- }
-
- for (banknr=first;banknr<=last;banknr++)
- {
- /* Address is first word in page */
- target_write_u32(target, FLASH_FMA, banknr*stellaris_info->pagesize);
- /* Write erase command */
- target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);
- /* Wait until erase complete */
- do
- {
- target_read_u32(target, FLASH_FMC, &flash_fmc);
- }
- while(flash_fmc & FMC_ERASE);
-
- /* Check acess violations */
- target_read_u32(target, FLASH_CRIS, &flash_cris);
- if(flash_cris & (AMASK))
- {
- WARNING("Error erasing flash page %i, flash_cris 0x%x", banknr, flash_cris);
- target_write_u32(target, FLASH_CRIS, 0);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
-
- return ERROR_OK;
-}
-
-int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- u32 fmppe, flash_fmc, flash_cris;
- int lockregion;
-
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if ((first < 0) || (last < first) || (last >= stellaris_info->num_lockbits))
- {
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- if (stellaris_info->did1 == 0)
- {
- stellaris_read_part_info(bank);
- }
-
- if (stellaris_info->did1 == 0)
- {
- WARNING("Cannot identify target as an Stellaris MCU");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* Configure the flash controller timing */
- stellaris_read_clock_info(bank);
- stellaris_set_flash_mode(bank,0);
-
- fmppe = stellaris_info->lockbits;
- for (lockregion=first;lockregion<=last;lockregion++)
- {
- if (set)
- fmppe &= ~(1<<lockregion);
- else
- fmppe |= (1<<lockregion);
- }
-
- /* Clear and disable flash programming interrupts */
- target_write_u32(target, FLASH_CIM, 0);
- target_write_u32(target, FLASH_MISC, PMISC|AMISC);
-
- DEBUG("fmppe 0x%x",fmppe);
- target_write_u32(target, SCB_BASE|FMPPE, fmppe);
- /* Commit FMPPE */
- target_write_u32(target, FLASH_FMA, 1);
- /* Write commit command */
- /* TODO safety check, sice this cannot be undone */
- WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
- /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
- /* Wait until erase complete */
- do
- {
- target_read_u32(target, FLASH_FMC, &flash_fmc);
- }
- while(flash_fmc & FMC_COMT);
-
- /* Check acess violations */
- target_read_u32(target, FLASH_CRIS, &flash_cris);
- if(flash_cris & (AMASK))
- {
- WARNING("Error setting flash page protection, flash_cris 0x%x", flash_cris);
- target_write_u32(target, FLASH_CRIS, 0);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);
-
- return ERROR_OK;
-}
-
-u8 stellaris_write_code[] =
-{
-/*
- Call with :
- r0 = buffer address
- r1 = destination address
- r2 = bytecount (in) - endaddr (work)
-
- Used registers:
- r3 = pFLASH_CTRL_BASE
- r4 = FLASHWRITECMD
- r5 = #1
- r6 = bytes written
- r7 = temp reg
-*/
- 0x07,0x4B, /* ldr r3,pFLASH_CTRL_BASE */
- 0x08,0x4C, /* ldr r4,FLASHWRITECMD */
- 0x01,0x25, /* movs r5, 1 */
- 0x00,0x26, /* movs r6, #0 */
-/* mainloop: */
- 0x19,0x60, /* str r1, [r3, #0] */
- 0x87,0x59, /* ldr r7, [r0, r6] */
- 0x5F,0x60, /* str r7, [r3, #4] */
- 0x9C,0x60, /* str r4, [r3, #8] */
-/* waitloop: */
- 0x9F,0x68, /* ldr r7, [r3, #8] */
- 0x2F,0x42, /* tst r7, r5 */
- 0xFC,0xD1, /* bne waitloop */
- 0x04,0x31, /* adds r1, r1, #4 */
- 0x04,0x36, /* adds r6, r6, #4 */
- 0x96,0x42, /* cmp r6, r2 */
- 0xF4,0xD1, /* bne mainloop */
- 0x00,0xBE, /* bkpt #0 */
-/* pFLASH_CTRL_BASE: */
- 0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */
-/* FLASHWRITECMD: */
- 0x01,0x00,0x42,0xA4 /* .word 0xA4420001 */
-};
-
-int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 wcount)
-{
-// stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 buffer_size = 8192;
- working_area_t *source;
- working_area_t *write_algorithm;
- u32 address = bank->base + offset;
- reg_param_t reg_params[8];
- armv7m_algorithm_t armv7m_info;
- int retval;
-
- DEBUG("(bank=%08X buffer=%08X offset=%08X wcount=%08X)",
- (unsigned int)bank, (unsigned int)buffer, offset, wcount);
-
- /* flash write code */
- if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
- {
- WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- };
-
- target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), stellaris_write_code);
-
- /* memory buffer */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
- {
- DEBUG("called target_alloc_working_area(target=%08X buffer_size=%08X source=%08X)",
- (unsigned int)target, buffer_size, (unsigned int)source);
- buffer_size /= 2;
- if (buffer_size <= 256)
- {
- /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
- if (write_algorithm)
- target_free_working_area(target, write_algorithm);
-
- WARNING("no large enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- };
-
- armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
- armv7m_info.core_mode = ARMV7M_MODE_ANY;
- armv7m_info.core_state = ARMV7M_STATE_THUMB;
-
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
- init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
- init_reg_param(®_params[5], "r5", 32, PARAM_OUT);
- init_reg_param(®_params[6], "r6", 32, PARAM_OUT);
- init_reg_param(®_params[7], "r7", 32, PARAM_OUT);
-
- while (wcount > 0)
- {
- u32 thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
-
- target_write_buffer(target, source->address, thisrun_count * 4, buffer);
-
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- buf_set_u32(reg_params[1].value, 0, 32, address);
- buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
- WARNING("Algorithm flash write %i words to 0x%x, %i remaining",thisrun_count,address, wcount);
- DEBUG("Algorithm flash write %i words to 0x%x, %i remaining",thisrun_count,address, wcount);
- if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
- {
- ERROR("error executing stellaris flash write algorithm");
- target_free_working_area(target, source);
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- buffer += thisrun_count * 4;
- address += thisrun_count * 4;
- wcount -= thisrun_count;
- }
-
-
- target_free_working_area(target, write_algorithm);
- target_free_working_area(target, source);
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_params[4]);
- destroy_reg_param(®_params[5]);
- destroy_reg_param(®_params[6]);
- destroy_reg_param(®_params[7]);
-
- return ERROR_OK;
-}
-
-int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 address = offset;
- u32 flash_cris,flash_fmc;
- u32 retval;
-
- DEBUG("(bank=%08X buffer=%08X offset=%08X count=%08X)",
- (unsigned int)bank, (unsigned int)buffer, offset, count);
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stellaris_info->did1 == 0)
- {
- stellaris_read_part_info(bank);
- }
-
- if (stellaris_info->did1 == 0)
- {
- WARNING("Cannot identify target as a Stellaris processor");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if((offset & 3) || (count & 3))
- {
- WARNING("offset size must be word aligned");
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
-
- if (offset + count > bank->size)
- return ERROR_FLASH_DST_OUT_OF_BANK;
-
- /* Configure the flash controller timing */
- stellaris_read_clock_info(bank);
- stellaris_set_flash_mode(bank,0);
-
-
- /* Clear and disable flash programming interrupts */
- target_write_u32(target, FLASH_CIM, 0);
- target_write_u32(target, FLASH_MISC, PMISC|AMISC);
-
- /* multiple words to be programmed? */
- if (count > 0)
- {
- /* try using a block write */
- if ((retval = stellaris_write_block(bank, buffer, offset, count/4)) != ERROR_OK)
- {
- if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- /* if block write failed (no sufficient working area),
- * we use normal (slow) single dword accesses */
- WARNING("couldn't use block writes, falling back to single memory accesses");
- }
- else if (retval == ERROR_FLASH_OPERATION_FAILED)
- {
- /* if an error occured, we examine the reason, and quit */
- target_read_u32(target, FLASH_CRIS, &flash_cris);
-
- ERROR("flash writing failed with CRIS: 0x%x", flash_cris);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
- else
- {
- buffer += count * 4;
- address += count * 4;
- count = 0;
- }
- }
-
-
-
- while(count>0)
- {
- if (!(address&0xff)) DEBUG("0x%x",address);
- /* Program one word */
- target_write_u32(target, FLASH_FMA, address);
- target_write_buffer(target, FLASH_FMD, 4, buffer);
- target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
- //DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE);
- /* Wait until write complete */
- do
- {
- target_read_u32(target, FLASH_FMC, &flash_fmc);
- }
- while(flash_fmc & FMC_WRITE);
- buffer += 4;
- address += 4;
- count -= 4;
- }
- /* Check acess violations */
- target_read_u32(target, FLASH_CRIS, &flash_cris);
- if(flash_cris & (AMASK))
- {
- DEBUG("flash_cris 0x%x", flash_cris);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- return ERROR_OK;
-}
-
-
-int stellaris_probe(struct flash_bank_s *bank)
-{
- /* we can't probe on an stellaris
- * if this is an stellaris, it has the configured flash
- */
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
-
- stellaris_info->probed = 0;
-
- if (stellaris_info->did1 == 0)
- {
- stellaris_read_part_info(bank);
- }
-
- if (stellaris_info->did1 == 0)
- {
- WARNING("Cannot identify target as a LMI Stellaris");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- stellaris_info->probed = 1;
-
- return ERROR_OK;
-}
-
-int stellaris_auto_probe(struct flash_bank_s *bank)
-{
- stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
- if (stellaris_info->probed)
- return ERROR_OK;
- return stellaris_probe(bank);
-}
+/***************************************************************************\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
+* STELLARIS is tested on LM3S811\r
+* \r
+*\r
+*\r
+ ***************************************************************************/\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "replacements.h"\r
+\r
+#include "stellaris.h"\r
+#include "cortex_m3.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
+#define DID0_VER(did0) ((did0>>28)&0x07)\r
+int stellaris_register_commands(struct command_context_s *cmd_ctx);\r
+int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
+int stellaris_erase(struct flash_bank_s *bank, int first, int last);\r
+int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last);\r
+int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
+int stellaris_auto_probe(struct flash_bank_s *bank);\r
+int stellaris_probe(struct flash_bank_s *bank);\r
+int stellaris_erase_check(struct flash_bank_s *bank);\r
+int stellaris_protect_check(struct flash_bank_s *bank);\r
+int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
+\r
+int stellaris_read_part_info(struct flash_bank_s *bank);\r
+u32 stellaris_get_flash_status(flash_bank_t *bank);\r
+void stellaris_set_flash_mode(flash_bank_t *bank,int mode);\r
+u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);\r
+\r
+int stellaris_read_part_info(struct flash_bank_s *bank);\r
+\r
+flash_driver_t stellaris_flash =\r
+{\r
+ .name = "stellaris",\r
+ .register_commands = stellaris_register_commands,\r
+ .flash_bank_command = stellaris_flash_bank_command,\r
+ .erase = stellaris_erase,\r
+ .protect = stellaris_protect,\r
+ .write = stellaris_write,\r
+ .probe = stellaris_probe,\r
+ .auto_probe = stellaris_auto_probe,\r
+ .erase_check = stellaris_erase_check,\r
+ .protect_check = stellaris_protect_check,\r
+ .info = stellaris_info\r
+};\r
+\r
+\r
+struct {\r
+ u32 partno;\r
+ char *partname;\r
+} StellarisParts[] =\r
+{\r
+ {0x01,"LM3S101"},\r
+ {0x02,"LM3S102"},\r
+ {0x19,"LM3S300"},\r
+ {0x11,"LM3S301"},\r
+ {0x12,"LM3S310"},\r
+ {0x1A,"LM3S308"},\r
+ {0x13,"LM3S315"},\r
+ {0x14,"LM3S316"},\r
+ {0x17,"LM3S317"},\r
+ {0x18,"LM3S318"},\r
+ {0x15,"LM3S328"},\r
+ {0x2A,"LM3S600"},\r
+ {0x21,"LM3S601"},\r
+ {0x2B,"LM3S608"},\r
+ {0x22,"LM3S610"},\r
+ {0x23,"LM3S611"},\r
+ {0x24,"LM3S612"},\r
+ {0x25,"LM3S613"},\r
+ {0x26,"LM3S615"},\r
+ {0x28,"LM3S617"},\r
+ {0x29,"LM3S618"},\r
+ {0x27,"LM3S628"},\r
+ {0x38,"LM3S800"},\r
+ {0x31,"LM3S801"},\r
+ {0x39,"LM3S808"},\r
+ {0x32,"LM3S811"},\r
+ {0x33,"LM3S812"},\r
+ {0x34,"LM3S815"},\r
+ {0x36,"LM3S817"},\r
+ {0x37,"LM3S818"},\r
+ {0x35,"LM3S828"},\r
+ {0x51,"LM3S2110"},\r
+ {0x52,"LM3S2739"},\r
+ {0x53,"LM3S2651"},\r
+ {0x54,"LM3S2939"},\r
+ {0x55,"LM3S2965"},\r
+ {0x56,"LM3S2432"},\r
+ {0x57,"LM3S2620"},\r
+ {0x58,"LM3S2950"},\r
+ {0x59,"LM3S2412"},\r
+ {0x5A,"LM3S2533"},\r
+ {0x61,"LM3S8630"},\r
+ {0x62,"LM3S8970"},\r
+ {0x63,"LM3S8730"},\r
+ {0x64,"LM3S8530"},\r
+ {0x65,"LM3S8930"},\r
+ {0x71,"LM3S6610"},\r
+ {0x72,"LM3S6950"},\r
+ {0x73,"LM3S6965"},\r
+ {0x74,"LM3S6110"},\r
+ {0x75,"LM3S6432"},\r
+ {0x76,"LM3S6537"},\r
+ {0x77,"LM3S6753"},\r
+ {0x78,"LM3S6952"},\r
+ {0x82,"LM3S6422"},\r
+ {0x83,"LM3S6633"},\r
+ {0x84,"LM3S2139"},\r
+ {0x85,"LM3S2637"},\r
+ {0x86,"LM3S8738"},\r
+ {0x88,"LM3S8938"},\r
+ {0x89,"LM3S6938"},\r
+ {0x8B,"LM3S6637"},\r
+ {0x8C,"LM3S8933"},\r
+ {0x8D,"LM3S8733"},\r
+ {0x8E,"LM3S8538"},\r
+ {0x8F,"LM3S2948"},\r
+ {0xA1,"LM3S6100"},\r
+ {0xA2,"LM3S2410"},\r
+ {0xA3,"LM3S6730"},\r
+ {0xA4,"LM3S2730"},\r
+ {0xA5,"LM3S6420"},\r
+ {0xA6,"LM3S8962"},\r
+ {0xB3,"LM3S1635"},\r
+ {0xB4,"LM3S1850"},\r
+ {0xB5,"LM3S1960"},\r
+ {0xB7,"LM3S1937"},\r
+ {0xB8,"LM3S1968"},\r
+ {0xB9,"LM3S1751"},\r
+ {0xBA,"LM3S1439"},\r
+ {0xBB,"LM3S1512"},\r
+ {0xBC,"LM3S1435"},\r
+ {0xBD,"LM3S1637"},\r
+ {0xBE,"LM3S1958"},\r
+ {0xBF,"LM3S1110"},\r
+ {0xC0,"LM3S1620"},\r
+ {0xC1,"LM3S1150"},\r
+ {0xC2,"LM3S1165"},\r
+ {0xC3,"LM3S1133"},\r
+ {0xC4,"LM3S1162"},\r
+ {0xC5,"LM3S1138"},\r
+ {0xC6,"LM3S1332"},\r
+ {0xC7,"LM3S1538"},\r
+ {0xD0,"LM3S6815"},\r
+ {0xD1,"LM3S6816"},\r
+ {0xD2,"LM3S6915"},\r
+ {0xD3,"LM3S6916"},\r
+ {0xD4,"LM3S2016"},\r
+ {0xD5,"LM3S1615"},\r
+ {0xD6,"LM3S1616"},\r
+ {0xD7,"LM3S8971"},\r
+ {0xD8,"LM3S1108"},\r
+ {0xD9,"LM3S1101"},\r
+ {0xDA,"LM3S1608"},\r
+ {0xDB,"LM3S1601"},\r
+ {0xDC,"LM3S1918"},\r
+ {0xDD,"LM3S1911"},\r
+ {0xDE,"LM3S2108"},\r
+ {0xDF,"LM3S2101"},\r
+ {0xE0,"LM3S2608"},\r
+ {0xE1,"LM3S2601"},\r
+ {0xE2,"LM3S2918"},\r
+ {0xE3,"LM3S2911"},\r
+ {0xE4,"LM3S6118"},\r
+ {0xE5,"LM3S6111"},\r
+ {0xE6,"LM3S6618"},\r
+ {0xE7,"LM3S6611"},\r
+ {0xE8,"LM3S6918"},\r
+ {0xE9,"LM3S6911"},\r
+ {0,"Unknown part"}\r
+};\r
+\r
+char * StellarisClassname[2] =\r
+{\r
+ "Sandstorm",\r
+ "Fury"\r
+};\r
+\r
+/***************************************************************************\r
+* openocd command interface *\r
+***************************************************************************/\r
+\r
+/* flash_bank stellaris <base> <size> 0 0 <target#>\r
+ */\r
+int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
+{\r
+ stellaris_flash_bank_t *stellaris_info;\r
+ \r
+ if (argc < 6)\r
+ {\r
+ WARNING("incomplete flash_bank stellaris configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ stellaris_info = calloc(sizeof(stellaris_flash_bank_t),1);\r
+ bank->base = 0x0;\r
+ bank->driver_priv = stellaris_info;\r
+ \r
+ stellaris_info->target_name = "Unknown target";\r
+ \r
+ /* part wasn't probed for info yet */\r
+ stellaris_info->did1 = 0;\r
+ \r
+ /* TODO Use an optional main oscillator clock rate in kHz from arg[6] */ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+/*\r
+ command_t *stellaris_cmd = register_command(cmd_ctx, NULL, "stellaris", NULL, COMMAND_ANY, NULL);\r
+ register_command(cmd_ctx, stellaris_cmd, "gpnvm", stellaris_handle_gpnvm_command, COMMAND_EXEC,\r
+ "stellaris gpnvm <num> <bit> set|clear, set or clear stellaris gpnvm bit");\r
+*/\r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
+{\r
+ int printed, device_class;\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ \r
+ stellaris_read_part_info(bank);\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");\r
+ buf += printed;\r
+ buf_size -= printed;\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (DID0_VER(stellaris_info->did0)>0)\r
+ {\r
+ device_class = (stellaris_info->did0>>16)&0xFF;\r
+ }\r
+ else\r
+ {\r
+ device_class = 0;\r
+ } \r
+ printed = snprintf(buf, buf_size, "\nLMI Stellaris information: Chip is class %i(%s) %s v%c.%i\n",\r
+ device_class, StellarisClassname[device_class], stellaris_info->target_name,\r
+ 'A' + (stellaris_info->did0>>8)&0xFF, (stellaris_info->did0)&0xFF);\r
+ buf += printed;\r
+ buf_size -= printed;\r
+\r
+ printed = snprintf(buf, buf_size, "did1: 0x%8.8x, arch: 0x%4.4x, eproc: %s, ramsize:%ik, flashsize: %ik\n", \r
+ stellaris_info->did1, stellaris_info->did1, "ARMV7M", (1+(stellaris_info->dc0>>16)&0xFFFF)/4, (1+stellaris_info->dc0&0xFFFF)*2);\r
+ buf += printed;\r
+ buf_size -= printed;\r
+\r
+ printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz, rcc is 0x%x \n", stellaris_info->mck_freq / 1000, stellaris_info->rcc);\r
+ buf += printed;\r
+ buf_size -= printed;\r
+\r
+ if (stellaris_info->num_lockbits>0) { \r
+ printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", stellaris_info->pagesize, stellaris_info->num_lockbits, stellaris_info->lockbits,stellaris_info->num_pages/stellaris_info->num_lockbits);\r
+ buf += printed;\r
+ buf_size -= printed;\r
+ }\r
+ return ERROR_OK;\r
+}\r
+\r
+/***************************************************************************\r
+* chip identification and status *\r
+***************************************************************************/\r
+\r
+u32 stellaris_get_flash_status(flash_bank_t *bank)\r
+{\r
+ target_t *target = bank->target;\r
+ u32 fmc;\r
+ \r
+ target_read_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, &fmc);\r
+ \r
+ return fmc;\r
+}\r
+\r
+/** Read clock configuration and set stellaris_info->usec_clocks*/\r
+ \r
+void stellaris_read_clock_info(flash_bank_t *bank)\r
+{\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 rcc, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;\r
+ unsigned long mainfreq;\r
+\r
+ target_read_u32(target, SCB_BASE|RCC, &rcc);\r
+ DEBUG("Stellaris RCC %x",rcc);\r
+ target_read_u32(target, SCB_BASE|PLLCFG, &pllcfg);\r
+ DEBUG("Stellaris PLLCFG %x",pllcfg);\r
+ stellaris_info->rcc = rcc;\r
+ \r
+ sysdiv = (rcc>>23)&0xF;\r
+ usesysdiv = (rcc>>22)&0x1;\r
+ bypass = (rcc>>11)&0x1;\r
+ oscsrc = (rcc>>4)&0x3;\r
+ /* xtal = (rcc>>6)&0xF; */\r
+ switch (oscsrc)\r
+ {\r
+ case 0:\r
+ mainfreq = 6000000; /* Default xtal */\r
+ break;\r
+ case 1:\r
+ mainfreq = 22500000; /* Internal osc. 15 MHz +- 50% */\r
+ break;\r
+ case 2:\r
+ mainfreq = 5625000; /* Internal osc. / 4 */\r
+ break;\r
+ case 3:\r
+ WARNING("Invalid oscsrc (3) in rcc register");\r
+ mainfreq = 6000000;\r
+ break;\r
+ }\r
+ \r
+ if (!bypass)\r
+ mainfreq = 200000000; /* PLL out frec */\r
+ \r
+ if (usesysdiv)\r
+ stellaris_info->mck_freq = mainfreq/(1+sysdiv);\r
+ else\r
+ stellaris_info->mck_freq = mainfreq;\r
+ \r
+ /* Forget old flash timing */\r
+ stellaris_set_flash_mode(bank,0);\r
+}\r
+\r
+/* Setup the timimg registers */\r
+void stellaris_set_flash_mode(flash_bank_t *bank,int mode)\r
+{\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+\r
+ u32 usecrl = (stellaris_info->mck_freq/1000000ul-1);\r
+ DEBUG("usecrl = %i",usecrl); \r
+ target_write_u32(target, SCB_BASE|USECRL , usecrl);\r
+ \r
+}\r
+\r
+u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)\r
+{\r
+ u32 status;\r
+ \r
+ /* Stellaris waits for cmdbit to clear */\r
+ while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))\r
+ {\r
+ DEBUG("status: 0x%x", status);\r
+ usleep(1000);\r
+ }\r
+ \r
+ /* Flash errors are reflected in the FLASH_CRIS register */\r
+\r
+ return status;\r
+}\r
+\r
+\r
+/* Send one command to the flash controller */\r
+int stellaris_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen) \r
+{\r
+ u32 fmc;\r
+// stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+\r
+ fmc = FMC_WRKEY | cmd; \r
+ target_write_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, fmc);\r
+ DEBUG("Flash command: 0x%x", fmc);\r
+\r
+ if (stellaris_wait_status_busy(bank, cmd, 100)) \r
+ {\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ } \r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+/* Read device id register, main clock frequency register and fill in driver info structure */\r
+int stellaris_read_part_info(struct flash_bank_s *bank)\r
+{\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 did0,did1, ver, fam, status;\r
+ int i;\r
+ \r
+ /* Read and parse chip identification register */\r
+ target_read_u32(target, SCB_BASE|DID0, &did0);\r
+ target_read_u32(target, SCB_BASE|DID1, &did1);\r
+ target_read_u32(target, SCB_BASE|DC0, &stellaris_info->dc0);\r
+ target_read_u32(target, SCB_BASE|DC1, &stellaris_info->dc1);\r
+ DEBUG("did0 0x%x, did1 0x%x, dc0 0x%x, dc1 0x%x",did0, did1, stellaris_info->dc0,stellaris_info->dc1);\r
+\r
+ ver = did0 >> 28;\r
+ if((ver != 0) && (ver != 1))\r
+ {\r
+ WARNING("Unknown did0 version, cannot identify target");\r
+ return ERROR_FLASH_OPERATION_FAILED; \r
+ }\r
+\r
+ ver = did1 >> 28;\r
+ fam = (did1 >> 24) & 0xF;\r
+ if(((ver != 0) && (ver != 1)) || (fam != 0))\r
+ {\r
+ WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");\r
+ }\r
+\r
+ if (did1 == 0)\r
+ {\r
+ WARNING("Cannot identify target as a Stellaris");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ for (i=0;StellarisParts[i].partno;i++)\r
+ {\r
+ if (StellarisParts[i].partno==((did1>>16)&0xFF))\r
+ break;\r
+ }\r
+ \r
+ stellaris_info->target_name = StellarisParts[i].partname;\r
+ \r
+ stellaris_info->did0 = did0;\r
+ stellaris_info->did1 = did1;\r
+\r
+ stellaris_info->num_lockbits = 1+stellaris_info->dc0&0xFFFF;\r
+ stellaris_info->num_pages = 2*(1+stellaris_info->dc0&0xFFFF);\r
+ stellaris_info->pagesize = 1024;\r
+ bank->size = 1024*stellaris_info->num_pages;\r
+ stellaris_info->pages_in_lockregion = 2;\r
+ target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);\r
+\r
+ // Read main and master clock freqency register \r
+ stellaris_read_clock_info(bank);\r
+ \r
+ status = stellaris_get_flash_status(bank);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+/***************************************************************************\r
+* flash operations *\r
+***************************************************************************/\r
+\r
+int stellaris_erase_check(struct flash_bank_s *bank)\r
+{\r
+ /* \r
+ \r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ int i;\r
+ \r
+ */\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_protect_check(struct flash_bank_s *bank)\r
+{\r
+ u32 status;\r
+ \r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ stellaris_read_part_info(bank);\r
+ }\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ WARNING("Cannot identify target as an AT91SAM");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ status = stellaris_get_flash_status(bank);\r
+ stellaris_info->lockbits = status >> 16;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_erase(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ int banknr;\r
+ u32 flash_fmc, flash_cris;\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ \r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ stellaris_read_part_info(bank);\r
+ }\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ WARNING("Cannot identify target as Stellaris");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ } \r
+ \r
+ if ((first < 0) || (last < first) || (last >= stellaris_info->num_pages))\r
+ {\r
+ return ERROR_FLASH_SECTOR_INVALID;\r
+ }\r
+\r
+ /* Configure the flash controller timing */\r
+ stellaris_read_clock_info(bank); \r
+ stellaris_set_flash_mode(bank,0);\r
+\r
+ /* Clear and disable flash programming interrupts */\r
+ target_write_u32(target, FLASH_CIM, 0);\r
+ target_write_u32(target, FLASH_MISC, PMISC|AMISC);\r
+\r
+ if ((first == 0) && (last == (stellaris_info->num_pages-1)))\r
+ {\r
+ target_write_u32(target, FLASH_FMA, 0);\r
+ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);\r
+ /* Wait until erase complete */\r
+ do\r
+ {\r
+ target_read_u32(target, FLASH_FMC, &flash_fmc);\r
+ }\r
+ while(flash_fmc & FMC_MERASE);\r
+ \r
+ /* if device has > 128k, then second erase cycle is needed */\r
+ if(stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)\r
+ {\r
+ target_write_u32(target, FLASH_FMA, 0x20000);\r
+ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);\r
+ /* Wait until erase complete */\r
+ do\r
+ {\r
+ target_read_u32(target, FLASH_FMC, &flash_fmc);\r
+ }\r
+ while(flash_fmc & FMC_MERASE);\r
+ }\r
+\r
+ return ERROR_OK;\r
+ }\r
+\r
+ for (banknr=first;banknr<=last;banknr++)\r
+ {\r
+ /* Address is first word in page */\r
+ target_write_u32(target, FLASH_FMA, banknr*stellaris_info->pagesize);\r
+ /* Write erase command */\r
+ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);\r
+ /* Wait until erase complete */\r
+ do\r
+ {\r
+ target_read_u32(target, FLASH_FMC, &flash_fmc);\r
+ }\r
+ while(flash_fmc & FMC_ERASE);\r
+\r
+ /* Check acess violations */\r
+ target_read_u32(target, FLASH_CRIS, &flash_cris);\r
+ if(flash_cris & (AMASK))\r
+ {\r
+ WARNING("Error erasing flash page %i, flash_cris 0x%x", banknr, flash_cris);\r
+ target_write_u32(target, FLASH_CRIS, 0);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)\r
+{\r
+ u32 fmppe, flash_fmc, flash_cris;\r
+ int lockregion;\r
+ \r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ \r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ if ((first < 0) || (last < first) || (last >= stellaris_info->num_lockbits))\r
+ {\r
+ return ERROR_FLASH_SECTOR_INVALID;\r
+ }\r
+ \r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ stellaris_read_part_info(bank);\r
+ }\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ WARNING("Cannot identify target as an Stellaris MCU");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ /* Configure the flash controller timing */\r
+ stellaris_read_clock_info(bank); \r
+ stellaris_set_flash_mode(bank,0);\r
+\r
+ fmppe = stellaris_info->lockbits; \r
+ for (lockregion=first;lockregion<=last;lockregion++) \r
+ {\r
+ if (set)\r
+ fmppe &= ~(1<<lockregion); \r
+ else\r
+ fmppe |= (1<<lockregion); \r
+ }\r
+\r
+ /* Clear and disable flash programming interrupts */\r
+ target_write_u32(target, FLASH_CIM, 0);\r
+ target_write_u32(target, FLASH_MISC, PMISC|AMISC);\r
+ \r
+ DEBUG("fmppe 0x%x",fmppe);\r
+ target_write_u32(target, SCB_BASE|FMPPE, fmppe);\r
+ /* Commit FMPPE */\r
+ target_write_u32(target, FLASH_FMA, 1);\r
+ /* Write commit command */\r
+ /* TODO safety check, sice this cannot be undone */\r
+ WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");\r
+ /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */\r
+ /* Wait until erase complete */\r
+ do\r
+ {\r
+ target_read_u32(target, FLASH_FMC, &flash_fmc);\r
+ }\r
+ while(flash_fmc & FMC_COMT);\r
+\r
+ /* Check acess violations */\r
+ target_read_u32(target, FLASH_CRIS, &flash_cris);\r
+ if(flash_cris & (AMASK))\r
+ {\r
+ WARNING("Error setting flash page protection, flash_cris 0x%x", flash_cris);\r
+ target_write_u32(target, FLASH_CRIS, 0);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+u8 stellaris_write_code[] = \r
+{\r
+/* \r
+ Call with : \r
+ r0 = buffer address\r
+ r1 = destination address\r
+ r2 = bytecount (in) - endaddr (work) \r
+ \r
+ Used registers: \r
+ r3 = pFLASH_CTRL_BASE\r
+ r4 = FLASHWRITECMD\r
+ r5 = #1\r
+ r6 = bytes written\r
+ r7 = temp reg\r
+*/\r
+ 0x07,0x4B, /* ldr r3,pFLASH_CTRL_BASE */\r
+ 0x08,0x4C, /* ldr r4,FLASHWRITECMD */\r
+ 0x01,0x25, /* movs r5, 1 */\r
+ 0x00,0x26, /* movs r6, #0 */\r
+/* mainloop: */\r
+ 0x19,0x60, /* str r1, [r3, #0] */\r
+ 0x87,0x59, /* ldr r7, [r0, r6] */\r
+ 0x5F,0x60, /* str r7, [r3, #4] */\r
+ 0x9C,0x60, /* str r4, [r3, #8] */\r
+/* waitloop: */\r
+ 0x9F,0x68, /* ldr r7, [r3, #8] */\r
+ 0x2F,0x42, /* tst r7, r5 */\r
+ 0xFC,0xD1, /* bne waitloop */\r
+ 0x04,0x31, /* adds r1, r1, #4 */\r
+ 0x04,0x36, /* adds r6, r6, #4 */\r
+ 0x96,0x42, /* cmp r6, r2 */\r
+ 0xF4,0xD1, /* bne mainloop */\r
+ 0x00,0xBE, /* bkpt #0 */\r
+/* pFLASH_CTRL_BASE: */\r
+ 0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */\r
+/* FLASHWRITECMD: */\r
+ 0x01,0x00,0x42,0xA4 /* .word 0xA4420001 */\r
+};\r
+\r
+int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 wcount)\r
+{\r
+// stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 buffer_size = 8192;\r
+ working_area_t *source;\r
+ working_area_t *write_algorithm;\r
+ u32 address = bank->base + offset;\r
+ reg_param_t reg_params[8];\r
+ armv7m_algorithm_t armv7m_info;\r
+ int retval;\r
+ \r
+ DEBUG("(bank=%08X buffer=%08X offset=%08X wcount=%08X)",\r
+ (unsigned int)bank, (unsigned int)buffer, offset, wcount);\r
+\r
+ /* flash write code */\r
+ if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)\r
+ {\r
+ WARNING("no working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ };\r
+\r
+ target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), stellaris_write_code);\r
+\r
+ /* memory buffer */\r
+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)\r
+ {\r
+ DEBUG("called target_alloc_working_area(target=%08X buffer_size=%08X source=%08X)",\r
+ (unsigned int)target, buffer_size, (unsigned int)source); \r
+ buffer_size /= 2;\r
+ if (buffer_size <= 256)\r
+ {\r
+ /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */\r
+ if (write_algorithm)\r
+ target_free_working_area(target, write_algorithm);\r
+ \r
+ WARNING("no large enough working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ }\r
+ };\r
+ \r
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;\r
+ armv7m_info.core_mode = ARMV7M_MODE_ANY;\r
+ armv7m_info.core_state = ARMV7M_STATE_THUMB;\r
+ \r
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);\r
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);\r
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);\r
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);\r
+ init_reg_param(®_params[4], "r4", 32, PARAM_OUT);\r
+ init_reg_param(®_params[5], "r5", 32, PARAM_OUT);\r
+ init_reg_param(®_params[6], "r6", 32, PARAM_OUT);\r
+ init_reg_param(®_params[7], "r7", 32, PARAM_OUT);\r
+\r
+ while (wcount > 0)\r
+ {\r
+ u32 thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;\r
+ \r
+ target_write_buffer(target, source->address, thisrun_count * 4, buffer);\r
+ \r
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);\r
+ buf_set_u32(reg_params[1].value, 0, 32, address);\r
+ buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);\r
+ WARNING("Algorithm flash write %i words to 0x%x, %i remaining",thisrun_count,address, wcount);\r
+ DEBUG("Algorithm flash write %i words to 0x%x, %i remaining",thisrun_count,address, wcount);\r
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)\r
+ {\r
+ ERROR("error executing stellaris flash write algorithm");\r
+ target_free_working_area(target, source);\r
+ destroy_reg_param(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ buffer += thisrun_count * 4;\r
+ address += thisrun_count * 4;\r
+ wcount -= thisrun_count;\r
+ }\r
+ \r
+\r
+ target_free_working_area(target, write_algorithm);\r
+ target_free_working_area(target, source);\r
+ \r
+ destroy_reg_param(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ destroy_reg_param(®_params[3]);\r
+ destroy_reg_param(®_params[4]);\r
+ destroy_reg_param(®_params[5]);\r
+ destroy_reg_param(®_params[6]);\r
+ destroy_reg_param(®_params[7]);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 address = offset;\r
+ u32 flash_cris,flash_fmc;\r
+ u32 retval;\r
+ \r
+ DEBUG("(bank=%08X buffer=%08X offset=%08X count=%08X)",\r
+ (unsigned int)bank, (unsigned int)buffer, offset, count);\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ stellaris_read_part_info(bank);\r
+ }\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ WARNING("Cannot identify target as a Stellaris processor");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ if((offset & 3) || (count & 3))\r
+ {\r
+ WARNING("offset size must be word aligned");\r
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
+ }\r
+ \r
+ if (offset + count > bank->size)\r
+ return ERROR_FLASH_DST_OUT_OF_BANK;\r
+\r
+ /* Configure the flash controller timing */ \r
+ stellaris_read_clock_info(bank); \r
+ stellaris_set_flash_mode(bank,0);\r
+\r
+ \r
+ /* Clear and disable flash programming interrupts */\r
+ target_write_u32(target, FLASH_CIM, 0);\r
+ target_write_u32(target, FLASH_MISC, PMISC|AMISC);\r
+\r
+ /* multiple words to be programmed? */\r
+ if (count > 0) \r
+ {\r
+ /* try using a block write */\r
+ if ((retval = stellaris_write_block(bank, buffer, offset, count/4)) != ERROR_OK)\r
+ {\r
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)\r
+ {\r
+ /* if block write failed (no sufficient working area),\r
+ * we use normal (slow) single dword accesses */ \r
+ WARNING("couldn't use block writes, falling back to single memory accesses");\r
+ }\r
+ else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
+ {\r
+ /* if an error occured, we examine the reason, and quit */\r
+ target_read_u32(target, FLASH_CRIS, &flash_cris);\r
+ \r
+ ERROR("flash writing failed with CRIS: 0x%x", flash_cris);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ buffer += count * 4;\r
+ address += count * 4;\r
+ count = 0;\r
+ }\r
+ }\r
+\r
+\r
+\r
+ while(count>0)\r
+ {\r
+ if (!(address&0xff)) DEBUG("0x%x",address);\r
+ /* Program one word */\r
+ target_write_u32(target, FLASH_FMA, address);\r
+ target_write_buffer(target, FLASH_FMD, 4, buffer);\r
+ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);\r
+ //DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE);\r
+ /* Wait until write complete */\r
+ do\r
+ {\r
+ target_read_u32(target, FLASH_FMC, &flash_fmc);\r
+ }\r
+ while(flash_fmc & FMC_WRITE);\r
+ buffer += 4;\r
+ address += 4;\r
+ count -= 4;\r
+ }\r
+ /* Check acess violations */\r
+ target_read_u32(target, FLASH_CRIS, &flash_cris);\r
+ if(flash_cris & (AMASK))\r
+ {\r
+ DEBUG("flash_cris 0x%x", flash_cris);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+int stellaris_probe(struct flash_bank_s *bank)\r
+{\r
+ /* we can't probe on an stellaris\r
+ * if this is an stellaris, it has the configured flash\r
+ */\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ \r
+ stellaris_info->probed = 0;\r
+ \r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ stellaris_read_part_info(bank);\r
+ }\r
+\r
+ if (stellaris_info->did1 == 0)\r
+ {\r
+ WARNING("Cannot identify target as a LMI Stellaris");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ stellaris_info->probed = 1;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stellaris_auto_probe(struct flash_bank_s *bank)\r
+{\r
+ stellaris_flash_bank_t *stellaris_info = bank->driver_priv;\r
+ if (stellaris_info->probed)\r
+ return ERROR_OK;\r
+ return stellaris_probe(bank);\r
+}\r
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "stm32x.h"
-#include "flash.h"
-#include "target.h"
-#include "log.h"
-#include "armv7m.h"
-#include "algorithm.h"
-#include "binarybuffer.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-int stm32x_register_commands(struct command_context_s *cmd_ctx);
-int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int stm32x_erase(struct flash_bank_s *bank, int first, int last);
-int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last);
-int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int stm32x_probe(struct flash_bank_s *bank);
-int stm32x_auto_probe(struct flash_bank_s *bank);
-int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int stm32x_protect_check(struct flash_bank_s *bank);
-int stm32x_erase_check(struct flash_bank_s *bank);
-int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-flash_driver_t stm32x_flash =
-{
- .name = "stm32x",
- .register_commands = stm32x_register_commands,
- .flash_bank_command = stm32x_flash_bank_command,
- .erase = stm32x_erase,
- .protect = stm32x_protect,
- .write = stm32x_write,
- .probe = stm32x_probe,
- .auto_probe = stm32x_auto_probe,
- .erase_check = stm32x_erase_check,
- .protect_check = stm32x_protect_check,
- .info = stm32x_info
-};
-
-int stm32x_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *stm32x_cmd = register_command(cmd_ctx, NULL, "stm32x", NULL, COMMAND_ANY, "stm32x flash specific commands");
-
- register_command(cmd_ctx, stm32x_cmd, "lock", stm32x_handle_lock_command, COMMAND_EXEC,
- "lock device");
- register_command(cmd_ctx, stm32x_cmd, "unlock", stm32x_handle_unlock_command, COMMAND_EXEC,
- "unlock protected device");
- register_command(cmd_ctx, stm32x_cmd, "mass_erase", stm32x_handle_mass_erase_command, COMMAND_EXEC,
- "mass erase device");
- register_command(cmd_ctx, stm32x_cmd, "options_read", stm32x_handle_options_read_command, COMMAND_EXEC,
- "read device option bytes");
- register_command(cmd_ctx, stm32x_cmd, "options_write", stm32x_handle_options_write_command, COMMAND_EXEC,
- "write device option bytes");
- return ERROR_OK;
-}
-
-/* flash bank stm32x <base> <size> 0 0 <target#>
- */
-int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- stm32x_flash_bank_t *stm32x_info;
-
- if (argc < 6)
- {
- WARNING("incomplete flash_bank stm32x configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- stm32x_info = malloc(sizeof(stm32x_flash_bank_t));
- bank->driver_priv = stm32x_info;
-
- stm32x_info->write_algorithm = NULL;
- stm32x_info->probed = 0;
-
- return ERROR_OK;
-}
-
-u32 stm32x_get_flash_status(flash_bank_t *bank)
-{
- target_t *target = bank->target;
- u32 status;
-
- target_read_u32(target, STM32_FLASH_SR, &status);
-
- return status;
-}
-
-u32 stm32x_wait_status_busy(flash_bank_t *bank, int timeout)
-{
- u32 status;
-
- /* wait for busy to clear */
- while (((status = stm32x_get_flash_status(bank)) & FLASH_BSY) && (timeout-- > 0))
- {
- DEBUG("status: 0x%x", status);
- usleep(1000);
- }
-
- return status;
-}
-
-int stm32x_read_options(struct flash_bank_s *bank)
-{
- u32 optiondata;
- stm32x_flash_bank_t *stm32x_info = NULL;
- target_t *target = bank->target;
-
- stm32x_info = bank->driver_priv;
-
- /* read current option bytes */
- target_read_u32(target, STM32_FLASH_OBR, &optiondata);
-
- stm32x_info->option_bytes.user_options = (u16)0xFFF8|((optiondata >> 2) & 0x07);
- stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
-
- if (optiondata & (1 << OPT_READOUT))
- INFO("Device Security Bit Set");
-
- /* each bit refers to a 4bank protection */
- target_read_u32(target, STM32_FLASH_WRPR, &optiondata);
-
- stm32x_info->option_bytes.protection[0] = (u16)optiondata;
- stm32x_info->option_bytes.protection[1] = (u16)(optiondata >> 8);
- stm32x_info->option_bytes.protection[2] = (u16)(optiondata >> 16);
- stm32x_info->option_bytes.protection[3] = (u16)(optiondata >> 24);
-
- return ERROR_OK;
-}
-
-int stm32x_erase_options(struct flash_bank_s *bank)
-{
- stm32x_flash_bank_t *stm32x_info = NULL;
- target_t *target = bank->target;
- u32 status;
-
- stm32x_info = bank->driver_priv;
-
- /* read current options */
- stm32x_read_options(bank);
-
- /* unlock flash registers */
- target_write_u32(target, STM32_FLASH_KEYR, KEY1);
- target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
- /* unlock option flash registers */
- target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);
- target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
-
- /* erase option bytes */
- target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER|FLASH_OPTWRE);
- target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER|FLASH_STRT|FLASH_OPTWRE);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* clear readout protection and complementary option bytes
- * this will also force a device unlock if set */
- stm32x_info->option_bytes.RDP = 0x5AA5;
-
- return ERROR_OK;
-}
-
-int stm32x_write_options(struct flash_bank_s *bank)
-{
- stm32x_flash_bank_t *stm32x_info = NULL;
- target_t *target = bank->target;
- u32 status;
-
- stm32x_info = bank->driver_priv;
-
- /* unlock flash registers */
- target_write_u32(target, STM32_FLASH_KEYR, KEY1);
- target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
- /* unlock option flash registers */
- target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);
- target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
-
- /* program option bytes */
- target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG|FLASH_OPTWRE);
-
- /* write user option byte */
- target_write_u16(target, STM32_OB_USER, stm32x_info->option_bytes.user_options);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* write protection byte 1 */
- target_write_u16(target, STM32_OB_WRP0, stm32x_info->option_bytes.protection[0]);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* write protection byte 2 */
- target_write_u16(target, STM32_OB_WRP1, stm32x_info->option_bytes.protection[1]);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* write protection byte 3 */
- target_write_u16(target, STM32_OB_WRP2, stm32x_info->option_bytes.protection[2]);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* write protection byte 4 */
- target_write_u16(target, STM32_OB_WRP3, stm32x_info->option_bytes.protection[3]);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* write readout protection bit */
- target_write_u16(target, STM32_OB_RDP, stm32x_info->option_bytes.RDP);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
- return ERROR_OK;
-}
-
-int stm32x_blank_check(struct flash_bank_s *bank, int first, int last)
-{
- target_t *target = bank->target;
- u8 *buffer;
- int i;
- int nBytes;
-
- if ((first < 0) || (last > bank->num_sectors))
- return ERROR_FLASH_SECTOR_INVALID;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- buffer = malloc(256);
-
- for (i = first; i <= last; i++)
- {
- bank->sectors[i].is_erased = 1;
-
- target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
-
- for (nBytes = 0; nBytes < 256; nBytes++)
- {
- if (buffer[nBytes] != 0xFF)
- {
- bank->sectors[i].is_erased = 0;
- break;
- }
- }
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int stm32x_protect_check(struct flash_bank_s *bank)
-{
- target_t *target = bank->target;
-
- u32 protection;
- int i, s;
- int num_bits;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* each bit refers to a 4bank protection */
- target_read_u32(target, STM32_FLASH_WRPR, &protection);
-
- /* each protection bit is for 4 1K pages */
- num_bits = (bank->num_sectors / 4);
-
- for (i = 0; i < num_bits; i++)
- {
- int set = 1;
-
- if( protection & (1 << i))
- set = 0;
-
- for (s = 0; s < 4; s++)
- bank->sectors[(i * 4) + s].is_protected = set;
- }
-
- return ERROR_OK;
-}
-
-int stm32x_erase(struct flash_bank_s *bank, int first, int last)
-{
- target_t *target = bank->target;
-
- int i;
- u32 status;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* unlock flash registers */
- target_write_u32(target, STM32_FLASH_KEYR, KEY1);
- target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
- for (i = first; i <= last; i++)
- {
- target_write_u32(target, STM32_FLASH_CR, FLASH_PER);
- target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset);
- target_write_u32(target, STM32_FLASH_CR, FLASH_PER|FLASH_STRT);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
- bank->sectors[i].is_erased = 1;
- }
-
- target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
- return ERROR_OK;
-}
-
-int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- stm32x_flash_bank_t *stm32x_info = NULL;
- target_t *target = bank->target;
- u16 prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
- int i, reg, bit;
- int status;
- u32 protection;
-
- stm32x_info = bank->driver_priv;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if ((first && (first % 4)) || ((last + 1) && (last + 1) % 4))
- {
- WARNING("sector start/end incorrect - stm32 has 4K sector protection");
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- /* each bit refers to a 4bank protection */
- target_read_u32(target, STM32_FLASH_WRPR, &protection);
-
- prot_reg[0] = (u16)protection;
- prot_reg[1] = (u16)(protection >> 8);
- prot_reg[2] = (u16)(protection >> 16);
- prot_reg[3] = (u16)(protection >> 24);
-
- for (i = first; i <= last; i++)
- {
- reg = (i / 4) / 8;
- bit = (i / 4) - (reg * 8);
-
- if( set )
- prot_reg[reg] &= ~(1 << bit);
- else
- prot_reg[reg] |= (1 << bit);
- }
-
- if ((status = stm32x_erase_options(bank)) != ERROR_OK)
- return status;
-
- stm32x_info->option_bytes.protection[0] = prot_reg[0];
- stm32x_info->option_bytes.protection[1] = prot_reg[1];
- stm32x_info->option_bytes.protection[2] = prot_reg[2];
- stm32x_info->option_bytes.protection[3] = prot_reg[3];
-
- return stm32x_write_options(bank);
-}
-
-int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 buffer_size = 8192;
- working_area_t *source;
- u32 address = bank->base + offset;
- reg_param_t reg_params[4];
- armv7m_algorithm_t armv7m_info;
- int retval = ERROR_OK;
-
- u8 stm32x_flash_write_code[] = {
- /* write: */
- 0xDF, 0xF8, 0x24, 0x40, /* ldr r4, STM32_FLASH_CR */
- 0x09, 0x4D, /* ldr r5, STM32_FLASH_SR */
- 0x4F, 0xF0, 0x01, 0x03, /* mov r3, #1 */
- 0x23, 0x60, /* str r3, [r4, #0] */
- 0x30, 0xF8, 0x02, 0x3B, /* ldrh r3, [r0], #2 */
- 0x21, 0xF8, 0x02, 0x3B, /* strh r3, [r1], #2 */
- /* busy: */
- 0x2B, 0x68, /* ldr r3, [r5, #0] */
- 0x13, 0xF0, 0x01, 0x0F, /* tst r3, #0x01 */
- 0xFB, 0xD0, /* beq busy */
- 0x13, 0xF0, 0x14, 0x0F, /* tst r3, #0x14 */
- 0x01, 0xD1, /* bne exit */
- 0x01, 0x3A, /* subs r2, r2, #1 */
- 0xED, 0xD1, /* bne write */
- /* exit: */
- 0xFE, 0xE7, /* b exit */
- 0x10, 0x20, 0x02, 0x40, /* STM32_FLASH_CR: .word 0x40022010 */
- 0x0C, 0x20, 0x02, 0x40 /* STM32_FLASH_SR: .word 0x4002200C */
- };
-
- /* flash write code */
- if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)
- {
- WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- };
-
- target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
-
- /* memory buffer */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
- {
- buffer_size /= 2;
- if (buffer_size <= 256)
- {
- /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
- if (stm32x_info->write_algorithm)
- target_free_working_area(target, stm32x_info->write_algorithm);
-
- WARNING("no large enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- };
-
- armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
- armv7m_info.core_mode = ARMV7M_MODE_ANY;
- armv7m_info.core_state = ARMV7M_STATE_THUMB;
-
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_IN);
-
- while (count > 0)
- {
- u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
-
- target_write_buffer(target, source->address, thisrun_count * 2, buffer);
-
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- buf_set_u32(reg_params[1].value, 0, 32, address);
- buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
-
- if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
- stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
- {
- ERROR("error executing str7x flash write algorithm");
- break;
- }
-
- if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)
- {
- retval = ERROR_FLASH_OPERATION_FAILED;
- break;
- }
-
- buffer += thisrun_count * 2;
- address += thisrun_count * 2;
- count -= thisrun_count;
- }
-
- target_free_working_area(target, source);
- target_free_working_area(target, stm32x_info->write_algorithm);
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
-
- return retval;
-}
-
-int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- target_t *target = bank->target;
- u32 words_remaining = (count / 2);
- u32 bytes_remaining = (count & 0x00000001);
- u32 address = bank->base + offset;
- u32 bytes_written = 0;
- u8 status;
- u32 retval;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (offset & 0x1)
- {
- WARNING("offset 0x%x breaks required 2-byte alignment", offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
-
- /* unlock flash registers */
- target_write_u32(target, STM32_FLASH_KEYR, KEY1);
- target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
- /* multiple half words (2-byte) to be programmed? */
- if (words_remaining > 0)
- {
- /* try using a block write */
- if ((retval = stm32x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
- {
- if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- /* if block write failed (no sufficient working area),
- * we use normal (slow) single dword accesses */
- WARNING("couldn't use block writes, falling back to single memory accesses");
- }
- else if (retval == ERROR_FLASH_OPERATION_FAILED)
- {
- ERROR("flash writing failed with error code: 0x%x", retval);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
- else
- {
- buffer += words_remaining * 2;
- address += words_remaining * 2;
- words_remaining = 0;
- }
- }
-
- while (words_remaining > 0)
- {
- target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
- target_write_u16(target, address, *(u16*)(buffer + bytes_written));
-
- status = stm32x_wait_status_busy(bank, 5);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
-
- bytes_written += 2;
- words_remaining--;
- address += 2;
- }
-
- if (bytes_remaining)
- {
- u8 last_halfword[2] = {0xff, 0xff};
- int i = 0;
-
- while(bytes_remaining > 0)
- {
- last_halfword[i++] = *(buffer + bytes_written);
- bytes_remaining--;
- bytes_written++;
- }
-
- target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
- target_write_u16(target, address, *(u16*)last_halfword);
-
- status = stm32x_wait_status_busy(bank, 5);
-
- if( status & FLASH_WRPRTERR )
- return ERROR_FLASH_OPERATION_FAILED;
- if( status & FLASH_PGERR )
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
- return ERROR_OK;
-}
-
-int stm32x_probe(struct flash_bank_s *bank)
-{
- target_t *target = bank->target;
- stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
- int i;
- u16 num_sectors;
- u32 device_id;
-
- stm32x_info->probed = 0;
-
- /* read stm32 device id register */
- target_read_u32(target, 0xE0042000, &device_id);
- INFO( "device id = 0x%08x", device_id );
-
- if (!(device_id & 0x410))
- {
- WARNING( "Cannot identify target as a STM32 family." );
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* get flash size from target */
- target_read_u16(target, 0x1FFFF7E0, &num_sectors);
-
- /* check for early silicon rev A */
- if ((device_id >> 16) == 0 )
- {
- /* number of sectors incorrect on revA */
- WARNING( "STM32 Rev A Silicon detected, probe inaccurate - assuming 128k flash" );
- num_sectors = 128;
- }
-
- INFO( "flash size = %dkbytes", num_sectors );
-
- bank->base = 0x08000000;
- bank->size = num_sectors * 1024;
- bank->num_sectors = num_sectors;
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
-
- for (i = 0; i < num_sectors; i++)
- {
- bank->sectors[i].offset = i * 1024;
- bank->sectors[i].size = 1024;
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 1;
- }
-
- stm32x_info->probed = 1;
-
- return ERROR_OK;
-}
-
-int stm32x_auto_probe(struct flash_bank_s *bank)
-{
- stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
- if (stm32x_info->probed)
- return ERROR_OK;
- return stm32x_probe(bank);
-}
-
-int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- return ERROR_OK;
-}
-
-int stm32x_erase_check(struct flash_bank_s *bank)
-{
- return stm32x_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- snprintf(buf, buf_size, "stm32x flash driver info" );
- return ERROR_OK;
-}
-
-int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- target_t *target = NULL;
- stm32x_flash_bank_t *stm32x_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "stm32x lock <bank>");
- 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;
- }
-
- stm32x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stm32x_erase_options(bank) != ERROR_OK)
- {
- command_print(cmd_ctx, "stm32x failed to erase options");
- return ERROR_OK;
- }
-
- /* set readout protection */
- stm32x_info->option_bytes.RDP = 0;
-
- if (stm32x_write_options(bank) != ERROR_OK)
- {
- command_print(cmd_ctx, "stm32x failed to lock device");
- return ERROR_OK;
- }
-
- command_print(cmd_ctx, "stm32x locked");
-
- return ERROR_OK;
-}
-
-int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- target_t *target = NULL;
- stm32x_flash_bank_t *stm32x_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "stm32x unlock <bank>");
- 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;
- }
-
- stm32x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stm32x_erase_options(bank) != ERROR_OK)
- {
- command_print(cmd_ctx, "stm32x failed to unlock device");
- return ERROR_OK;
- }
-
- if (stm32x_write_options(bank) != ERROR_OK)
- {
- command_print(cmd_ctx, "stm32x failed to lock device");
- return ERROR_OK;
- }
-
- command_print(cmd_ctx, "stm32x unlocked");
-
- return ERROR_OK;
-}
-
-int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u32 optionbyte;
- target_t *target = NULL;
- stm32x_flash_bank_t *stm32x_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "stm32x options_read <bank>");
- 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;
- }
-
- stm32x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- target_read_u32(target, STM32_FLASH_OBR, &optionbyte);
- command_print(cmd_ctx, "Option Byte: 0x%x", optionbyte);
-
- if (buf_get_u32((u8*)&optionbyte, OPT_ERROR, 1))
- command_print(cmd_ctx, "Option Byte Complement Error");
-
- if (buf_get_u32((u8*)&optionbyte, OPT_READOUT, 1))
- command_print(cmd_ctx, "Readout Protection On");
- else
- command_print(cmd_ctx, "Readout Protection Off");
-
- if (buf_get_u32((u8*)&optionbyte, OPT_RDWDGSW, 1))
- command_print(cmd_ctx, "Software Watchdog");
- else
- command_print(cmd_ctx, "Hardware Watchdog");
-
- if (buf_get_u32((u8*)&optionbyte, OPT_RDRSTSTOP, 1))
- command_print(cmd_ctx, "Stop: No reset generated");
- else
- command_print(cmd_ctx, "Stop: Reset generated");
-
- if (buf_get_u32((u8*)&optionbyte, OPT_RDRSTSTDBY, 1))
- command_print(cmd_ctx, "Standby: No reset generated");
- else
- command_print(cmd_ctx, "Standby: Reset generated");
-
- return ERROR_OK;
-}
-
-int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- target_t *target = NULL;
- stm32x_flash_bank_t *stm32x_info = NULL;
- u16 optionbyte = 0xF8;
-
- if (argc < 4)
- {
- command_print(cmd_ctx, "stm32x options_write <bank> <SWWDG|HWWDG> <RSTSTNDBY|NORSTSTNDBY> <RSTSTOP|NORSTSTOP>");
- 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;
- }
-
- stm32x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (strcmp(args[1], "SWWDG") == 0)
- {
- optionbyte |= (1<<0);
- }
- else
- {
- optionbyte &= ~(1<<0);
- }
-
- if (strcmp(args[2], "NORSTSTNDBY") == 0)
- {
- optionbyte |= (1<<1);
- }
- else
- {
- optionbyte &= ~(1<<1);
- }
-
- if (strcmp(args[3], "NORSTSTOP") == 0)
- {
- optionbyte |= (1<<2);
- }
- else
- {
- optionbyte &= ~(1<<2);
- }
-
- if (stm32x_erase_options(bank) != ERROR_OK)
- {
- command_print(cmd_ctx, "stm32x failed to erase options");
- return ERROR_OK;
- }
-
- stm32x_info->option_bytes.user_options = optionbyte;
-
- if (stm32x_write_options(bank) != ERROR_OK)
- {
- command_print(cmd_ctx, "stm32x failed to write options");
- return ERROR_OK;
- }
-
- command_print(cmd_ctx, "stm32x write options complete");
-
- return ERROR_OK;
-}
-
-int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = NULL;
- stm32x_flash_bank_t *stm32x_info = NULL;
- flash_bank_t *bank;
- u32 status;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "stm32x mass_erase <bank>");
- 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;
- }
-
- stm32x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* unlock option flash registers */
- target_write_u32(target, STM32_FLASH_KEYR, KEY1);
- target_write_u32(target, STM32_FLASH_KEYR, KEY2);
-
- /* mass erase flash memory */
- target_write_u32(target, STM32_FLASH_CR, FLASH_MER);
- target_write_u32(target, STM32_FLASH_CR, FLASH_MER|FLASH_STRT);
-
- status = stm32x_wait_status_busy(bank, 10);
-
- target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
-
- if( status & FLASH_WRPRTERR )
- {
- command_print(cmd_ctx, "stm32x device protected");
- return ERROR_OK;
- }
-
- if( status & FLASH_PGERR )
- {
- command_print(cmd_ctx, "stm32x device programming failed");
- return ERROR_OK;
- }
-
- command_print(cmd_ctx, "stm32x mass erase complete");
-
- 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 "replacements.h"\r
+\r
+#include "stm32x.h"\r
+#include "flash.h"\r
+#include "target.h"\r
+#include "log.h"\r
+#include "armv7m.h"\r
+#include "algorithm.h"\r
+#include "binarybuffer.h"\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+int stm32x_register_commands(struct command_context_s *cmd_ctx);\r
+int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
+int stm32x_erase(struct flash_bank_s *bank, int first, int last);\r
+int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last);\r
+int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
+int stm32x_probe(struct flash_bank_s *bank);\r
+int stm32x_auto_probe(struct flash_bank_s *bank);\r
+int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int stm32x_protect_check(struct flash_bank_s *bank);\r
+int stm32x_erase_check(struct flash_bank_s *bank);\r
+int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
+\r
+int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+flash_driver_t stm32x_flash =\r
+{\r
+ .name = "stm32x",\r
+ .register_commands = stm32x_register_commands,\r
+ .flash_bank_command = stm32x_flash_bank_command,\r
+ .erase = stm32x_erase,\r
+ .protect = stm32x_protect,\r
+ .write = stm32x_write,\r
+ .probe = stm32x_probe,\r
+ .auto_probe = stm32x_auto_probe,\r
+ .erase_check = stm32x_erase_check,\r
+ .protect_check = stm32x_protect_check,\r
+ .info = stm32x_info\r
+};\r
+\r
+int stm32x_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ command_t *stm32x_cmd = register_command(cmd_ctx, NULL, "stm32x", NULL, COMMAND_ANY, "stm32x flash specific commands");\r
+ \r
+ register_command(cmd_ctx, stm32x_cmd, "lock", stm32x_handle_lock_command, COMMAND_EXEC,\r
+ "lock device");\r
+ register_command(cmd_ctx, stm32x_cmd, "unlock", stm32x_handle_unlock_command, COMMAND_EXEC,\r
+ "unlock protected device");\r
+ register_command(cmd_ctx, stm32x_cmd, "mass_erase", stm32x_handle_mass_erase_command, COMMAND_EXEC,\r
+ "mass erase device");\r
+ register_command(cmd_ctx, stm32x_cmd, "options_read", stm32x_handle_options_read_command, COMMAND_EXEC,\r
+ "read device option bytes");\r
+ register_command(cmd_ctx, stm32x_cmd, "options_write", stm32x_handle_options_write_command, COMMAND_EXEC,\r
+ "write device option bytes");\r
+ return ERROR_OK;\r
+}\r
+\r
+/* flash bank stm32x <base> <size> 0 0 <target#>\r
+ */\r
+int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
+{\r
+ stm32x_flash_bank_t *stm32x_info;\r
+ \r
+ if (argc < 6)\r
+ {\r
+ WARNING("incomplete flash_bank stm32x configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ stm32x_info = malloc(sizeof(stm32x_flash_bank_t));\r
+ bank->driver_priv = stm32x_info;\r
+ \r
+ stm32x_info->write_algorithm = NULL;\r
+ stm32x_info->probed = 0;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+u32 stm32x_get_flash_status(flash_bank_t *bank)\r
+{\r
+ target_t *target = bank->target;\r
+ u32 status;\r
+ \r
+ target_read_u32(target, STM32_FLASH_SR, &status);\r
+ \r
+ return status;\r
+}\r
+\r
+u32 stm32x_wait_status_busy(flash_bank_t *bank, int timeout)\r
+{\r
+ u32 status;\r
+ \r
+ /* wait for busy to clear */\r
+ while (((status = stm32x_get_flash_status(bank)) & FLASH_BSY) && (timeout-- > 0))\r
+ {\r
+ DEBUG("status: 0x%x", status);\r
+ usleep(1000);\r
+ }\r
+ \r
+ return status;\r
+}\r
+\r
+int stm32x_read_options(struct flash_bank_s *bank)\r
+{\r
+ u32 optiondata;\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ target_t *target = bank->target;\r
+ \r
+ stm32x_info = bank->driver_priv;\r
+ \r
+ /* read current option bytes */\r
+ target_read_u32(target, STM32_FLASH_OBR, &optiondata);\r
+ \r
+ stm32x_info->option_bytes.user_options = (u16)0xFFF8|((optiondata >> 2) & 0x07);\r
+ stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;\r
+ \r
+ if (optiondata & (1 << OPT_READOUT))\r
+ INFO("Device Security Bit Set");\r
+ \r
+ /* each bit refers to a 4bank protection */\r
+ target_read_u32(target, STM32_FLASH_WRPR, &optiondata);\r
+ \r
+ stm32x_info->option_bytes.protection[0] = (u16)optiondata;\r
+ stm32x_info->option_bytes.protection[1] = (u16)(optiondata >> 8);\r
+ stm32x_info->option_bytes.protection[2] = (u16)(optiondata >> 16);\r
+ stm32x_info->option_bytes.protection[3] = (u16)(optiondata >> 24);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_erase_options(struct flash_bank_s *bank)\r
+{\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ target_t *target = bank->target;\r
+ u32 status;\r
+ \r
+ stm32x_info = bank->driver_priv;\r
+ \r
+ /* read current options */\r
+ stm32x_read_options(bank);\r
+ \r
+ /* unlock flash registers */\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY2);\r
+ \r
+ /* unlock option flash registers */\r
+ target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);\r
+ \r
+ /* erase option bytes */\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER|FLASH_OPTWRE);\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER|FLASH_STRT|FLASH_OPTWRE);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* clear readout protection and complementary option bytes\r
+ * this will also force a device unlock if set */\r
+ stm32x_info->option_bytes.RDP = 0x5AA5;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_write_options(struct flash_bank_s *bank)\r
+{\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ target_t *target = bank->target;\r
+ u32 status;\r
+ \r
+ stm32x_info = bank->driver_priv;\r
+ \r
+ /* unlock flash registers */\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY2);\r
+ \r
+ /* unlock option flash registers */\r
+ target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);\r
+ \r
+ /* program option bytes */\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG|FLASH_OPTWRE);\r
+ \r
+ /* write user option byte */\r
+ target_write_u16(target, STM32_OB_USER, stm32x_info->option_bytes.user_options);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* write protection byte 1 */\r
+ target_write_u16(target, STM32_OB_WRP0, stm32x_info->option_bytes.protection[0]);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* write protection byte 2 */\r
+ target_write_u16(target, STM32_OB_WRP1, stm32x_info->option_bytes.protection[1]);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* write protection byte 3 */\r
+ target_write_u16(target, STM32_OB_WRP2, stm32x_info->option_bytes.protection[2]);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* write protection byte 4 */\r
+ target_write_u16(target, STM32_OB_WRP3, stm32x_info->option_bytes.protection[3]);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* write readout protection bit */\r
+ target_write_u16(target, STM32_OB_RDP, stm32x_info->option_bytes.RDP);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_blank_check(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ target_t *target = bank->target;\r
+ u8 *buffer;\r
+ int i;\r
+ int nBytes;\r
+ \r
+ if ((first < 0) || (last > bank->num_sectors))\r
+ return ERROR_FLASH_SECTOR_INVALID;\r
+\r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ buffer = malloc(256);\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ bank->sectors[i].is_erased = 1;\r
+\r
+ target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);\r
+ \r
+ for (nBytes = 0; nBytes < 256; nBytes++)\r
+ {\r
+ if (buffer[nBytes] != 0xFF)\r
+ {\r
+ bank->sectors[i].is_erased = 0;\r
+ break;\r
+ }\r
+ } \r
+ }\r
+ \r
+ free(buffer);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_protect_check(struct flash_bank_s *bank)\r
+{\r
+ target_t *target = bank->target;\r
+ \r
+ u32 protection;\r
+ int i, s;\r
+ int num_bits;\r
+\r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+\r
+ /* each bit refers to a 4bank protection */\r
+ target_read_u32(target, STM32_FLASH_WRPR, &protection);\r
+ \r
+ /* each protection bit is for 4 1K pages */\r
+ num_bits = (bank->num_sectors / 4);\r
+ \r
+ for (i = 0; i < num_bits; i++)\r
+ {\r
+ int set = 1;\r
+ \r
+ if( protection & (1 << i))\r
+ set = 0;\r
+ \r
+ for (s = 0; s < 4; s++)\r
+ bank->sectors[(i * 4) + s].is_protected = set;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_erase(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ target_t *target = bank->target;\r
+ \r
+ int i;\r
+ u32 status;\r
+ \r
+ /* unlock flash registers */\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY2);\r
+ \r
+ for (i = first; i <= last; i++)\r
+ { \r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_PER);\r
+ target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset);\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_PER|FLASH_STRT);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ bank->sectors[i].is_erased = 1;\r
+ }\r
+\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)\r
+{\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ target_t *target = bank->target;\r
+ u16 prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};\r
+ int i, reg, bit;\r
+ int status;\r
+ u32 protection;\r
+ \r
+ stm32x_info = bank->driver_priv;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ if ((first && (first % 4)) || ((last + 1) && (last + 1) % 4))\r
+ {\r
+ WARNING("sector start/end incorrect - stm32 has 4K sector protection");\r
+ return ERROR_FLASH_SECTOR_INVALID;\r
+ }\r
+ \r
+ /* each bit refers to a 4bank protection */\r
+ target_read_u32(target, STM32_FLASH_WRPR, &protection);\r
+ \r
+ prot_reg[0] = (u16)protection;\r
+ prot_reg[1] = (u16)(protection >> 8);\r
+ prot_reg[2] = (u16)(protection >> 16);\r
+ prot_reg[3] = (u16)(protection >> 24);\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ reg = (i / 4) / 8;\r
+ bit = (i / 4) - (reg * 8);\r
+ \r
+ if( set )\r
+ prot_reg[reg] &= ~(1 << bit);\r
+ else\r
+ prot_reg[reg] |= (1 << bit);\r
+ }\r
+ \r
+ if ((status = stm32x_erase_options(bank)) != ERROR_OK)\r
+ return status;\r
+ \r
+ stm32x_info->option_bytes.protection[0] = prot_reg[0];\r
+ stm32x_info->option_bytes.protection[1] = prot_reg[1];\r
+ stm32x_info->option_bytes.protection[2] = prot_reg[2];\r
+ stm32x_info->option_bytes.protection[3] = prot_reg[3];\r
+ \r
+ return stm32x_write_options(bank);\r
+}\r
+\r
+int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ stm32x_flash_bank_t *stm32x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 buffer_size = 8192;\r
+ working_area_t *source;\r
+ u32 address = bank->base + offset;\r
+ reg_param_t reg_params[4];\r
+ armv7m_algorithm_t armv7m_info;\r
+ int retval = ERROR_OK;\r
+ \r
+ u8 stm32x_flash_write_code[] = {\r
+ /* write: */\r
+ 0xDF, 0xF8, 0x24, 0x40, /* ldr r4, STM32_FLASH_CR */\r
+ 0x09, 0x4D, /* ldr r5, STM32_FLASH_SR */\r
+ 0x4F, 0xF0, 0x01, 0x03, /* mov r3, #1 */\r
+ 0x23, 0x60, /* str r3, [r4, #0] */\r
+ 0x30, 0xF8, 0x02, 0x3B, /* ldrh r3, [r0], #2 */\r
+ 0x21, 0xF8, 0x02, 0x3B, /* strh r3, [r1], #2 */\r
+ /* busy: */\r
+ 0x2B, 0x68, /* ldr r3, [r5, #0] */\r
+ 0x13, 0xF0, 0x01, 0x0F, /* tst r3, #0x01 */\r
+ 0xFB, 0xD0, /* beq busy */\r
+ 0x13, 0xF0, 0x14, 0x0F, /* tst r3, #0x14 */\r
+ 0x01, 0xD1, /* bne exit */\r
+ 0x01, 0x3A, /* subs r2, r2, #1 */\r
+ 0xED, 0xD1, /* bne write */\r
+ /* exit: */\r
+ 0xFE, 0xE7, /* b exit */ \r
+ 0x10, 0x20, 0x02, 0x40, /* STM32_FLASH_CR: .word 0x40022010 */\r
+ 0x0C, 0x20, 0x02, 0x40 /* STM32_FLASH_SR: .word 0x4002200C */\r
+ };\r
+ \r
+ /* flash write code */\r
+ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)\r
+ {\r
+ WARNING("no working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ };\r
+ \r
+ target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code);\r
+\r
+ /* memory buffer */\r
+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)\r
+ {\r
+ buffer_size /= 2;\r
+ if (buffer_size <= 256)\r
+ {\r
+ /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */\r
+ if (stm32x_info->write_algorithm)\r
+ target_free_working_area(target, stm32x_info->write_algorithm);\r
+ \r
+ WARNING("no large enough working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ }\r
+ };\r
+ \r
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;\r
+ armv7m_info.core_mode = ARMV7M_MODE_ANY;\r
+ armv7m_info.core_state = ARMV7M_STATE_THUMB;\r
+ \r
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);\r
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);\r
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);\r
+ init_reg_param(®_params[3], "r3", 32, PARAM_IN);\r
+ \r
+ while (count > 0)\r
+ {\r
+ u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;\r
+ \r
+ target_write_buffer(target, source->address, thisrun_count * 2, buffer);\r
+ \r
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);\r
+ buf_set_u32(reg_params[1].value, 0, 32, address);\r
+ buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);\r
+ \r
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \\r
+ stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)\r
+ {\r
+ ERROR("error executing str7x flash write algorithm");\r
+ break;\r
+ }\r
+ \r
+ if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)\r
+ {\r
+ retval = ERROR_FLASH_OPERATION_FAILED;\r
+ break;\r
+ }\r
+ \r
+ buffer += thisrun_count * 2;\r
+ address += thisrun_count * 2;\r
+ count -= thisrun_count;\r
+ }\r
+ \r
+ target_free_working_area(target, source);\r
+ target_free_working_area(target, stm32x_info->write_algorithm);\r
+ \r
+ destroy_reg_param(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ destroy_reg_param(®_params[3]);\r
+ \r
+ return retval;\r
+}\r
+\r
+int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ target_t *target = bank->target;\r
+ u32 words_remaining = (count / 2);\r
+ u32 bytes_remaining = (count & 0x00000001);\r
+ u32 address = bank->base + offset;\r
+ u32 bytes_written = 0;\r
+ u8 status;\r
+ u32 retval;\r
+ \r
+ if (offset & 0x1)\r
+ {\r
+ WARNING("offset 0x%x breaks required 2-byte alignment", offset);\r
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
+ }\r
+ \r
+ /* unlock flash registers */\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY2);\r
+ \r
+ /* multiple half words (2-byte) to be programmed? */\r
+ if (words_remaining > 0) \r
+ {\r
+ /* try using a block write */\r
+ if ((retval = stm32x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)\r
+ {\r
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)\r
+ {\r
+ /* if block write failed (no sufficient working area),\r
+ * we use normal (slow) single dword accesses */ \r
+ WARNING("couldn't use block writes, falling back to single memory accesses");\r
+ }\r
+ else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
+ {\r
+ ERROR("flash writing failed with error code: 0x%x", retval);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ buffer += words_remaining * 2;\r
+ address += words_remaining * 2;\r
+ words_remaining = 0;\r
+ }\r
+ }\r
+\r
+ while (words_remaining > 0)\r
+ {\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_PG);\r
+ target_write_u16(target, address, *(u16*)(buffer + bytes_written));\r
+ \r
+ status = stm32x_wait_status_busy(bank, 5);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+\r
+ bytes_written += 2;\r
+ words_remaining--;\r
+ address += 2;\r
+ }\r
+ \r
+ if (bytes_remaining)\r
+ {\r
+ u8 last_halfword[2] = {0xff, 0xff};\r
+ int i = 0;\r
+ \r
+ while(bytes_remaining > 0)\r
+ {\r
+ last_halfword[i++] = *(buffer + bytes_written); \r
+ bytes_remaining--;\r
+ bytes_written++;\r
+ }\r
+ \r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_PG);\r
+ target_write_u16(target, address, *(u16*)last_halfword);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 5);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ if( status & FLASH_PGERR )\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_probe(struct flash_bank_s *bank)\r
+{\r
+ target_t *target = bank->target;\r
+ stm32x_flash_bank_t *stm32x_info = bank->driver_priv;\r
+ int i;\r
+ u16 num_sectors;\r
+ u32 device_id;\r
+ \r
+ stm32x_info->probed = 0;\r
+ \r
+ /* read stm32 device id register */\r
+ target_read_u32(target, 0xE0042000, &device_id);\r
+ INFO( "device id = 0x%08x", device_id );\r
+ \r
+ if (!(device_id & 0x410))\r
+ {\r
+ WARNING( "Cannot identify target as a STM32 family." );\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ /* get flash size from target */\r
+ target_read_u16(target, 0x1FFFF7E0, &num_sectors);\r
+ \r
+ /* check for early silicon rev A */\r
+ if ((device_id >> 16) == 0 )\r
+ {\r
+ /* number of sectors incorrect on revA */\r
+ WARNING( "STM32 Rev A Silicon detected, probe inaccurate - assuming 128k flash" );\r
+ num_sectors = 128;\r
+ }\r
+ \r
+ INFO( "flash size = %dkbytes", num_sectors );\r
+ \r
+ bank->base = 0x08000000;\r
+ bank->size = num_sectors * 1024;\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
+ bank->sectors[i].offset = i * 1024;\r
+ bank->sectors[i].size = 1024;\r
+ bank->sectors[i].is_erased = -1;\r
+ bank->sectors[i].is_protected = 1;\r
+ }\r
+ \r
+ stm32x_info->probed = 1;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_auto_probe(struct flash_bank_s *bank)\r
+{\r
+ stm32x_flash_bank_t *stm32x_info = bank->driver_priv;\r
+ if (stm32x_info->probed)\r
+ return ERROR_OK;\r
+ return stm32x_probe(bank);\r
+}\r
+\r
+int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_erase_check(struct flash_bank_s *bank)\r
+{\r
+ return stm32x_blank_check(bank, 0, bank->num_sectors - 1);\r
+}\r
+\r
+int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
+{\r
+ snprintf(buf, buf_size, "stm32x flash driver info" );\r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ target_t *target = NULL;\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "stm32x lock <bank>");\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
+ stm32x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ if (stm32x_erase_options(bank) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "stm32x failed to erase options");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ /* set readout protection */ \r
+ stm32x_info->option_bytes.RDP = 0;\r
+ \r
+ if (stm32x_write_options(bank) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "stm32x failed to lock device");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ command_print(cmd_ctx, "stm32x locked");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ target_t *target = NULL;\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "stm32x unlock <bank>");\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
+ stm32x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ if (stm32x_erase_options(bank) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "stm32x failed to unlock device");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ if (stm32x_write_options(bank) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "stm32x failed to lock device");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ command_print(cmd_ctx, "stm32x unlocked");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ u32 optionbyte;\r
+ target_t *target = NULL;\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "stm32x options_read <bank>");\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
+ stm32x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ target_read_u32(target, STM32_FLASH_OBR, &optionbyte);\r
+ command_print(cmd_ctx, "Option Byte: 0x%x", optionbyte);\r
+ \r
+ if (buf_get_u32((u8*)&optionbyte, OPT_ERROR, 1))\r
+ command_print(cmd_ctx, "Option Byte Complement Error");\r
+ \r
+ if (buf_get_u32((u8*)&optionbyte, OPT_READOUT, 1))\r
+ command_print(cmd_ctx, "Readout Protection On");\r
+ else\r
+ command_print(cmd_ctx, "Readout Protection Off");\r
+ \r
+ if (buf_get_u32((u8*)&optionbyte, OPT_RDWDGSW, 1))\r
+ command_print(cmd_ctx, "Software Watchdog");\r
+ else\r
+ command_print(cmd_ctx, "Hardware Watchdog");\r
+ \r
+ if (buf_get_u32((u8*)&optionbyte, OPT_RDRSTSTOP, 1))\r
+ command_print(cmd_ctx, "Stop: No reset generated");\r
+ else\r
+ command_print(cmd_ctx, "Stop: Reset generated");\r
+ \r
+ if (buf_get_u32((u8*)&optionbyte, OPT_RDRSTSTDBY, 1))\r
+ command_print(cmd_ctx, "Standby: No reset generated");\r
+ else\r
+ command_print(cmd_ctx, "Standby: Reset generated");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ target_t *target = NULL;\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ u16 optionbyte = 0xF8;\r
+ \r
+ if (argc < 4)\r
+ {\r
+ command_print(cmd_ctx, "stm32x options_write <bank> <SWWDG|HWWDG> <RSTSTNDBY|NORSTSTNDBY> <RSTSTOP|NORSTSTOP>");\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
+ stm32x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ if (strcmp(args[1], "SWWDG") == 0)\r
+ {\r
+ optionbyte |= (1<<0);\r
+ }\r
+ else\r
+ {\r
+ optionbyte &= ~(1<<0);\r
+ }\r
+ \r
+ if (strcmp(args[2], "NORSTSTNDBY") == 0)\r
+ {\r
+ optionbyte |= (1<<1);\r
+ }\r
+ else\r
+ {\r
+ optionbyte &= ~(1<<1);\r
+ }\r
+ \r
+ if (strcmp(args[3], "NORSTSTOP") == 0)\r
+ {\r
+ optionbyte |= (1<<2);\r
+ }\r
+ else\r
+ {\r
+ optionbyte &= ~(1<<2);\r
+ }\r
+ \r
+ if (stm32x_erase_options(bank) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "stm32x failed to erase options");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ stm32x_info->option_bytes.user_options = optionbyte;\r
+ \r
+ if (stm32x_write_options(bank) != ERROR_OK)\r
+ {\r
+ command_print(cmd_ctx, "stm32x failed to write options");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ command_print(cmd_ctx, "stm32x write options complete");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ target_t *target = NULL;\r
+ stm32x_flash_bank_t *stm32x_info = NULL;\r
+ flash_bank_t *bank;\r
+ u32 status;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "stm32x mass_erase <bank>");\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
+ stm32x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ /* unlock option flash registers */\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY1);\r
+ target_write_u32(target, STM32_FLASH_KEYR, KEY2);\r
+ \r
+ /* mass erase flash memory */\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_MER);\r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_MER|FLASH_STRT);\r
+ \r
+ status = stm32x_wait_status_busy(bank, 10);\r
+ \r
+ target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);\r
+ \r
+ if( status & FLASH_WRPRTERR )\r
+ {\r
+ command_print(cmd_ctx, "stm32x device protected");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ if( status & FLASH_PGERR )\r
+ {\r
+ command_print(cmd_ctx, "stm32x device programming failed");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ command_print(cmd_ctx, "stm32x mass erase complete");\r
+ \r
+ return ERROR_OK;\r
+}\r
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "str7x.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>
-#include <unistd.h>
-
-str7x_mem_layout_t mem_layout[] = {
- {0x00000000, 0x02000, 0x01},
- {0x00002000, 0x02000, 0x02},
- {0x00004000, 0x02000, 0x04},
- {0x00006000, 0x02000, 0x08},
- {0x00008000, 0x08000, 0x10},
- {0x00010000, 0x10000, 0x20},
- {0x00020000, 0x10000, 0x40},
- {0x00030000, 0x10000, 0x80},
- {0x000C0000, 0x02000, 0x10000},
- {0x000C2000, 0x02000, 0x20000},
-};
-
-int str7x_register_commands(struct command_context_s *cmd_ctx);
-int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int str7x_erase(struct flash_bank_s *bank, int first, int last);
-int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
-int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int str7x_probe(struct flash_bank_s *bank);
-int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str7x_protect_check(struct flash_bank_s *bank);
-int str7x_erase_check(struct flash_bank_s *bank);
-int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-flash_driver_t str7x_flash =
-{
- .name = "str7x",
- .register_commands = str7x_register_commands,
- .flash_bank_command = str7x_flash_bank_command,
- .erase = str7x_erase,
- .protect = str7x_protect,
- .write = str7x_write,
- .probe = str7x_probe,
- .auto_probe = str7x_probe,
- .erase_check = str7x_erase_check,
- .protect_check = str7x_protect_check,
- .info = str7x_info
-};
-
-int str7x_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *str7x_cmd = register_command(cmd_ctx, NULL, "str7x", NULL, COMMAND_ANY, NULL);
-
- register_command(cmd_ctx, str7x_cmd, "disable_jtag", str7x_handle_disable_jtag_command, COMMAND_EXEC,
- "disable jtag access");
-
- return ERROR_OK;
-}
-
-int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
-{
- return (bank->base | reg);
-}
-
-int str7x_build_block_list(struct flash_bank_s *bank)
-{
- str7x_flash_bank_t *str7x_info = bank->driver_priv;
-
- int i;
- int num_sectors = 0, b0_sectors = 0, b1_sectors = 0;
-
- switch (bank->size)
- {
- case 16 * 1024:
- b0_sectors = 2;
- break;
- case 64 * 1024:
- b0_sectors = 5;
- break;
- case 128 * 1024:
- b0_sectors = 6;
- break;
- case 256 * 1024:
- b0_sectors = 8;
- break;
- default:
- ERROR("BUG: unknown bank->size encountered");
- exit(-1);
- }
-
- if( str7x_info->bank1 == 1 )
- {
- b1_sectors += 2;
- }
-
- num_sectors = b0_sectors + b1_sectors;
-
- bank->num_sectors = num_sectors;
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
- str7x_info->sector_bits = malloc(sizeof(u32) * num_sectors);
- str7x_info->sector_bank = malloc(sizeof(u32) * num_sectors);
-
- num_sectors = 0;
-
- for (i = 0; i < b0_sectors; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str7x_info->sector_bank[num_sectors] = 0;
- str7x_info->sector_bits[num_sectors++] = mem_layout[i].sector_bit;
- }
-
- if (b1_sectors)
- {
- for (i = 8; i < 10; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str7x_info->sector_bank[num_sectors] = 1;
- str7x_info->sector_bits[num_sectors++] = mem_layout[i].sector_bit;
- }
- }
-
- return ERROR_OK;
-}
-
-/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
- */
-int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- str7x_flash_bank_t *str7x_info;
-
- if (argc < 7)
- {
- WARNING("incomplete flash_bank str7x configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- str7x_info = malloc(sizeof(str7x_flash_bank_t));
- bank->driver_priv = str7x_info;
-
- /* set default bits for str71x flash */
- str7x_info->bank1 = 1;
- str7x_info->busy_bits = (FLASH_LOCK|FLASH_BSYA1|FLASH_BSYA0);
- str7x_info->disable_bit = (1<<1);
-
- if (strcmp(args[6], "STR71x") == 0)
- {
- if (bank->base != 0x40000000)
- {
- WARNING("overriding flash base address for STR71x device with 0x40000000");
- bank->base = 0x40000000;
- }
- }
- else if (strcmp(args[6], "STR73x") == 0)
- {
- str7x_info->bank1 = 0;
- str7x_info->busy_bits = (FLASH_LOCK|FLASH_BSYA0);
-
- if (bank->base != 0x80000000)
- {
- WARNING("overriding flash base address for STR73x device with 0x80000000");
- bank->base = 0x80000000;
- }
- }
- else if (strcmp(args[6], "STR75x") == 0)
- {
- str7x_info->disable_bit = (1<<0);
-
- if (bank->base != 0x20000000)
- {
- WARNING("overriding flash base address for STR75x device with 0x20000000");
- bank->base = 0x20000000;
- }
- }
- else
- {
- ERROR("unknown STR7x variant: '%s'", args[6]);
- free(str7x_info);
- return ERROR_FLASH_BANK_INVALID;
- }
-
- str7x_build_block_list(bank);
-
- str7x_info->write_algorithm = NULL;
-
- return ERROR_OK;
-}
-
-u32 str7x_status(struct flash_bank_s *bank)
-{
- target_t *target = bank->target;
- u32 retval;
-
- target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
-
- return retval;
-}
-
-u32 str7x_result(struct flash_bank_s *bank)
-{
- target_t *target = bank->target;
- u32 retval;
-
- target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
-
- return retval;
-}
-
-int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
-{
- target_t *target = bank->target;
- u8 *buffer;
- int i;
- int nBytes;
-
- if ((first < 0) || (last > bank->num_sectors))
- return ERROR_FLASH_SECTOR_INVALID;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- buffer = malloc(256);
-
- for (i = first; i <= last; i++)
- {
- bank->sectors[i].is_erased = 1;
-
- target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
-
- for (nBytes = 0; nBytes < 256; nBytes++)
- {
- if (buffer[nBytes] != 0xFF)
- {
- bank->sectors[i].is_erased = 0;
- break;
- }
- }
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int str7x_protect_check(struct flash_bank_s *bank)
-{
- str7x_flash_bank_t *str7x_info = bank->driver_priv;
- target_t *target = bank->target;
-
- int i;
- u32 retval;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &retval);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (retval & str7x_info->sector_bits[i])
- bank->sectors[i].is_protected = 0;
- else
- bank->sectors[i].is_protected = 1;
- }
-
- return ERROR_OK;
-}
-
-int str7x_erase(struct flash_bank_s *bank, int first, int last)
-{
- str7x_flash_bank_t *str7x_info = bank->driver_priv;
- target_t *target = bank->target;
-
- int i;
- u32 cmd;
- u32 retval;
- u32 b0_sectors = 0, b1_sectors = 0;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- for (i = first; i <= last; i++)
- {
- if (str7x_info->sector_bank[i] == 0)
- b0_sectors |= str7x_info->sector_bits[i];
- else if (str7x_info->sector_bank[i] == 1)
- b1_sectors |= str7x_info->sector_bits[i];
- else
- ERROR("BUG: str7x_info->sector_bank[i] neither 0 nor 1 (%i)", str7x_info->sector_bank[i]);
- }
-
- if (b0_sectors)
- {
- DEBUG("b0_sectors: 0x%x", b0_sectors);
-
- /* clear FLASH_ER register */
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
- cmd = FLASH_SER;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- cmd = b0_sectors;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
-
- cmd = FLASH_SER|FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){
- usleep(1000);
- }
-
- retval = str7x_result(bank);
-
- if (retval)
- {
- ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
-
- if (b1_sectors)
- {
- DEBUG("b1_sectors: 0x%x", b1_sectors);
-
- /* clear FLASH_ER register */
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
- cmd = FLASH_SER;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- cmd = b1_sectors;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
-
- cmd = FLASH_SER|FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){
- usleep(1000);
- }
-
- retval = str7x_result(bank);
-
- if (retval)
- {
- ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
-
- for (i = first; i <= last; i++)
- bank->sectors[i].is_erased = 1;
-
- return ERROR_OK;
-}
-
-int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- str7x_flash_bank_t *str7x_info = bank->driver_priv;
- target_t *target = bank->target;
- int i;
- u32 cmd;
- u32 retval;
- u32 protect_blocks;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- protect_blocks = 0xFFFFFFFF;
-
- if (set)
- {
- for (i = first; i <= last; i++)
- protect_blocks &= ~(str7x_info->sector_bits[i]);
- }
-
- /* clear FLASH_ER register */
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
- cmd = FLASH_SPR;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
-
- cmd = protect_blocks;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
-
- cmd = FLASH_SPR|FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){
- usleep(1000);
- }
-
- retval = str7x_result(bank);
-
- DEBUG("retval: 0x%8.8x", retval);
-
- if (retval & FLASH_ERER)
- return ERROR_FLASH_SECTOR_NOT_ERASED;
- else if (retval & FLASH_WPF)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- str7x_flash_bank_t *str7x_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 buffer_size = 8192;
- working_area_t *source;
- u32 address = bank->base + offset;
- reg_param_t reg_params[6];
- armv4_5_algorithm_t armv4_5_info;
- int retval = ERROR_OK;
-
- u32 str7x_flash_write_code[] = {
- /* write: */
- 0xe3a04201, /* mov r4, #0x10000000 */
- 0xe5824000, /* str r4, [r2, #0x0] */
- 0xe5821010, /* str r1, [r2, #0x10] */
- 0xe4904004, /* ldr r4, [r0], #4 */
- 0xe5824008, /* str r4, [r2, #0x8] */
- 0xe4904004, /* ldr r4, [r0], #4 */
- 0xe582400c, /* str r4, [r2, #0xc] */
- 0xe3a04209, /* mov r4, #0x90000000 */
- 0xe5824000, /* str r4, [r2, #0x0] */
- /* busy: */
- 0xe5924000, /* ldr r4, [r2, #0x0] */
- 0xe1140005, /* tst r4, r5 */
- 0x1afffffc, /* bne busy */
- 0xe5924014, /* ldr r4, [r2, #0x14] */
- 0xe31400ff, /* tst r4, #0xff */
- 0x03140c01, /* tsteq r4, #0x100 */
- 0x1a000002, /* bne exit */
- 0xe2811008, /* add r1, r1, #0x8 */
- 0xe2533001, /* subs r3, r3, #1 */
- 0x1affffec, /* bne write */
- /* exit: */
- 0xeafffffe, /* b exit */
- };
-
- /* flash write code */
- if (target_alloc_working_area(target, 4 * 20, &str7x_info->write_algorithm) != ERROR_OK)
- {
- WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- };
-
- target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (u8*)str7x_flash_write_code);
-
- /* memory buffer */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
- {
- buffer_size /= 2;
- if (buffer_size <= 256)
- {
- /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
- if (str7x_info->write_algorithm)
- target_free_working_area(target, str7x_info->write_algorithm);
-
- WARNING("no large enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- }
-
- armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
- armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
- armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
- init_reg_param(®_params[4], "r4", 32, PARAM_IN);
- init_reg_param(®_params[5], "r5", 32, PARAM_OUT);
-
- while (count > 0)
- {
- u32 thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
-
- target_write_buffer(target, source->address, thisrun_count * 8, buffer);
-
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- buf_set_u32(reg_params[1].value, 0, 32, address);
- buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
- buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
- buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
-
- if ((retval = target->type->run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
- {
- ERROR("error executing str7x flash write algorithm");
- break;
- }
-
- if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
- {
- retval = ERROR_FLASH_OPERATION_FAILED;
- break;
- }
-
- buffer += thisrun_count * 8;
- address += thisrun_count * 8;
- count -= thisrun_count;
- }
-
- target_free_working_area(target, source);
- target_free_working_area(target, str7x_info->write_algorithm);
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_params[4]);
- destroy_reg_param(®_params[5]);
-
- return retval;
-}
-
-int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- target_t *target = bank->target;
- str7x_flash_bank_t *str7x_info = bank->driver_priv;
- u32 dwords_remaining = (count / 8);
- u32 bytes_remaining = (count & 0x00000007);
- u32 address = bank->base + offset;
- u32 bytes_written = 0;
- u32 cmd;
- u32 retval;
- u32 check_address = offset;
- int i;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (offset & 0x7)
- {
- WARNING("offset 0x%x breaks required 8-byte alignment", offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 sec_start = bank->sectors[i].offset;
- u32 sec_end = sec_start + bank->sectors[i].size;
-
- /* check if destination falls within the current sector */
- if ((check_address >= sec_start) && (check_address < sec_end))
- {
- /* check if destination ends in the current sector */
- if (offset + count < sec_end)
- check_address = offset + count;
- else
- check_address = sec_end;
- }
- }
-
- if (check_address != offset + count)
- return ERROR_FLASH_DST_OUT_OF_BANK;
-
- /* clear FLASH_ER register */
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
-
- /* multiple dwords (8-byte) to be programmed? */
- if (dwords_remaining > 0)
- {
- /* try using a block write */
- if ((retval = str7x_write_block(bank, buffer, offset, dwords_remaining)) != ERROR_OK)
- {
- if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- /* if block write failed (no sufficient working area),
- * we use normal (slow) single dword accesses */
- WARNING("couldn't use block writes, falling back to single memory accesses");
- }
- else if (retval == ERROR_FLASH_OPERATION_FAILED)
- {
- /* if an error occured, we examine the reason, and quit */
- retval = str7x_result(bank);
-
- ERROR("flash writing failed with error code: 0x%x", retval);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
- else
- {
- buffer += dwords_remaining * 8;
- address += dwords_remaining * 8;
- dwords_remaining = 0;
- }
- }
-
- while (dwords_remaining > 0)
- {
- // command
- cmd = FLASH_DWPG;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- // address
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
-
- // data word 1
- target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
- bytes_written += 4;
-
- // data word 2
- target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
- bytes_written += 4;
-
- /* start programming cycle */
- cmd = FLASH_DWPG | FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
- {
- usleep(1000);
- }
-
- retval = str7x_result(bank);
-
- if (retval & FLASH_PGER)
- return ERROR_FLASH_OPERATION_FAILED;
- else if (retval & FLASH_WPF)
- return ERROR_FLASH_OPERATION_FAILED;
-
- dwords_remaining--;
- address += 8;
- }
-
- if (bytes_remaining)
- {
- u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- int i = 0;
-
- while(bytes_remaining > 0)
- {
- last_dword[i++] = *(buffer + bytes_written);
- bytes_remaining--;
- bytes_written++;
- }
-
- // command
- cmd = FLASH_DWPG;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- // address
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
-
- // data word 1
- target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
- bytes_written += 4;
-
- // data word 2
- target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
- bytes_written += 4;
-
- /* start programming cycle */
- cmd = FLASH_DWPG | FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
-
- while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
- {
- usleep(1000);
- }
-
- retval = str7x_result(bank);
-
- if (retval & FLASH_PGER)
- return ERROR_FLASH_OPERATION_FAILED;
- else if (retval & FLASH_WPF)
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int str7x_probe(struct flash_bank_s *bank)
-{
- return ERROR_OK;
-}
-
-int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- return ERROR_OK;
-}
-
-int str7x_erase_check(struct flash_bank_s *bank)
-{
- return str7x_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- snprintf(buf, buf_size, "str7x flash driver info" );
- return ERROR_OK;
-}
-
-int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- target_t *target = NULL;
- str7x_flash_bank_t *str7x_info = NULL;
-
- u32 flash_cmd;
- u32 retval;
- u16 ProtectionLevel = 0;
- u16 ProtectionRegs;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str7x disable_jtag <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "str7x disable_jtag <bank> ok");
- return ERROR_OK;
- }
-
- str7x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* first we get protection status */
- target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &retval);
-
- if (!(retval & str7x_info->disable_bit))
- {
- ProtectionLevel = 1;
- }
-
- target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &retval);
- ProtectionRegs = ~(retval >> 16);
-
- while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))
- {
- ProtectionRegs >>= 1;
- ProtectionLevel++;
- }
-
- if (ProtectionLevel == 0)
- {
- flash_cmd = FLASH_SPR;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);
- flash_cmd = FLASH_SPR | FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
- }
- else
- {
- flash_cmd = FLASH_SPR;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1<<(15+ProtectionLevel)));
- flash_cmd = FLASH_SPR | FLASH_WMS;
- target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
- }
-
- return ERROR_OK;
-}
-
+/***************************************************************************\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 "replacements.h"\r
+\r
+#include "str7x.h"\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
+#include <unistd.h>\r
+\r
+str7x_mem_layout_t mem_layout[] = {\r
+ {0x00000000, 0x02000, 0x01},\r
+ {0x00002000, 0x02000, 0x02},\r
+ {0x00004000, 0x02000, 0x04},\r
+ {0x00006000, 0x02000, 0x08},\r
+ {0x00008000, 0x08000, 0x10},\r
+ {0x00010000, 0x10000, 0x20},\r
+ {0x00020000, 0x10000, 0x40},\r
+ {0x00030000, 0x10000, 0x80},\r
+ {0x000C0000, 0x02000, 0x10000},\r
+ {0x000C2000, 0x02000, 0x20000},\r
+};\r
+\r
+int str7x_register_commands(struct command_context_s *cmd_ctx);\r
+int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
+int str7x_erase(struct flash_bank_s *bank, int first, int last);\r
+int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);\r
+int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
+int str7x_probe(struct flash_bank_s *bank);\r
+int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str7x_protect_check(struct flash_bank_s *bank);\r
+int str7x_erase_check(struct flash_bank_s *bank);\r
+int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
+\r
+int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+flash_driver_t str7x_flash =\r
+{\r
+ .name = "str7x",\r
+ .register_commands = str7x_register_commands,\r
+ .flash_bank_command = str7x_flash_bank_command,\r
+ .erase = str7x_erase,\r
+ .protect = str7x_protect,\r
+ .write = str7x_write,\r
+ .probe = str7x_probe,\r
+ .auto_probe = str7x_probe,\r
+ .erase_check = str7x_erase_check,\r
+ .protect_check = str7x_protect_check,\r
+ .info = str7x_info\r
+};\r
+\r
+int str7x_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ command_t *str7x_cmd = register_command(cmd_ctx, NULL, "str7x", NULL, COMMAND_ANY, NULL);\r
+ \r
+ register_command(cmd_ctx, str7x_cmd, "disable_jtag", str7x_handle_disable_jtag_command, COMMAND_EXEC,\r
+ "disable jtag access");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)\r
+{\r
+ return (bank->base | reg);\r
+}\r
+\r
+int str7x_build_block_list(struct flash_bank_s *bank)\r
+{\r
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;\r
+\r
+ int i;\r
+ int num_sectors = 0, b0_sectors = 0, b1_sectors = 0;\r
+ \r
+ switch (bank->size)\r
+ {\r
+ case 16 * 1024:\r
+ b0_sectors = 2;\r
+ break;\r
+ case 64 * 1024:\r
+ b0_sectors = 5;\r
+ break;\r
+ case 128 * 1024:\r
+ b0_sectors = 6;\r
+ break;\r
+ case 256 * 1024:\r
+ b0_sectors = 8;\r
+ break;\r
+ default:\r
+ ERROR("BUG: unknown bank->size encountered");\r
+ exit(-1);\r
+ }\r
+ \r
+ if( str7x_info->bank1 == 1 )\r
+ {\r
+ b1_sectors += 2;\r
+ }\r
+ \r
+ num_sectors = b0_sectors + b1_sectors;\r
+ \r
+ bank->num_sectors = num_sectors;\r
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);\r
+ str7x_info->sector_bits = malloc(sizeof(u32) * num_sectors);\r
+ str7x_info->sector_bank = malloc(sizeof(u32) * num_sectors);\r
+ \r
+ num_sectors = 0;\r
+ \r
+ for (i = 0; i < b0_sectors; i++)\r
+ {\r
+ bank->sectors[num_sectors].offset = mem_layout[i].sector_start;\r
+ bank->sectors[num_sectors].size = mem_layout[i].sector_size;\r
+ bank->sectors[num_sectors].is_erased = -1;\r
+ bank->sectors[num_sectors].is_protected = 1;\r
+ str7x_info->sector_bank[num_sectors] = 0;\r
+ str7x_info->sector_bits[num_sectors++] = mem_layout[i].sector_bit;\r
+ }\r
+ \r
+ if (b1_sectors)\r
+ {\r
+ for (i = 8; i < 10; i++)\r
+ {\r
+ bank->sectors[num_sectors].offset = mem_layout[i].sector_start;\r
+ bank->sectors[num_sectors].size = mem_layout[i].sector_size;\r
+ bank->sectors[num_sectors].is_erased = -1;\r
+ bank->sectors[num_sectors].is_protected = 1;\r
+ str7x_info->sector_bank[num_sectors] = 1;\r
+ str7x_info->sector_bits[num_sectors++] = mem_layout[i].sector_bit;\r
+ }\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>\r
+ */\r
+int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
+{\r
+ str7x_flash_bank_t *str7x_info;\r
+ \r
+ if (argc < 7)\r
+ {\r
+ WARNING("incomplete flash_bank str7x configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ str7x_info = malloc(sizeof(str7x_flash_bank_t));\r
+ bank->driver_priv = str7x_info;\r
+ \r
+ /* set default bits for str71x flash */\r
+ str7x_info->bank1 = 1;\r
+ str7x_info->busy_bits = (FLASH_LOCK|FLASH_BSYA1|FLASH_BSYA0);\r
+ str7x_info->disable_bit = (1<<1);\r
+ \r
+ if (strcmp(args[6], "STR71x") == 0)\r
+ {\r
+ if (bank->base != 0x40000000)\r
+ {\r
+ WARNING("overriding flash base address for STR71x device with 0x40000000");\r
+ bank->base = 0x40000000;\r
+ }\r
+ }\r
+ else if (strcmp(args[6], "STR73x") == 0)\r
+ {\r
+ str7x_info->bank1 = 0;\r
+ str7x_info->busy_bits = (FLASH_LOCK|FLASH_BSYA0);\r
+ \r
+ if (bank->base != 0x80000000)\r
+ {\r
+ WARNING("overriding flash base address for STR73x device with 0x80000000");\r
+ bank->base = 0x80000000;\r
+ }\r
+ }\r
+ else if (strcmp(args[6], "STR75x") == 0)\r
+ {\r
+ str7x_info->disable_bit = (1<<0);\r
+ \r
+ if (bank->base != 0x20000000)\r
+ {\r
+ WARNING("overriding flash base address for STR75x device with 0x20000000");\r
+ bank->base = 0x20000000;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ERROR("unknown STR7x variant: '%s'", args[6]);\r
+ free(str7x_info);\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+\r
+ str7x_build_block_list(bank);\r
+ \r
+ str7x_info->write_algorithm = NULL;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+u32 str7x_status(struct flash_bank_s *bank)\r
+{\r
+ target_t *target = bank->target;\r
+ u32 retval;\r
+\r
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);\r
+\r
+ return retval;\r
+}\r
+\r
+u32 str7x_result(struct flash_bank_s *bank)\r
+{\r
+ target_t *target = bank->target;\r
+ u32 retval;\r
+\r
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);\r
+ \r
+ return retval;\r
+}\r
+\r
+int str7x_blank_check(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ target_t *target = bank->target;\r
+ u8 *buffer;\r
+ int i;\r
+ int nBytes;\r
+ \r
+ if ((first < 0) || (last > bank->num_sectors))\r
+ return ERROR_FLASH_SECTOR_INVALID;\r
+\r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ buffer = malloc(256);\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ bank->sectors[i].is_erased = 1;\r
+\r
+ target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);\r
+ \r
+ for (nBytes = 0; nBytes < 256; nBytes++)\r
+ {\r
+ if (buffer[nBytes] != 0xFF)\r
+ {\r
+ bank->sectors[i].is_erased = 0;\r
+ break;\r
+ }\r
+ } \r
+ }\r
+ \r
+ free(buffer);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_protect_check(struct flash_bank_s *bank)\r
+{\r
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ \r
+ int i;\r
+ u32 retval;\r
+\r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+\r
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &retval);\r
+\r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ if (retval & str7x_info->sector_bits[i])\r
+ bank->sectors[i].is_protected = 0;\r
+ else\r
+ bank->sectors[i].is_protected = 1;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_erase(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ \r
+ int i;\r
+ u32 cmd;\r
+ u32 retval;\r
+ u32 b0_sectors = 0, b1_sectors = 0;\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ if (str7x_info->sector_bank[i] == 0)\r
+ b0_sectors |= str7x_info->sector_bits[i];\r
+ else if (str7x_info->sector_bank[i] == 1)\r
+ b1_sectors |= str7x_info->sector_bits[i];\r
+ else\r
+ ERROR("BUG: str7x_info->sector_bank[i] neither 0 nor 1 (%i)", str7x_info->sector_bank[i]);\r
+ }\r
+ \r
+ if (b0_sectors)\r
+ {\r
+ DEBUG("b0_sectors: 0x%x", b0_sectors);\r
+ \r
+ /* clear FLASH_ER register */ \r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);\r
+ \r
+ cmd = FLASH_SER;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ cmd = b0_sectors;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);\r
+ \r
+ cmd = FLASH_SER|FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){\r
+ usleep(1000);\r
+ }\r
+ \r
+ retval = str7x_result(bank);\r
+ \r
+ if (retval)\r
+ {\r
+ ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ if (b1_sectors)\r
+ {\r
+ DEBUG("b1_sectors: 0x%x", b1_sectors);\r
+ \r
+ /* clear FLASH_ER register */ \r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);\r
+ \r
+ cmd = FLASH_SER;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ cmd = b1_sectors;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);\r
+ \r
+ cmd = FLASH_SER|FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){\r
+ usleep(1000);\r
+ }\r
+ \r
+ retval = str7x_result(bank);\r
+ \r
+ if (retval)\r
+ {\r
+ ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ for (i = first; i <= last; i++)\r
+ bank->sectors[i].is_erased = 1;\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)\r
+{\r
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ int i;\r
+ u32 cmd;\r
+ u32 retval;\r
+ u32 protect_blocks;\r
+ \r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ protect_blocks = 0xFFFFFFFF;\r
+\r
+ if (set)\r
+ {\r
+ for (i = first; i <= last; i++)\r
+ protect_blocks &= ~(str7x_info->sector_bits[i]);\r
+ }\r
+ \r
+ /* clear FLASH_ER register */ \r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);\r
+\r
+ cmd = FLASH_SPR;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);\r
+ \r
+ cmd = protect_blocks;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);\r
+ \r
+ cmd = FLASH_SPR|FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){\r
+ usleep(1000);\r
+ }\r
+ \r
+ retval = str7x_result(bank);\r
+ \r
+ DEBUG("retval: 0x%8.8x", retval);\r
+ \r
+ if (retval & FLASH_ERER)\r
+ return ERROR_FLASH_SECTOR_NOT_ERASED;\r
+ else if (retval & FLASH_WPF)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 buffer_size = 8192;\r
+ working_area_t *source;\r
+ u32 address = bank->base + offset;\r
+ reg_param_t reg_params[6];\r
+ armv4_5_algorithm_t armv4_5_info;\r
+ int retval = ERROR_OK;\r
+ \r
+ u32 str7x_flash_write_code[] = {\r
+ /* write: */\r
+ 0xe3a04201, /* mov r4, #0x10000000 */\r
+ 0xe5824000, /* str r4, [r2, #0x0] */\r
+ 0xe5821010, /* str r1, [r2, #0x10] */\r
+ 0xe4904004, /* ldr r4, [r0], #4 */\r
+ 0xe5824008, /* str r4, [r2, #0x8] */\r
+ 0xe4904004, /* ldr r4, [r0], #4 */\r
+ 0xe582400c, /* str r4, [r2, #0xc] */\r
+ 0xe3a04209, /* mov r4, #0x90000000 */\r
+ 0xe5824000, /* str r4, [r2, #0x0] */\r
+ /* busy: */\r
+ 0xe5924000, /* ldr r4, [r2, #0x0] */\r
+ 0xe1140005, /* tst r4, r5 */\r
+ 0x1afffffc, /* bne busy */\r
+ 0xe5924014, /* ldr r4, [r2, #0x14] */\r
+ 0xe31400ff, /* tst r4, #0xff */\r
+ 0x03140c01, /* tsteq r4, #0x100 */\r
+ 0x1a000002, /* bne exit */\r
+ 0xe2811008, /* add r1, r1, #0x8 */\r
+ 0xe2533001, /* subs r3, r3, #1 */\r
+ 0x1affffec, /* bne write */\r
+ /* exit: */\r
+ 0xeafffffe, /* b exit */\r
+ };\r
+ \r
+ /* flash write code */\r
+ if (target_alloc_working_area(target, 4 * 20, &str7x_info->write_algorithm) != ERROR_OK)\r
+ {\r
+ WARNING("no working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ };\r
+ \r
+ target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (u8*)str7x_flash_write_code);\r
+\r
+ /* memory buffer */\r
+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)\r
+ {\r
+ buffer_size /= 2;\r
+ if (buffer_size <= 256)\r
+ {\r
+ /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */\r
+ if (str7x_info->write_algorithm)\r
+ target_free_working_area(target, str7x_info->write_algorithm);\r
+ \r
+ WARNING("no large enough working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ }\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
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);\r
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);\r
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);\r
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);\r
+ init_reg_param(®_params[4], "r4", 32, PARAM_IN);\r
+ init_reg_param(®_params[5], "r5", 32, PARAM_OUT);\r
+ \r
+ while (count > 0)\r
+ {\r
+ u32 thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;\r
+ \r
+ target_write_buffer(target, source->address, thisrun_count * 8, buffer);\r
+ \r
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);\r
+ buf_set_u32(reg_params[1].value, 0, 32, address);\r
+ buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));\r
+ buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);\r
+ buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);\r
+ \r
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)\r
+ {\r
+ ERROR("error executing str7x flash write algorithm");\r
+ break;\r
+ }\r
+ \r
+ if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)\r
+ {\r
+ retval = ERROR_FLASH_OPERATION_FAILED;\r
+ break;\r
+ }\r
+ \r
+ buffer += thisrun_count * 8;\r
+ address += thisrun_count * 8;\r
+ count -= thisrun_count;\r
+ }\r
+ \r
+ target_free_working_area(target, source);\r
+ target_free_working_area(target, str7x_info->write_algorithm);\r
+ \r
+ destroy_reg_param(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ destroy_reg_param(®_params[3]);\r
+ destroy_reg_param(®_params[4]);\r
+ destroy_reg_param(®_params[5]);\r
+ \r
+ return retval;\r
+}\r
+\r
+int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ target_t *target = bank->target;\r
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;\r
+ u32 dwords_remaining = (count / 8);\r
+ u32 bytes_remaining = (count & 0x00000007);\r
+ u32 address = bank->base + offset;\r
+ u32 bytes_written = 0;\r
+ u32 cmd;\r
+ u32 retval;\r
+ u32 check_address = offset;\r
+ int i;\r
+ \r
+ if (offset & 0x7)\r
+ {\r
+ WARNING("offset 0x%x breaks required 8-byte alignment", offset);\r
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
+ }\r
+ \r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ u32 sec_start = bank->sectors[i].offset;\r
+ u32 sec_end = sec_start + bank->sectors[i].size;\r
+ \r
+ /* check if destination falls within the current sector */\r
+ if ((check_address >= sec_start) && (check_address < sec_end))\r
+ {\r
+ /* check if destination ends in the current sector */\r
+ if (offset + count < sec_end)\r
+ check_address = offset + count;\r
+ else\r
+ check_address = sec_end;\r
+ }\r
+ }\r
+ \r
+ if (check_address != offset + count)\r
+ return ERROR_FLASH_DST_OUT_OF_BANK;\r
+ \r
+ /* clear FLASH_ER register */ \r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);\r
+\r
+ /* multiple dwords (8-byte) to be programmed? */\r
+ if (dwords_remaining > 0) \r
+ {\r
+ /* try using a block write */\r
+ if ((retval = str7x_write_block(bank, buffer, offset, dwords_remaining)) != ERROR_OK)\r
+ {\r
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)\r
+ {\r
+ /* if block write failed (no sufficient working area),\r
+ * we use normal (slow) single dword accesses */ \r
+ WARNING("couldn't use block writes, falling back to single memory accesses");\r
+ }\r
+ else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
+ {\r
+ /* if an error occured, we examine the reason, and quit */\r
+ retval = str7x_result(bank);\r
+ \r
+ ERROR("flash writing failed with error code: 0x%x", retval);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ buffer += dwords_remaining * 8;\r
+ address += dwords_remaining * 8;\r
+ dwords_remaining = 0;\r
+ }\r
+ }\r
+\r
+ while (dwords_remaining > 0)\r
+ {\r
+ // command\r
+ cmd = FLASH_DWPG;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ // address\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);\r
+ \r
+ // data word 1\r
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);\r
+ bytes_written += 4;\r
+ \r
+ // data word 2\r
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);\r
+ bytes_written += 4;\r
+ \r
+ /* start programming cycle */\r
+ cmd = FLASH_DWPG | FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ while (((retval = str7x_status(bank)) & str7x_info->busy_bits))\r
+ {\r
+ usleep(1000);\r
+ }\r
+ \r
+ retval = str7x_result(bank);\r
+ \r
+ if (retval & FLASH_PGER)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ else if (retval & FLASH_WPF)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+\r
+ dwords_remaining--;\r
+ address += 8;\r
+ }\r
+ \r
+ if (bytes_remaining)\r
+ {\r
+ u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
+ int i = 0;\r
+ \r
+ while(bytes_remaining > 0)\r
+ {\r
+ last_dword[i++] = *(buffer + bytes_written); \r
+ bytes_remaining--;\r
+ bytes_written++;\r
+ }\r
+ \r
+ // command\r
+ cmd = FLASH_DWPG;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ // address\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);\r
+ \r
+ // data word 1\r
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);\r
+ bytes_written += 4;\r
+ \r
+ // data word 2\r
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);\r
+ bytes_written += 4;\r
+ \r
+ /* start programming cycle */\r
+ cmd = FLASH_DWPG | FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);\r
+ \r
+ while (((retval = str7x_status(bank)) & str7x_info->busy_bits))\r
+ {\r
+ usleep(1000);\r
+ }\r
+ \r
+ retval = str7x_result(bank);\r
+ \r
+ if (retval & FLASH_PGER)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ else if (retval & FLASH_WPF)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_probe(struct flash_bank_s *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_erase_check(struct flash_bank_s *bank)\r
+{\r
+ return str7x_blank_check(bank, 0, bank->num_sectors - 1);\r
+}\r
+\r
+int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
+{\r
+ snprintf(buf, buf_size, "str7x flash driver info" );\r
+ return ERROR_OK;\r
+}\r
+\r
+int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ target_t *target = NULL;\r
+ str7x_flash_bank_t *str7x_info = NULL;\r
+ \r
+ u32 flash_cmd;\r
+ u32 retval;\r
+ u16 ProtectionLevel = 0;\r
+ u16 ProtectionRegs;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str7x disable_jtag <bank>");\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, "str7x disable_jtag <bank> ok");\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ str7x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ /* first we get protection status */\r
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &retval);\r
+\r
+ if (!(retval & str7x_info->disable_bit))\r
+ {\r
+ ProtectionLevel = 1;\r
+ }\r
+ \r
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &retval);\r
+ ProtectionRegs = ~(retval >> 16);\r
+\r
+ while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))\r
+ {\r
+ ProtectionRegs >>= 1;\r
+ ProtectionLevel++;\r
+ }\r
+ \r
+ if (ProtectionLevel == 0)\r
+ {\r
+ flash_cmd = FLASH_SPR;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);\r
+ flash_cmd = FLASH_SPR | FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);\r
+ }\r
+ else\r
+ {\r
+ flash_cmd = FLASH_SPR;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1<<(15+ProtectionLevel)));\r
+ flash_cmd = FLASH_SPR | FLASH_WMS;\r
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "str9x.h"
-#include "flash.h"
-#include "target.h"
-#include "log.h"
-#include "armv4_5.h"
-#include "arm966e.h"
-#include "algorithm.h"
-#include "binarybuffer.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-str9x_mem_layout_t mem_layout_str9bank0[] = {
- {0x00000000, 0x10000, 0x01},
- {0x00010000, 0x10000, 0x02},
- {0x00020000, 0x10000, 0x04},
- {0x00030000, 0x10000, 0x08},
- {0x00040000, 0x10000, 0x10},
- {0x00050000, 0x10000, 0x20},
- {0x00060000, 0x10000, 0x40},
- {0x00070000, 0x10000, 0x80},
-};
-
-str9x_mem_layout_t mem_layout_str9bank1[] = {
- {0x00000000, 0x02000, 0x100},
- {0x00002000, 0x02000, 0x200},
- {0x00004000, 0x02000, 0x400},
- {0x00006000, 0x02000, 0x800}
-};
-
-static u32 bank1start = 0x00080000;
-
-int str9x_register_commands(struct command_context_s *cmd_ctx);
-int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int str9x_erase(struct flash_bank_s *bank, int first, int last);
-int str9x_protect(struct flash_bank_s *bank, int set, int first, int last);
-int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int str9x_probe(struct flash_bank_s *bank);
-int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9x_protect_check(struct flash_bank_s *bank);
-int str9x_erase_check(struct flash_bank_s *bank);
-int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-flash_driver_t str9x_flash =
-{
- .name = "str9x",
- .register_commands = str9x_register_commands,
- .flash_bank_command = str9x_flash_bank_command,
- .erase = str9x_erase,
- .protect = str9x_protect,
- .write = str9x_write,
- .probe = str9x_probe,
- .auto_probe = str9x_probe,
- .erase_check = str9x_erase_check,
- .protect_check = str9x_protect_check,
- .info = str9x_info
-};
-
-int str9x_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *str9x_cmd = register_command(cmd_ctx, NULL, "str9x", NULL, COMMAND_ANY, NULL);
-
- register_command(cmd_ctx, str9x_cmd, "flash_config", str9x_handle_flash_config_command, COMMAND_EXEC,
- "configure str9 flash controller");
-
- return ERROR_OK;
-}
-
-int str9x_build_block_list(struct flash_bank_s *bank)
-{
- str9x_flash_bank_t *str9x_info = bank->driver_priv;
-
- int i;
- int num_sectors = 0;
- int b0_sectors = 0, b1_sectors = 0;
-
- switch (bank->size)
- {
- case (256 * 1024):
- b0_sectors = 4;
- break;
- case (512 * 1024):
- b0_sectors = 8;
- break;
- case (32 * 1024):
- b1_sectors = 4;
- bank1start = bank->base;
- break;
- default:
- ERROR("BUG: unknown bank->size encountered");
- exit(-1);
- }
-
- num_sectors = b0_sectors + b1_sectors;
-
- bank->num_sectors = num_sectors;
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
- str9x_info->sector_bits = malloc(sizeof(u32) * num_sectors);
-
- num_sectors = 0;
-
- for (i = 0; i < b0_sectors; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout_str9bank0[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout_str9bank0[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str9x_info->sector_bits[num_sectors++] = mem_layout_str9bank0[i].sector_bit;
- }
-
- for (i = 0; i < b1_sectors; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout_str9bank1[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout_str9bank1[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str9x_info->sector_bits[num_sectors++] = mem_layout_str9bank1[i].sector_bit;
- }
-
- return ERROR_OK;
-}
-
-/* flash bank str9x <base> <size> 0 0 <target#>
- */
-int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- str9x_flash_bank_t *str9x_info;
-
- if (argc < 6)
- {
- WARNING("incomplete flash_bank str9x configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- str9x_info = malloc(sizeof(str9x_flash_bank_t));
- bank->driver_priv = str9x_info;
-
- str9x_build_block_list(bank);
-
- str9x_info->write_algorithm = NULL;
-
- return ERROR_OK;
-}
-
-int str9x_blank_check(struct flash_bank_s *bank, int first, int last)
-{
- target_t *target = bank->target;
- u8 *buffer;
- int i;
- int nBytes;
-
- if ((first < 0) || (last > bank->num_sectors))
- return ERROR_FLASH_SECTOR_INVALID;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- buffer = malloc(256);
-
- for (i = first; i <= last; i++)
- {
- bank->sectors[i].is_erased = 1;
-
- target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
-
- for (nBytes = 0; nBytes < 256; nBytes++)
- {
- if (buffer[nBytes] != 0xFF)
- {
- bank->sectors[i].is_erased = 0;
- break;
- }
- }
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int str9x_protect_check(struct flash_bank_s *bank)
-{
- str9x_flash_bank_t *str9x_info = bank->driver_priv;
- target_t *target = bank->target;
-
- int i;
- u32 adr;
- u16 status;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* read level one protection */
-
- adr = bank1start + 0x10;
-
- target_write_u16(target, adr, 0x90);
- target_read_u16(target, adr, &status);
- target_write_u16(target, adr, 0xFF);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (status & str9x_info->sector_bits[i])
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
- }
-
- return ERROR_OK;
-}
-
-int str9x_erase(struct flash_bank_s *bank, int first, int last)
-{
- target_t *target = bank->target;
- int i;
- u32 adr;
- u8 status;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- for (i = first; i <= last; i++)
- {
- adr = bank->base + bank->sectors[i].offset;
-
- /* erase sectors */
- target_write_u16(target, adr, 0x20);
- target_write_u16(target, adr, 0xD0);
-
- /* get status */
- target_write_u16(target, adr, 0x70);
-
- while (1) {
- target_read_u8(target, adr, &status);
- if( status & 0x80 )
- break;
- usleep(1000);
- }
-
- /* clear status, also clear read array */
- target_write_u16(target, adr, 0x50);
-
- /* read array command */
- target_write_u16(target, adr, 0xFF);
-
- if( status & 0x22 )
- {
- ERROR("error erasing flash bank, status: 0x%x", status);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
-
- for (i = first; i <= last; i++)
- bank->sectors[i].is_erased = 1;
-
- return ERROR_OK;
-}
-
-int str9x_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- target_t *target = bank->target;
- int i;
- u32 adr;
- u8 status;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- for (i = first; i <= last; i++)
- {
- /* Level One Protection */
-
- adr = bank->base + bank->sectors[i].offset;
-
- target_write_u16(target, adr, 0x60);
- if( set )
- target_write_u16(target, adr, 0x01);
- else
- target_write_u16(target, adr, 0xD0);
-
- /* query status */
- target_read_u8(target, adr, &status);
- }
-
- return ERROR_OK;
-}
-
-int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- str9x_flash_bank_t *str9x_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 buffer_size = 8192;
- working_area_t *source;
- u32 address = bank->base + offset;
- reg_param_t reg_params[4];
- armv4_5_algorithm_t armv4_5_info;
- int retval;
-
- u32 str9x_flash_write_code[] = {
- /* write: */
- 0xe3c14003, /* bic r4, r1, #3 */
- 0xe3a03040, /* mov r3, #0x40 */
- 0xe1c430b0, /* strh r3, [r4, #0] */
- 0xe0d030b2, /* ldrh r3, [r0], #2 */
- 0xe0c130b2, /* strh r3, [r1], #2 */
- 0xe3a03070, /* mov r3, #0x70 */
- 0xe1c430b0, /* strh r3, [r4, #0] */
- /* busy: */
- 0xe5d43000, /* ldrb r3, [r4, #0] */
- 0xe3130080, /* tst r3, #0x80 */
- 0x0afffffc, /* beq busy */
- 0xe3a05050, /* mov r5, #0x50 */
- 0xe1c450b0, /* strh r5, [r4, #0] */
- 0xe3a050ff, /* mov r5, #0xFF */
- 0xe1c450b0, /* strh r5, [r4, #0] */
- 0xe3130012, /* tst r3, #0x12 */
- 0x1a000001, /* bne exit */
- 0xe2522001, /* subs r2, r2, #1 */
- 0x1affffed, /* bne write */
- /* exit: */
- 0xeafffffe, /* b exit */
- };
-
- /* flash write code */
- if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
- {
- WARNING("no working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- };
-
- target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (u8*)str9x_flash_write_code);
-
- /* memory buffer */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
- {
- buffer_size /= 2;
- if (buffer_size <= 256)
- {
- /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
- if (str9x_info->write_algorithm)
- target_free_working_area(target, str9x_info->write_algorithm);
-
- WARNING("no large enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- }
-
- armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
- armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
- armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_IN);
-
- while (count > 0)
- {
- u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
-
- target_write_buffer(target, source->address, thisrun_count * 2, buffer);
-
- buf_set_u32(reg_params[0].value, 0, 32, source->address);
- buf_set_u32(reg_params[1].value, 0, 32, address);
- buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
-
- if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
- {
- target_free_working_area(target, source);
- target_free_working_area(target, str9x_info->write_algorithm);
- ERROR("error executing str9x flash write algorithm");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
- {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- buffer += thisrun_count * 2;
- address += thisrun_count * 2;
- count -= thisrun_count;
- }
-
- target_free_working_area(target, source);
- target_free_working_area(target, str9x_info->write_algorithm);
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
-
- return ERROR_OK;
-}
-
-int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- target_t *target = bank->target;
- u32 words_remaining = (count / 2);
- u32 bytes_remaining = (count & 0x00000001);
- u32 address = bank->base + offset;
- u32 bytes_written = 0;
- u8 status;
- u32 retval;
- u32 check_address = offset;
- u32 bank_adr;
- int i;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (offset & 0x1)
- {
- WARNING("offset 0x%x breaks required 2-byte alignment", offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 sec_start = bank->sectors[i].offset;
- u32 sec_end = sec_start + bank->sectors[i].size;
-
- /* check if destination falls within the current sector */
- if ((check_address >= sec_start) && (check_address < sec_end))
- {
- /* check if destination ends in the current sector */
- if (offset + count < sec_end)
- check_address = offset + count;
- else
- check_address = sec_end;
- }
- }
-
- if (check_address != offset + count)
- return ERROR_FLASH_DST_OUT_OF_BANK;
-
- /* multiple half words (2-byte) to be programmed? */
- if (words_remaining > 0)
- {
- /* try using a block write */
- if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
- {
- if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- /* if block write failed (no sufficient working area),
- * we use normal (slow) single dword accesses */
- WARNING("couldn't use block writes, falling back to single memory accesses");
- }
- else if (retval == ERROR_FLASH_OPERATION_FAILED)
- {
- ERROR("flash writing failed with error code: 0x%x", retval);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
- else
- {
- buffer += words_remaining * 2;
- address += words_remaining * 2;
- words_remaining = 0;
- }
- }
-
- while (words_remaining > 0)
- {
- bank_adr = address & ~0x03;
-
- /* write data command */
- target_write_u16(target, bank_adr, 0x40);
- target->type->write_memory(target, address, 2, 1, buffer + bytes_written);
-
- /* get status command */
- target_write_u16(target, bank_adr, 0x70);
-
- while (1) {
- target_read_u8(target, bank_adr, &status);
- if( status & 0x80 )
- break;
- usleep(1000);
- }
-
- /* clear status reg and read array */
- target_write_u16(target, bank_adr, 0x50);
- target_write_u16(target, bank_adr, 0xFF);
-
- if (status & 0x10)
- return ERROR_FLASH_OPERATION_FAILED;
- else if (status & 0x02)
- return ERROR_FLASH_OPERATION_FAILED;
-
- bytes_written += 2;
- words_remaining--;
- address += 2;
- }
-
- if (bytes_remaining)
- {
- u8 last_halfword[2] = {0xff, 0xff};
- int i = 0;
-
- while(bytes_remaining > 0)
- {
- last_halfword[i++] = *(buffer + bytes_written);
- bytes_remaining--;
- bytes_written++;
- }
-
- bank_adr = address & ~0x03;
-
- /* write data comamnd */
- target_write_u16(target, bank_adr, 0x40);
- target->type->write_memory(target, address, 2, 1, last_halfword);
-
- /* query status command */
- target_write_u16(target, bank_adr, 0x70);
-
- while (1) {
- target_read_u8(target, bank_adr, &status);
- if( status & 0x80 )
- break;
- usleep(1000);
- }
-
- /* clear status reg and read array */
- target_write_u16(target, bank_adr, 0x50);
- target_write_u16(target, bank_adr, 0xFF);
-
- if (status & 0x10)
- return ERROR_FLASH_OPERATION_FAILED;
- else if (status & 0x02)
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int str9x_probe(struct flash_bank_s *bank)
-{
- return ERROR_OK;
-}
-
-int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- return ERROR_OK;
-}
-
-int str9x_erase_check(struct flash_bank_s *bank)
-{
- return str9x_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- snprintf(buf, buf_size, "str9x flash driver info" );
- return ERROR_OK;
-}
-
-int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- str9x_flash_bank_t *str9x_info;
- flash_bank_t *bank;
- target_t *target = NULL;
-
- if (argc < 5)
- {
- command_print(cmd_ctx, "usage: str9x flash_config <bank> <bbsize> <nbsize> <bbstart> <nbstart>");
- 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;
- }
-
- str9x_info = bank->driver_priv;
-
- target = bank->target;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* config flash controller */
- target_write_u32(target, FLASH_BBSR, strtoul(args[1], NULL, 0));
- target_write_u32(target, FLASH_NBBSR, strtoul(args[2], NULL, 0));
- target_write_u32(target, FLASH_BBADR, (strtoul(args[3], NULL, 0) >> 2));
- target_write_u32(target, FLASH_NBBADR, (strtoul(args[4], NULL, 0) >> 2));
-
- /* set bit 18 instruction TCM order as per flash programming manual */
- arm966e_write_cp15(target, 62, 0x40000);
-
- /* enable flash bank 1 */
- target_write_u32(target, FLASH_CR, 0x18);
- return ERROR_OK;
-}
+/***************************************************************************\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 "replacements.h"\r
+\r
+#include "str9x.h"\r
+#include "flash.h"\r
+#include "target.h"\r
+#include "log.h"\r
+#include "armv4_5.h"\r
+#include "arm966e.h"\r
+#include "algorithm.h"\r
+#include "binarybuffer.h"\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+\r
+str9x_mem_layout_t mem_layout_str9bank0[] = {\r
+ {0x00000000, 0x10000, 0x01},\r
+ {0x00010000, 0x10000, 0x02},\r
+ {0x00020000, 0x10000, 0x04},\r
+ {0x00030000, 0x10000, 0x08},\r
+ {0x00040000, 0x10000, 0x10},\r
+ {0x00050000, 0x10000, 0x20},\r
+ {0x00060000, 0x10000, 0x40},\r
+ {0x00070000, 0x10000, 0x80},\r
+};\r
+\r
+str9x_mem_layout_t mem_layout_str9bank1[] = {\r
+ {0x00000000, 0x02000, 0x100},\r
+ {0x00002000, 0x02000, 0x200},\r
+ {0x00004000, 0x02000, 0x400},\r
+ {0x00006000, 0x02000, 0x800}\r
+};\r
+\r
+static u32 bank1start = 0x00080000;\r
+\r
+int str9x_register_commands(struct command_context_s *cmd_ctx);\r
+int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
+int str9x_erase(struct flash_bank_s *bank, int first, int last);\r
+int str9x_protect(struct flash_bank_s *bank, int set, int first, int last);\r
+int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
+int str9x_probe(struct flash_bank_s *bank);\r
+int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9x_protect_check(struct flash_bank_s *bank);\r
+int str9x_erase_check(struct flash_bank_s *bank);\r
+int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
+\r
+int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+flash_driver_t str9x_flash =\r
+{\r
+ .name = "str9x",\r
+ .register_commands = str9x_register_commands,\r
+ .flash_bank_command = str9x_flash_bank_command,\r
+ .erase = str9x_erase,\r
+ .protect = str9x_protect,\r
+ .write = str9x_write,\r
+ .probe = str9x_probe,\r
+ .auto_probe = str9x_probe,\r
+ .erase_check = str9x_erase_check,\r
+ .protect_check = str9x_protect_check,\r
+ .info = str9x_info\r
+};\r
+\r
+int str9x_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ command_t *str9x_cmd = register_command(cmd_ctx, NULL, "str9x", NULL, COMMAND_ANY, NULL);\r
+ \r
+ register_command(cmd_ctx, str9x_cmd, "flash_config", str9x_handle_flash_config_command, COMMAND_EXEC,\r
+ "configure str9 flash controller");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_build_block_list(struct flash_bank_s *bank)\r
+{\r
+ str9x_flash_bank_t *str9x_info = bank->driver_priv;\r
+ \r
+ int i;\r
+ int num_sectors = 0;\r
+ int b0_sectors = 0, b1_sectors = 0;\r
+ \r
+ switch (bank->size)\r
+ {\r
+ case (256 * 1024):\r
+ b0_sectors = 4;\r
+ break;\r
+ case (512 * 1024):\r
+ b0_sectors = 8;\r
+ break;\r
+ case (32 * 1024):\r
+ b1_sectors = 4;\r
+ bank1start = bank->base;\r
+ break;\r
+ default:\r
+ ERROR("BUG: unknown bank->size encountered");\r
+ exit(-1);\r
+ }\r
+ \r
+ num_sectors = b0_sectors + b1_sectors;\r
+ \r
+ bank->num_sectors = num_sectors;\r
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);\r
+ str9x_info->sector_bits = malloc(sizeof(u32) * num_sectors);\r
+ \r
+ num_sectors = 0;\r
+ \r
+ for (i = 0; i < b0_sectors; i++)\r
+ {\r
+ bank->sectors[num_sectors].offset = mem_layout_str9bank0[i].sector_start;\r
+ bank->sectors[num_sectors].size = mem_layout_str9bank0[i].sector_size;\r
+ bank->sectors[num_sectors].is_erased = -1;\r
+ bank->sectors[num_sectors].is_protected = 1;\r
+ str9x_info->sector_bits[num_sectors++] = mem_layout_str9bank0[i].sector_bit;\r
+ }\r
+\r
+ for (i = 0; i < b1_sectors; i++)\r
+ {\r
+ bank->sectors[num_sectors].offset = mem_layout_str9bank1[i].sector_start;\r
+ bank->sectors[num_sectors].size = mem_layout_str9bank1[i].sector_size;\r
+ bank->sectors[num_sectors].is_erased = -1;\r
+ bank->sectors[num_sectors].is_protected = 1;\r
+ str9x_info->sector_bits[num_sectors++] = mem_layout_str9bank1[i].sector_bit;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+/* flash bank str9x <base> <size> 0 0 <target#>\r
+ */\r
+int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
+{\r
+ str9x_flash_bank_t *str9x_info;\r
+ \r
+ if (argc < 6)\r
+ {\r
+ WARNING("incomplete flash_bank str9x configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ str9x_info = malloc(sizeof(str9x_flash_bank_t));\r
+ bank->driver_priv = str9x_info;\r
+ \r
+ str9x_build_block_list(bank);\r
+ \r
+ str9x_info->write_algorithm = NULL;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_blank_check(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ target_t *target = bank->target;\r
+ u8 *buffer;\r
+ int i;\r
+ int nBytes;\r
+ \r
+ if ((first < 0) || (last > bank->num_sectors))\r
+ return ERROR_FLASH_SECTOR_INVALID;\r
+\r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ buffer = malloc(256);\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ bank->sectors[i].is_erased = 1;\r
+\r
+ target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);\r
+ \r
+ for (nBytes = 0; nBytes < 256; nBytes++)\r
+ {\r
+ if (buffer[nBytes] != 0xFF)\r
+ {\r
+ bank->sectors[i].is_erased = 0;\r
+ break;\r
+ }\r
+ } \r
+ }\r
+ \r
+ free(buffer);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_protect_check(struct flash_bank_s *bank)\r
+{\r
+ str9x_flash_bank_t *str9x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ \r
+ int i;\r
+ u32 adr;\r
+ u16 status;\r
+\r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+\r
+ /* read level one protection */\r
+ \r
+ adr = bank1start + 0x10;\r
+ \r
+ target_write_u16(target, adr, 0x90);\r
+ target_read_u16(target, adr, &status);\r
+ target_write_u16(target, adr, 0xFF);\r
+ \r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ if (status & str9x_info->sector_bits[i])\r
+ bank->sectors[i].is_protected = 1;\r
+ else\r
+ bank->sectors[i].is_protected = 0;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_erase(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ target_t *target = bank->target;\r
+ int i;\r
+ u32 adr;\r
+ u8 status;\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ adr = bank->base + bank->sectors[i].offset;\r
+ \r
+ /* erase sectors */\r
+ target_write_u16(target, adr, 0x20);\r
+ target_write_u16(target, adr, 0xD0);\r
+ \r
+ /* get status */\r
+ target_write_u16(target, adr, 0x70);\r
+ \r
+ while (1) {\r
+ target_read_u8(target, adr, &status);\r
+ if( status & 0x80 )\r
+ break;\r
+ usleep(1000);\r
+ }\r
+ \r
+ /* clear status, also clear read array */\r
+ target_write_u16(target, adr, 0x50);\r
+ \r
+ /* read array command */\r
+ target_write_u16(target, adr, 0xFF);\r
+ \r
+ if( status & 0x22 )\r
+ {\r
+ ERROR("error erasing flash bank, status: 0x%x", status);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ \r
+ for (i = first; i <= last; i++)\r
+ bank->sectors[i].is_erased = 1;\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_protect(struct flash_bank_s *bank, int set, int first, int last)\r
+{\r
+ target_t *target = bank->target;\r
+ int i;\r
+ u32 adr;\r
+ u8 status;\r
+ \r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ /* Level One Protection */\r
+ \r
+ adr = bank->base + bank->sectors[i].offset;\r
+ \r
+ target_write_u16(target, adr, 0x60);\r
+ if( set )\r
+ target_write_u16(target, adr, 0x01);\r
+ else\r
+ target_write_u16(target, adr, 0xD0);\r
+ \r
+ /* query status */\r
+ target_read_u8(target, adr, &status);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ str9x_flash_bank_t *str9x_info = bank->driver_priv;\r
+ target_t *target = bank->target;\r
+ u32 buffer_size = 8192;\r
+ working_area_t *source;\r
+ u32 address = bank->base + offset;\r
+ reg_param_t reg_params[4];\r
+ armv4_5_algorithm_t armv4_5_info;\r
+ int retval;\r
+ \r
+ u32 str9x_flash_write_code[] = {\r
+ /* write: */\r
+ 0xe3c14003, /* bic r4, r1, #3 */\r
+ 0xe3a03040, /* mov r3, #0x40 */\r
+ 0xe1c430b0, /* strh r3, [r4, #0] */\r
+ 0xe0d030b2, /* ldrh r3, [r0], #2 */\r
+ 0xe0c130b2, /* strh r3, [r1], #2 */\r
+ 0xe3a03070, /* mov r3, #0x70 */\r
+ 0xe1c430b0, /* strh r3, [r4, #0] */\r
+ /* busy: */\r
+ 0xe5d43000, /* ldrb r3, [r4, #0] */\r
+ 0xe3130080, /* tst r3, #0x80 */\r
+ 0x0afffffc, /* beq busy */\r
+ 0xe3a05050, /* mov r5, #0x50 */\r
+ 0xe1c450b0, /* strh r5, [r4, #0] */\r
+ 0xe3a050ff, /* mov r5, #0xFF */\r
+ 0xe1c450b0, /* strh r5, [r4, #0] */\r
+ 0xe3130012, /* tst r3, #0x12 */\r
+ 0x1a000001, /* bne exit */\r
+ 0xe2522001, /* subs r2, r2, #1 */\r
+ 0x1affffed, /* bne write */\r
+ /* exit: */\r
+ 0xeafffffe, /* b exit */\r
+ };\r
+ \r
+ /* flash write code */\r
+ if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)\r
+ {\r
+ WARNING("no working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ };\r
+ \r
+ target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (u8*)str9x_flash_write_code);\r
+\r
+ /* memory buffer */\r
+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)\r
+ {\r
+ buffer_size /= 2;\r
+ if (buffer_size <= 256)\r
+ {\r
+ /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */\r
+ if (str9x_info->write_algorithm)\r
+ target_free_working_area(target, str9x_info->write_algorithm);\r
+ \r
+ WARNING("no large enough working area available, can't do block memory writes");\r
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
+ }\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
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);\r
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);\r
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);\r
+ init_reg_param(®_params[3], "r3", 32, PARAM_IN);\r
+ \r
+ while (count > 0)\r
+ {\r
+ u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;\r
+ \r
+ target_write_buffer(target, source->address, thisrun_count * 2, buffer);\r
+ \r
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);\r
+ buf_set_u32(reg_params[1].value, 0, 32, address);\r
+ buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);\r
+\r
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)\r
+ {\r
+ target_free_working_area(target, source);\r
+ target_free_working_area(target, str9x_info->write_algorithm);\r
+ ERROR("error executing str9x flash write algorithm");\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)\r
+ {\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ buffer += thisrun_count * 2;\r
+ address += thisrun_count * 2;\r
+ count -= thisrun_count;\r
+ }\r
+ \r
+ target_free_working_area(target, source);\r
+ target_free_working_area(target, str9x_info->write_algorithm);\r
+ \r
+ destroy_reg_param(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ destroy_reg_param(®_params[3]);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ target_t *target = bank->target;\r
+ u32 words_remaining = (count / 2);\r
+ u32 bytes_remaining = (count & 0x00000001);\r
+ u32 address = bank->base + offset;\r
+ u32 bytes_written = 0;\r
+ u8 status;\r
+ u32 retval;\r
+ u32 check_address = offset;\r
+ u32 bank_adr;\r
+ int i;\r
+ \r
+ if (offset & 0x1)\r
+ {\r
+ WARNING("offset 0x%x breaks required 2-byte alignment", offset);\r
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
+ }\r
+ \r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ u32 sec_start = bank->sectors[i].offset;\r
+ u32 sec_end = sec_start + bank->sectors[i].size;\r
+ \r
+ /* check if destination falls within the current sector */\r
+ if ((check_address >= sec_start) && (check_address < sec_end))\r
+ {\r
+ /* check if destination ends in the current sector */\r
+ if (offset + count < sec_end)\r
+ check_address = offset + count;\r
+ else\r
+ check_address = sec_end;\r
+ }\r
+ }\r
+ \r
+ if (check_address != offset + count)\r
+ return ERROR_FLASH_DST_OUT_OF_BANK;\r
+ \r
+ /* multiple half words (2-byte) to be programmed? */\r
+ if (words_remaining > 0) \r
+ {\r
+ /* try using a block write */\r
+ if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)\r
+ {\r
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)\r
+ {\r
+ /* if block write failed (no sufficient working area),\r
+ * we use normal (slow) single dword accesses */ \r
+ WARNING("couldn't use block writes, falling back to single memory accesses");\r
+ }\r
+ else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
+ {\r
+ ERROR("flash writing failed with error code: 0x%x", retval);\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ buffer += words_remaining * 2;\r
+ address += words_remaining * 2;\r
+ words_remaining = 0;\r
+ }\r
+ }\r
+\r
+ while (words_remaining > 0)\r
+ {\r
+ bank_adr = address & ~0x03;\r
+ \r
+ /* write data command */\r
+ target_write_u16(target, bank_adr, 0x40);\r
+ target->type->write_memory(target, address, 2, 1, buffer + bytes_written);\r
+ \r
+ /* get status command */\r
+ target_write_u16(target, bank_adr, 0x70);\r
+ \r
+ while (1) {\r
+ target_read_u8(target, bank_adr, &status);\r
+ if( status & 0x80 )\r
+ break;\r
+ usleep(1000);\r
+ }\r
+ \r
+ /* clear status reg and read array */\r
+ target_write_u16(target, bank_adr, 0x50);\r
+ target_write_u16(target, bank_adr, 0xFF);\r
+ \r
+ if (status & 0x10)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ else if (status & 0x02)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+\r
+ bytes_written += 2;\r
+ words_remaining--;\r
+ address += 2;\r
+ }\r
+ \r
+ if (bytes_remaining)\r
+ {\r
+ u8 last_halfword[2] = {0xff, 0xff};\r
+ int i = 0;\r
+ \r
+ while(bytes_remaining > 0)\r
+ {\r
+ last_halfword[i++] = *(buffer + bytes_written); \r
+ bytes_remaining--;\r
+ bytes_written++;\r
+ }\r
+ \r
+ bank_adr = address & ~0x03;\r
+ \r
+ /* write data comamnd */\r
+ target_write_u16(target, bank_adr, 0x40);\r
+ target->type->write_memory(target, address, 2, 1, last_halfword);\r
+ \r
+ /* query status command */\r
+ target_write_u16(target, bank_adr, 0x70);\r
+ \r
+ while (1) {\r
+ target_read_u8(target, bank_adr, &status);\r
+ if( status & 0x80 )\r
+ break;\r
+ usleep(1000);\r
+ }\r
+ \r
+ /* clear status reg and read array */\r
+ target_write_u16(target, bank_adr, 0x50);\r
+ target_write_u16(target, bank_adr, 0xFF);\r
+ \r
+ if (status & 0x10)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ else if (status & 0x02)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_probe(struct flash_bank_s *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_erase_check(struct flash_bank_s *bank)\r
+{\r
+ return str9x_blank_check(bank, 0, bank->num_sectors - 1);\r
+}\r
+\r
+int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
+{\r
+ snprintf(buf, buf_size, "str9x flash driver info" );\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ str9x_flash_bank_t *str9x_info;\r
+ flash_bank_t *bank;\r
+ target_t *target = NULL;\r
+ \r
+ if (argc < 5)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\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
+ str9x_info = bank->driver_priv;\r
+ \r
+ target = bank->target;\r
+ \r
+ if (bank->target->state != TARGET_HALTED)\r
+ {\r
+ return ERROR_TARGET_NOT_HALTED;\r
+ }\r
+ \r
+ /* config flash controller */\r
+ target_write_u32(target, FLASH_BBSR, strtoul(args[1], NULL, 0));\r
+ target_write_u32(target, FLASH_NBBSR, strtoul(args[2], NULL, 0));\r
+ target_write_u32(target, FLASH_BBADR, (strtoul(args[3], NULL, 0) >> 2));\r
+ target_write_u32(target, FLASH_NBBADR, (strtoul(args[4], NULL, 0) >> 2));\r
+\r
+ /* set bit 18 instruction TCM order as per flash programming manual */\r
+ arm966e_write_cp15(target, 62, 0x40000);\r
+ \r
+ /* enable flash bank 1 */\r
+ target_write_u32(target, FLASH_CR, 0x18);\r
+ return ERROR_OK;\r
+}\r
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "str9xpec.h"
-#include "flash.h"
-#include "target.h"
-#include "log.h"
-#include "armv4_5.h"
-#include "arm7_9_common.h"
-#include "jtag.h"
-#include "binarybuffer.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-
-str9xpec_mem_layout_t mem_layout_str9pec[] = {
- {0x00000000, 0x10000, 0},
- {0x00010000, 0x10000, 1},
- {0x00020000, 0x10000, 2},
- {0x00030000, 0x10000, 3},
- {0x00040000, 0x10000, 4},
- {0x00050000, 0x10000, 5},
- {0x00060000, 0x10000, 6},
- {0x00070000, 0x10000, 7},
- {0x00080000, 0x02000, 32},
- {0x00082000, 0x02000, 33},
- {0x00084000, 0x02000, 34},
- {0x00086000, 0x02000, 35}
-};
-
-int str9xpec_register_commands(struct command_context_s *cmd_ctx);
-int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int str9xpec_erase(struct flash_bank_s *bank, int first, int last);
-int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last);
-int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int str9xpec_probe(struct flash_bank_s *bank);
-int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_protect_check(struct flash_bank_s *bank);
-int str9xpec_erase_check(struct flash_bank_s *bank);
-int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last);
-int str9xpec_set_address(struct flash_bank_s *bank, u8 sector);
-int str9xpec_write_options(struct flash_bank_s *bank);
-
-int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-flash_driver_t str9xpec_flash =
-{
- .name = "str9xpec",
- .register_commands = str9xpec_register_commands,
- .flash_bank_command = str9xpec_flash_bank_command,
- .erase = str9xpec_erase,
- .protect = str9xpec_protect,
- .write = str9xpec_write,
- .probe = str9xpec_probe,
- .auto_probe = str9xpec_probe,
- .erase_check = str9xpec_erase_check,
- .protect_check = str9xpec_protect_check,
- .info = str9xpec_info
-};
-
-int str9xpec_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands");
-
- register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC,
- "enable str9xpec turbo mode");
- register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC,
- "disable str9xpec turbo mode");
- register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC,
- "configure str9xpec boot sector");
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC,
- "configure str9xpec lvd threshold");
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC,
- "configure str9xpec lvd selection");
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC,
- "configure str9xpec lvd warning");
- register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC,
- "read str9xpec options");
- register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC,
- "write str9xpec options");
- register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC,
- "lock str9xpec device");
- register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC,
- "unlock str9xpec device");
- register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC,
- "print part id of str9xpec flash bank <num>");
-
- return ERROR_OK;
-}
-
-int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state)
-{
- jtag_device_t *device = jtag_get_device(chain_pos);
-
- if (device == NULL)
- {
- DEBUG("Invalid Target");
- return ERROR_TARGET_INVALID;
- }
-
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
- {
- scan_field_t field;
-
- field.device = chain_pos;
- field.num_bits = device->ir_length;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_ir_scan(1, &field, end_state, NULL);
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-u8 str9xpec_isc_status(int chain_pos)
-{
- scan_field_t field;
- u8 status;
-
- if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK)
- return ISC_STATUS_ERROR;
-
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = &status;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
- jtag_execute_queue();
-
- DEBUG("status: 0x%2.2x", status);
-
- if (status & ISC_STATUS_SECURITY)
- INFO("Device Security Bit Set");
-
- return status;
-}
-
-int str9xpec_isc_enable(struct flash_bank_s *bank)
-{
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (str9xpec_info->isc_enable)
- return ERROR_OK;
-
- /* enter isc mode */
- if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK)
- return ERROR_TARGET_INVALID;
-
- /* check ISC status */
- status = str9xpec_isc_status(chain_pos);
- if (status & ISC_STATUS_MODE)
- {
- /* we have entered isc mode */
- str9xpec_info->isc_enable = 1;
- DEBUG("ISC_MODE Enabled");
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_isc_disable(struct flash_bank_s *bank)
-{
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable)
- return ERROR_OK;
-
- if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK)
- return ERROR_TARGET_INVALID;
-
- /* delay to handle aborts */
- jtag_add_sleep(50);
-
- /* check ISC status */
- status = str9xpec_isc_status(chain_pos);
- if (!(status & ISC_STATUS_MODE))
- {
- /* we have left isc mode */
- str9xpec_info->isc_enable = 0;
- DEBUG("ISC_MODE Disabled");
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_read_config(struct flash_bank_s *bank)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- DEBUG("ISC_CONFIGURATION");
-
- /* execute ISC_CONFIGURATION command */
- str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = str9xpec_info->options;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
- jtag_execute_queue();
-
- status = str9xpec_isc_status(chain_pos);
-
- return status;
-}
-
-int str9xpec_build_block_list(struct flash_bank_s *bank)
-{
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- int i;
- int num_sectors = 0, b0_sectors = 0;
-
- switch (bank->size)
- {
- case (256 * 1024):
- b0_sectors = 4;
- break;
- case (512 * 1024):
- b0_sectors = 8;
- break;
- default:
- ERROR("BUG: unknown bank->size encountered");
- exit(-1);
- }
-
- /* include bank 1 sectors */
- num_sectors = b0_sectors + 4;
- bank->size += (32 * 1024);
-
- bank->num_sectors = num_sectors;
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
- str9xpec_info->sector_bits = malloc(sizeof(u32) * num_sectors);
-
- num_sectors = 0;
-
- for (i = 0; i < b0_sectors; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;
- }
-
- for (i = 8; i < 12; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;
- }
-
- return ERROR_OK;
-}
-
-/* flash bank str9x <base> <size> 0 0 <target#>
- */
-int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- str9xpec_flash_controller_t *str9xpec_info;
- armv4_5_common_t *armv4_5 = NULL;
- arm7_9_common_t *arm7_9 = NULL;
- arm_jtag_t *jtag_info = NULL;
-
- if (argc < 6)
- {
- WARNING("incomplete flash_bank str9x configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t));
- bank->driver_priv = str9xpec_info;
-
- if (bank->base != 0x00000000)
- {
- WARNING("overriding flash base address for STR91x device with 0x00000000");
- bank->base = 0x00000000;
- }
-
- /* find out jtag position of flash controller
- * it is always after the arm966 core */
-
- armv4_5 = bank->target->arch_info;
- arm7_9 = armv4_5->arch_info;
- jtag_info = &arm7_9->jtag_info;
-
- str9xpec_info->chain_pos = (jtag_info->chain_pos - 1);
- str9xpec_info->isc_enable = 0;
- str9xpec_info->devarm = NULL;
-
- str9xpec_build_block_list(bank);
-
- /* clear option byte register */
- buf_set_u32(str9xpec_info->options, 0, 64, 0);
-
- return ERROR_OK;
-}
-
-int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- int i;
- u8 *buffer = NULL;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- buffer = calloc(CEIL(64, 8), 1);
-
- DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);
-
- for (i = first; i <= last; i++) {
- buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
- }
-
- /* execute ISC_BLANK_CHECK command */
- str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = buffer;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
- jtag_add_sleep(40000);
-
- /* read blank check result */
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = buffer;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_PI, NULL);
- jtag_execute_queue();
-
- status = str9xpec_isc_status(chain_pos);
-
- for (i = first; i <= last; i++)
- {
- if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))
- bank->sectors[i].is_erased = 0;
- else
- bank->sectors[i].is_erased = 1;
- }
-
- free(buffer);
-
- str9xpec_isc_disable(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
- return ERROR_OK;
-}
-
-int str9xpec_protect_check(struct flash_bank_s *bank)
-{
- u8 status;
- int i;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- status = str9xpec_read_config(bank);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
- }
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
- return ERROR_OK;
-}
-
-int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- int i;
- u8 *buffer = NULL;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ISC_STATUS_ERROR;
- }
-
- buffer = calloc(CEIL(64, 8), 1);
-
- DEBUG("erase: first_bank: %i, last_bank: %i", first, last);
-
- /* last bank: 0xFF signals a full erase (unlock complete device) */
- /* last bank: 0xFE signals a option byte erase */
- if (last == 0xFF)
- {
- for (i = 0; i < 64; i++) {
- buf_set_u32(buffer, i, 1, 1);
- }
- }
- else if (last == 0xFE)
- {
- buf_set_u32(buffer, 49, 1, 1);
- }
- else
- {
- for (i = first; i <= last; i++) {
- buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
- }
- }
-
- DEBUG("ISC_ERASE");
-
- /* execute ISC_ERASE command */
- str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = buffer;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
- jtag_execute_queue();
-
- jtag_add_sleep(10);
-
- /* wait for erase completion */
- while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) {
- usleep(1000);
- }
-
- free(buffer);
-
- str9xpec_isc_disable(bank);
-
- return status;
-}
-
-int str9xpec_erase(struct flash_bank_s *bank, int first, int last)
-{
- int status;
-
- status = str9xpec_erase_area(bank, first, last);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_lock_device(struct flash_bank_s *bank)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- str9xpec_info = bank->driver_priv;
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ISC_STATUS_ERROR;
- }
-
- /* set security address */
- str9xpec_set_address(bank, 0x80);
-
- /* execute ISC_PROGRAM command */
- str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = &status;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1, NULL);
- jtag_execute_queue();
-
- } while(!(status & ISC_STATUS_BUSY));
-
- str9xpec_isc_disable(bank);
-
- return status;
-}
-
-int str9xpec_unlock_device(struct flash_bank_s *bank)
-{
- u8 status;
-
- status = str9xpec_erase_area(bank, 0, 255);
-
- return status;
-}
-
-int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- u8 status;
- int i;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- status = str9xpec_read_config(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- DEBUG("protect: first_bank: %i, last_bank: %i", first, last);
-
- /* last bank: 0xFF signals a full device protect */
- if (last == 0xFF)
- {
- if( set )
- {
- status = str9xpec_lock_device(bank);
- }
- else
- {
- /* perform full erase to unlock device */
- status = str9xpec_unlock_device(bank);
- }
- }
- else
- {
- for (i = first; i <= last; i++)
- {
- if( set )
- buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);
- else
- buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);
- }
-
- status = str9xpec_write_options(bank);
- }
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_set_address(struct flash_bank_s *bank, u8 sector)
-{
- u32 chain_pos;
- scan_field_t field;
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- /* set flash controller address */
- str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = §or;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1, NULL);
-
- return ERROR_OK;
-}
-
-int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
- u32 dwords_remaining = (count / 8);
- u32 bytes_remaining = (count & 0x00000007);
- u32 bytes_written = 0;
- u8 status;
- u32 check_address = offset;
- u32 chain_pos;
- scan_field_t field;
- u8 *scanbuf;
- int i;
- u32 first_sector = 0;
- u32 last_sector = 0;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable(bank);
- }
-
- if (!str9xpec_info->isc_enable) {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if (offset & 0x7)
- {
- WARNING("offset 0x%x breaks required 8-byte alignment", offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 sec_start = bank->sectors[i].offset;
- u32 sec_end = sec_start + bank->sectors[i].size;
-
- /* check if destination falls within the current sector */
- if ((check_address >= sec_start) && (check_address < sec_end))
- {
- /* check if destination ends in the current sector */
- if (offset + count < sec_end)
- check_address = offset + count;
- else
- check_address = sec_end;
- }
-
- if ((offset >= sec_start) && (offset < sec_end)){
- first_sector = i;
- }
-
- if ((offset + count >= sec_start) && (offset + count < sec_end)){
- last_sector = i;
- }
- }
-
- if (check_address != offset + count)
- return ERROR_FLASH_DST_OUT_OF_BANK;
-
- DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
-
- scanbuf = calloc(CEIL(64, 8), 1);
-
- DEBUG("ISC_PROGRAM");
-
- for (i = first_sector; i <= last_sector; i++)
- {
- str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);
-
- dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);
-
- while (dwords_remaining > 0)
- {
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = (buffer + bytes_written);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
-
- /* small delay before polling */
- jtag_add_sleep(50);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = scanbuf;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1, NULL);
- jtag_execute_queue();
-
- status = buf_get_u32(scanbuf, 0, 8);
-
- } while(!(status & ISC_STATUS_BUSY));
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
- // return ERROR_FLASH_OPERATION_FAILED;
-
- dwords_remaining--;
- bytes_written += 8;
- }
- }
-
- if (bytes_remaining)
- {
- u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- int i = 0;
-
- while(bytes_remaining > 0)
- {
- last_dword[i++] = *(buffer + bytes_written);
- bytes_remaining--;
- bytes_written++;
- }
-
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = last_dword;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
-
- /* small delay before polling */
- jtag_add_sleep(50);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = scanbuf;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1, NULL);
- jtag_execute_queue();
-
- status = buf_get_u32(scanbuf, 0, 8);
-
- } while(!(status & ISC_STATUS_BUSY));
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
- // return ERROR_FLASH_OPERATION_FAILED;
- }
-
- free(scanbuf);
-
- str9xpec_isc_disable(bank);
-
- return ERROR_OK;
-}
-
-int str9xpec_probe(struct flash_bank_s *bank)
-{
- return ERROR_OK;
-}
-
-int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- scan_field_t field;
- u8 *buffer = NULL;
- u32 chain_pos;
- u32 idcode;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: str9xpec 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;
- }
-
- str9xpec_info = bank->driver_priv;
- chain_pos = str9xpec_info->chain_pos;
-
- buffer = calloc(CEIL(32, 8), 1);
-
- str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 32;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = buffer;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
- jtag_execute_queue();
-
- idcode = buf_get_u32(buffer, 0, 32);
-
- command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode);
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int str9xpec_erase_check(struct flash_bank_s *bank)
-{
- return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- snprintf(buf, buf_size, "str9xpec flash driver info" );
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u8 status;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec options_read <bank>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- status = str9xpec_read_config(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* boot bank */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))
- command_print(cmd_ctx, "CS Map: bank1");
- else
- command_print(cmd_ctx, "CS Map: bank0");
-
- /* OTP lock */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))
- command_print(cmd_ctx, "OTP Lock: OTP Locked");
- else
- command_print(cmd_ctx, "OTP Lock: OTP Unlocked");
-
- /* LVD Threshold */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))
- command_print(cmd_ctx, "LVD Threshold: 2.7v");
- else
- command_print(cmd_ctx, "LVD Threshold: 2.4v");
-
- /* LVD reset warning */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))
- command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs");
- else
- command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only");
-
- /* LVD reset select */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))
- command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs");
- else
- command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only");
-
- return ERROR_OK;
-}
-
-int str9xpec_write_options(struct flash_bank_s *bank)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- str9xpec_info = bank->driver_priv;
- chain_pos = str9xpec_info->chain_pos;
-
- /* erase config options first */
- status = str9xpec_erase_area( bank, 0xFE, 0xFE );
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return status;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ISC_STATUS_ERROR;
- }
-
- /* according to data 64th bit has to be set */
- buf_set_u32(str9xpec_info->options, 63, 1, 1);
-
- /* set option byte address */
- str9xpec_set_address(bank, 0x50);
-
- /* execute ISC_PROGRAM command */
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = str9xpec_info->options;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI, NULL);
-
- /* small delay before polling */
- jtag_add_sleep(50);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = &status;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1, NULL);
- jtag_execute_queue();
-
- } while(!(status & ISC_STATUS_BUSY));
-
- str9xpec_isc_disable(bank);
-
- return status;
-}
-
-int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u8 status;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec options_write <bank>");
- 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;
- }
-
- status = str9xpec_write_options(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_cmap <bank> <bank0|bank1>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "bank1") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_lvdthd <bank> <2.4v|2.7v>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "2.7v") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_lvdsel <bank> <vdd|vdd_vddq>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "vdd_vddq") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_lvdwarn <bank> <vdd|vdd_vddq>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "vdd_vddq") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u8 status;
- flash_bank_t *bank;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec lock <bank>");
- 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;
- }
-
- status = str9xpec_lock_device(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u8 status;
- flash_bank_t *bank;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec unlock <bank>");
- 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;
- }
-
- status = str9xpec_unlock_device(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u32 chain_pos;
- jtag_device_t* dev0;
- jtag_device_t* dev2;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec enable_turbo <bank>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- /* remove arm core from chain - enter turbo mode */
-
- str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI);
- jtag_execute_queue();
-
- /* modify scan chain - str9 core has been removed */
- dev0 = jtag_get_device(chain_pos);
- str9xpec_info->devarm = jtag_get_device(chain_pos+1);
- dev2 = jtag_get_device(chain_pos+2);
- dev0->next = dev2;
- jtag_num_devices--;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u32 chain_pos;
- jtag_device_t* dev0;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec disable_turbo <bank>");
- 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;
- }
-
- str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- dev0 = jtag_get_device(chain_pos);
-
- /* exit turbo mode via TLR */
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR);
- jtag_execute_queue();
-
- /* restore previous scan chain */
- if( str9xpec_info->devarm ) {
- dev0->next = str9xpec_info->devarm;
- jtag_num_devices++;
- str9xpec_info->devarm = NULL;
- }
-
- 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 "replacements.h"\r
+\r
+#include "str9xpec.h"\r
+#include "flash.h"\r
+#include "target.h"\r
+#include "log.h"\r
+#include "armv4_5.h"\r
+#include "arm7_9_common.h"\r
+#include "jtag.h"\r
+#include "binarybuffer.h"\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <getopt.h>\r
+\r
+str9xpec_mem_layout_t mem_layout_str9pec[] = {\r
+ {0x00000000, 0x10000, 0},\r
+ {0x00010000, 0x10000, 1},\r
+ {0x00020000, 0x10000, 2},\r
+ {0x00030000, 0x10000, 3},\r
+ {0x00040000, 0x10000, 4},\r
+ {0x00050000, 0x10000, 5},\r
+ {0x00060000, 0x10000, 6},\r
+ {0x00070000, 0x10000, 7},\r
+ {0x00080000, 0x02000, 32},\r
+ {0x00082000, 0x02000, 33},\r
+ {0x00084000, 0x02000, 34},\r
+ {0x00086000, 0x02000, 35}\r
+};\r
+\r
+int str9xpec_register_commands(struct command_context_s *cmd_ctx);\r
+int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
+int str9xpec_erase(struct flash_bank_s *bank, int first, int last);\r
+int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last);\r
+int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
+int str9xpec_probe(struct flash_bank_s *bank);\r
+int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_protect_check(struct flash_bank_s *bank);\r
+int str9xpec_erase_check(struct flash_bank_s *bank);\r
+int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
+\r
+int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last);\r
+int str9xpec_set_address(struct flash_bank_s *bank, u8 sector);\r
+int str9xpec_write_options(struct flash_bank_s *bank);\r
+\r
+int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+flash_driver_t str9xpec_flash =\r
+{\r
+ .name = "str9xpec",\r
+ .register_commands = str9xpec_register_commands,\r
+ .flash_bank_command = str9xpec_flash_bank_command,\r
+ .erase = str9xpec_erase,\r
+ .protect = str9xpec_protect,\r
+ .write = str9xpec_write,\r
+ .probe = str9xpec_probe,\r
+ .auto_probe = str9xpec_probe,\r
+ .erase_check = str9xpec_erase_check,\r
+ .protect_check = str9xpec_protect_check,\r
+ .info = str9xpec_info\r
+};\r
+\r
+int str9xpec_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands");\r
+ \r
+ register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC,\r
+ "enable str9xpec turbo mode");\r
+ register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC,\r
+ "disable str9xpec turbo mode");\r
+ register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC,\r
+ "configure str9xpec boot sector");\r
+ register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC,\r
+ "configure str9xpec lvd threshold");\r
+ register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC,\r
+ "configure str9xpec lvd selection");\r
+ register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC,\r
+ "configure str9xpec lvd warning");\r
+ register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC,\r
+ "read str9xpec options");\r
+ register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC,\r
+ "write str9xpec options");\r
+ register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC,\r
+ "lock str9xpec device");\r
+ register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC,\r
+ "unlock str9xpec device");\r
+ register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC,\r
+ "print part id of str9xpec flash bank <num>");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state)\r
+{\r
+ jtag_device_t *device = jtag_get_device(chain_pos);\r
+ \r
+ if (device == NULL)\r
+ {\r
+ DEBUG("Invalid Target");\r
+ return ERROR_TARGET_INVALID;\r
+ }\r
+ \r
+ if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)\r
+ {\r
+ scan_field_t field;\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = device->ir_length;\r
+ field.out_value = calloc(CEIL(field.num_bits, 8), 1);\r
+ buf_set_u32(field.out_value, 0, field.num_bits, new_instr);\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_ir_scan(1, &field, end_state, NULL);\r
+ \r
+ free(field.out_value);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+u8 str9xpec_isc_status(int chain_pos)\r
+{\r
+ scan_field_t field;\r
+ u8 status;\r
+ \r
+ if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK)\r
+ return ISC_STATUS_ERROR;\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 8;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = &status;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ DEBUG("status: 0x%2.2x", status);\r
+ \r
+ if (status & ISC_STATUS_SECURITY)\r
+ INFO("Device Security Bit Set");\r
+ \r
+ return status;\r
+}\r
+\r
+int str9xpec_isc_enable(struct flash_bank_s *bank)\r
+{\r
+ u8 status;\r
+ u32 chain_pos;\r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ if (str9xpec_info->isc_enable)\r
+ return ERROR_OK;\r
+ \r
+ /* enter isc mode */\r
+ if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK)\r
+ return ERROR_TARGET_INVALID;\r
+ \r
+ /* check ISC status */\r
+ status = str9xpec_isc_status(chain_pos);\r
+ if (status & ISC_STATUS_MODE)\r
+ {\r
+ /* we have entered isc mode */\r
+ str9xpec_info->isc_enable = 1;\r
+ DEBUG("ISC_MODE Enabled");\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_isc_disable(struct flash_bank_s *bank)\r
+{\r
+ u8 status;\r
+ u32 chain_pos;\r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ if (!str9xpec_info->isc_enable)\r
+ return ERROR_OK;\r
+ \r
+ if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK)\r
+ return ERROR_TARGET_INVALID;\r
+ \r
+ /* delay to handle aborts */\r
+ jtag_add_sleep(50);\r
+ \r
+ /* check ISC status */\r
+ status = str9xpec_isc_status(chain_pos);\r
+ if (!(status & ISC_STATUS_MODE))\r
+ {\r
+ /* we have left isc mode */\r
+ str9xpec_info->isc_enable = 0;\r
+ DEBUG("ISC_MODE Disabled");\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_read_config(struct flash_bank_s *bank)\r
+{\r
+ scan_field_t field;\r
+ u8 status;\r
+ u32 chain_pos;\r
+ \r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ DEBUG("ISC_CONFIGURATION");\r
+ \r
+ /* execute ISC_CONFIGURATION command */\r
+ str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = str9xpec_info->options;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ status = str9xpec_isc_status(chain_pos);\r
+ \r
+ return status;\r
+}\r
+\r
+int str9xpec_build_block_list(struct flash_bank_s *bank)\r
+{\r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ int i;\r
+ int num_sectors = 0, b0_sectors = 0;\r
+ \r
+ switch (bank->size)\r
+ {\r
+ case (256 * 1024):\r
+ b0_sectors = 4;\r
+ break;\r
+ case (512 * 1024):\r
+ b0_sectors = 8;\r
+ break;\r
+ default:\r
+ ERROR("BUG: unknown bank->size encountered");\r
+ exit(-1);\r
+ }\r
+ \r
+ /* include bank 1 sectors */\r
+ num_sectors = b0_sectors + 4;\r
+ bank->size += (32 * 1024);\r
+ \r
+ bank->num_sectors = num_sectors;\r
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);\r
+ str9xpec_info->sector_bits = malloc(sizeof(u32) * num_sectors);\r
+ \r
+ num_sectors = 0;\r
+ \r
+ for (i = 0; i < b0_sectors; i++)\r
+ {\r
+ bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;\r
+ bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;\r
+ bank->sectors[num_sectors].is_erased = -1;\r
+ bank->sectors[num_sectors].is_protected = 1;\r
+ str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;\r
+ }\r
+ \r
+ for (i = 8; i < 12; i++)\r
+ {\r
+ bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;\r
+ bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;\r
+ bank->sectors[num_sectors].is_erased = -1;\r
+ bank->sectors[num_sectors].is_protected = 1;\r
+ str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+/* flash bank str9x <base> <size> 0 0 <target#>\r
+ */\r
+int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
+{\r
+ str9xpec_flash_controller_t *str9xpec_info;\r
+ armv4_5_common_t *armv4_5 = NULL;\r
+ arm7_9_common_t *arm7_9 = NULL;\r
+ arm_jtag_t *jtag_info = NULL;\r
+ \r
+ if (argc < 6)\r
+ {\r
+ WARNING("incomplete flash_bank str9x configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t));\r
+ bank->driver_priv = str9xpec_info;\r
+ \r
+ if (bank->base != 0x00000000)\r
+ {\r
+ WARNING("overriding flash base address for STR91x device with 0x00000000");\r
+ bank->base = 0x00000000;\r
+ }\r
+\r
+ /* find out jtag position of flash controller\r
+ * it is always after the arm966 core */\r
+ \r
+ armv4_5 = bank->target->arch_info;\r
+ arm7_9 = armv4_5->arch_info;\r
+ jtag_info = &arm7_9->jtag_info;\r
+ \r
+ str9xpec_info->chain_pos = (jtag_info->chain_pos - 1);\r
+ str9xpec_info->isc_enable = 0;\r
+ str9xpec_info->devarm = NULL;\r
+ \r
+ str9xpec_build_block_list(bank);\r
+ \r
+ /* clear option byte register */\r
+ buf_set_u32(str9xpec_info->options, 0, 64, 0);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ scan_field_t field;\r
+ u8 status;\r
+ u32 chain_pos;\r
+ int i;\r
+ u8 *buffer = NULL;\r
+ \r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ str9xpec_isc_enable( bank );\r
+ }\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ buffer = calloc(CEIL(64, 8), 1);\r
+\r
+ DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);\r
+ \r
+ for (i = first; i <= last; i++) {\r
+ buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);\r
+ }\r
+ \r
+ /* execute ISC_BLANK_CHECK command */\r
+ str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = buffer;\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ jtag_add_sleep(40000);\r
+ \r
+ /* read blank check result */\r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = buffer;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_PI, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ status = str9xpec_isc_status(chain_pos);\r
+ \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))\r
+ bank->sectors[i].is_erased = 0;\r
+ else\r
+ bank->sectors[i].is_erased = 1;\r
+ }\r
+ \r
+ free(buffer);\r
+ \r
+ str9xpec_isc_disable(bank);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED; \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_protect_check(struct flash_bank_s *bank)\r
+{\r
+ u8 status;\r
+ int i;\r
+ \r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ status = str9xpec_read_config(bank);\r
+ \r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))\r
+ bank->sectors[i].is_protected = 1;\r
+ else\r
+ bank->sectors[i].is_protected = 0;\r
+ }\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ scan_field_t field;\r
+ u8 status;\r
+ u32 chain_pos;\r
+ int i;\r
+ u8 *buffer = NULL;\r
+ \r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ str9xpec_isc_enable( bank );\r
+ }\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ return ISC_STATUS_ERROR;\r
+ }\r
+ \r
+ buffer = calloc(CEIL(64, 8), 1);\r
+ \r
+ DEBUG("erase: first_bank: %i, last_bank: %i", first, last);\r
+ \r
+ /* last bank: 0xFF signals a full erase (unlock complete device) */\r
+ /* last bank: 0xFE signals a option byte erase */\r
+ if (last == 0xFF)\r
+ {\r
+ for (i = 0; i < 64; i++) {\r
+ buf_set_u32(buffer, i, 1, 1);\r
+ } \r
+ }\r
+ else if (last == 0xFE)\r
+ {\r
+ buf_set_u32(buffer, 49, 1, 1);\r
+ }\r
+ else\r
+ { \r
+ for (i = first; i <= last; i++) {\r
+ buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);\r
+ }\r
+ }\r
+ \r
+ DEBUG("ISC_ERASE");\r
+ \r
+ /* execute ISC_ERASE command */\r
+ str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = buffer;\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ jtag_add_sleep(10);\r
+ \r
+ /* wait for erase completion */\r
+ while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) {\r
+ usleep(1000);\r
+ }\r
+ \r
+ free(buffer);\r
+ \r
+ str9xpec_isc_disable(bank);\r
+ \r
+ return status;\r
+}\r
+\r
+int str9xpec_erase(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ int status;\r
+ \r
+ status = str9xpec_erase_area(bank, first, last);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_lock_device(struct flash_bank_s *bank)\r
+{\r
+ scan_field_t field;\r
+ u8 status;\r
+ u32 chain_pos;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ str9xpec_info = bank->driver_priv;\r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ str9xpec_isc_enable( bank );\r
+ }\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ return ISC_STATUS_ERROR;\r
+ }\r
+ \r
+ /* set security address */\r
+ str9xpec_set_address(bank, 0x80);\r
+ \r
+ /* execute ISC_PROGRAM command */\r
+ str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI);\r
+ \r
+ str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
+ \r
+ do {\r
+ field.device = chain_pos;\r
+ field.num_bits = 8;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = &status;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, -1, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ } while(!(status & ISC_STATUS_BUSY));\r
+ \r
+ str9xpec_isc_disable(bank);\r
+ \r
+ return status;\r
+}\r
+\r
+int str9xpec_unlock_device(struct flash_bank_s *bank)\r
+{\r
+ u8 status;\r
+ \r
+ status = str9xpec_erase_area(bank, 0, 255);\r
+ \r
+ return status;\r
+}\r
+\r
+int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last)\r
+{\r
+ u8 status;\r
+ int i;\r
+ \r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ status = str9xpec_read_config(bank);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+\r
+ DEBUG("protect: first_bank: %i, last_bank: %i", first, last);\r
+ \r
+ /* last bank: 0xFF signals a full device protect */\r
+ if (last == 0xFF)\r
+ {\r
+ if( set )\r
+ {\r
+ status = str9xpec_lock_device(bank);\r
+ }\r
+ else\r
+ {\r
+ /* perform full erase to unlock device */\r
+ status = str9xpec_unlock_device(bank);\r
+ }\r
+ }\r
+ else\r
+ { \r
+ for (i = first; i <= last; i++)\r
+ {\r
+ if( set )\r
+ buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);\r
+ else\r
+ buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);\r
+ }\r
+ \r
+ status = str9xpec_write_options(bank);\r
+ }\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_set_address(struct flash_bank_s *bank, u8 sector)\r
+{\r
+ u32 chain_pos;\r
+ scan_field_t field;\r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ /* set flash controller address */\r
+ str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 8;\r
+ field.out_value = §or;\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, -1, NULL);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
+ u32 dwords_remaining = (count / 8);\r
+ u32 bytes_remaining = (count & 0x00000007);\r
+ u32 bytes_written = 0;\r
+ u8 status;\r
+ u32 check_address = offset;\r
+ u32 chain_pos;\r
+ scan_field_t field;\r
+ u8 *scanbuf;\r
+ int i;\r
+ u32 first_sector = 0;\r
+ u32 last_sector = 0;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ str9xpec_isc_enable(bank);\r
+ }\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+ \r
+ if (offset & 0x7)\r
+ {\r
+ WARNING("offset 0x%x breaks required 8-byte alignment", offset);\r
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
+ }\r
+ \r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ u32 sec_start = bank->sectors[i].offset;\r
+ u32 sec_end = sec_start + bank->sectors[i].size;\r
+ \r
+ /* check if destination falls within the current sector */\r
+ if ((check_address >= sec_start) && (check_address < sec_end))\r
+ {\r
+ /* check if destination ends in the current sector */\r
+ if (offset + count < sec_end)\r
+ check_address = offset + count;\r
+ else\r
+ check_address = sec_end;\r
+ }\r
+ \r
+ if ((offset >= sec_start) && (offset < sec_end)){\r
+ first_sector = i;\r
+ }\r
+ \r
+ if ((offset + count >= sec_start) && (offset + count < sec_end)){\r
+ last_sector = i;\r
+ }\r
+ }\r
+ \r
+ if (check_address != offset + count)\r
+ return ERROR_FLASH_DST_OUT_OF_BANK;\r
+\r
+ DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);\r
+ \r
+ scanbuf = calloc(CEIL(64, 8), 1);\r
+ \r
+ DEBUG("ISC_PROGRAM");\r
+ \r
+ for (i = first_sector; i <= last_sector; i++)\r
+ {\r
+ str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);\r
+ \r
+ dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);\r
+\r
+ while (dwords_remaining > 0)\r
+ { \r
+ str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = (buffer + bytes_written);\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ \r
+ /* small delay before polling */\r
+ jtag_add_sleep(50);\r
+ \r
+ str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
+ \r
+ do {\r
+ field.device = chain_pos;\r
+ field.num_bits = 8;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = scanbuf;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, -1, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ status = buf_get_u32(scanbuf, 0, 8);\r
+ \r
+ } while(!(status & ISC_STATUS_BUSY));\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)\r
+ // return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ dwords_remaining--;\r
+ bytes_written += 8;\r
+ }\r
+ }\r
+ \r
+ if (bytes_remaining)\r
+ {\r
+ u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
+ int i = 0;\r
+ \r
+ while(bytes_remaining > 0)\r
+ {\r
+ last_dword[i++] = *(buffer + bytes_written); \r
+ bytes_remaining--;\r
+ bytes_written++;\r
+ }\r
+ \r
+ str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = last_dword;\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ \r
+ /* small delay before polling */\r
+ jtag_add_sleep(50);\r
+ \r
+ str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
+ \r
+ do {\r
+ field.device = chain_pos;\r
+ field.num_bits = 8;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = scanbuf;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, -1, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ status = buf_get_u32(scanbuf, 0, 8);\r
+ \r
+ } while(!(status & ISC_STATUS_BUSY));\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)\r
+ // return ERROR_FLASH_OPERATION_FAILED;\r
+ }\r
+\r
+ free(scanbuf);\r
+\r
+ str9xpec_isc_disable(bank);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_probe(struct flash_bank_s *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ scan_field_t field;\r
+ u8 *buffer = NULL;\r
+ u32 chain_pos;\r
+ u32 idcode;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+\r
+ if (argc < 1)\r
+ {\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\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
+ str9xpec_info = bank->driver_priv;\r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ buffer = calloc(CEIL(32, 8), 1);\r
+ \r
+ str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 32;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = buffer;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ idcode = buf_get_u32(buffer, 0, 32);\r
+ \r
+ command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode);\r
+ \r
+ free(buffer);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_erase_check(struct flash_bank_s *bank)\r
+{\r
+ return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);\r
+}\r
+\r
+int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
+{\r
+ snprintf(buf, buf_size, "str9xpec flash driver info" );\r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ u8 status;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec options_read <bank>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ status = str9xpec_read_config(bank);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ /* boot bank */\r
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))\r
+ command_print(cmd_ctx, "CS Map: bank1");\r
+ else\r
+ command_print(cmd_ctx, "CS Map: bank0");\r
+ \r
+ /* OTP lock */\r
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))\r
+ command_print(cmd_ctx, "OTP Lock: OTP Locked");\r
+ else\r
+ command_print(cmd_ctx, "OTP Lock: OTP Unlocked");\r
+ \r
+ /* LVD Threshold */\r
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))\r
+ command_print(cmd_ctx, "LVD Threshold: 2.7v");\r
+ else\r
+ command_print(cmd_ctx, "LVD Threshold: 2.4v");\r
+ \r
+ /* LVD reset warning */\r
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))\r
+ command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs");\r
+ else\r
+ command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only");\r
+ \r
+ /* LVD reset select */\r
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))\r
+ command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs");\r
+ else\r
+ command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only");\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_write_options(struct flash_bank_s *bank)\r
+{\r
+ scan_field_t field;\r
+ u8 status;\r
+ u32 chain_pos;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ str9xpec_info = bank->driver_priv;\r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ /* erase config options first */\r
+ status = str9xpec_erase_area( bank, 0xFE, 0xFE );\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return status; \r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ str9xpec_isc_enable( bank );\r
+ }\r
+ \r
+ if (!str9xpec_info->isc_enable) {\r
+ return ISC_STATUS_ERROR;\r
+ }\r
+ \r
+ /* according to data 64th bit has to be set */\r
+ buf_set_u32(str9xpec_info->options, 63, 1, 1);\r
+ \r
+ /* set option byte address */\r
+ str9xpec_set_address(bank, 0x50);\r
+ \r
+ /* execute ISC_PROGRAM command */\r
+ str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);\r
+ \r
+ field.device = chain_pos;\r
+ field.num_bits = 64;\r
+ field.out_value = str9xpec_info->options;\r
+ field.out_mask = NULL;\r
+ field.in_value = NULL;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, TAP_RTI, NULL);\r
+ \r
+ /* small delay before polling */\r
+ jtag_add_sleep(50);\r
+ \r
+ str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
+ \r
+ do {\r
+ field.device = chain_pos;\r
+ field.num_bits = 8;\r
+ field.out_value = NULL;\r
+ field.out_mask = NULL;\r
+ field.in_value = &status;\r
+ field.in_check_value = NULL;\r
+ field.in_check_mask = NULL;\r
+ field.in_handler = NULL;\r
+ field.in_handler_priv = NULL;\r
+ \r
+ jtag_add_dr_scan(1, &field, -1, NULL);\r
+ jtag_execute_queue();\r
+ \r
+ } while(!(status & ISC_STATUS_BUSY));\r
+ \r
+ str9xpec_isc_disable(bank);\r
+ \r
+ return status;\r
+}\r
+\r
+int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ u8 status;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec options_write <bank>");\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
+ status = str9xpec_write_options(bank);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 2)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec options_cmap <bank> <bank0|bank1>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ if (strcmp(args[1], "bank1") == 0)\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);\r
+ }\r
+ else\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 2)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec options_lvdthd <bank> <2.4v|2.7v>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ if (strcmp(args[1], "2.7v") == 0)\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);\r
+ }\r
+ else\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 2)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec options_lvdsel <bank> <vdd|vdd_vddq>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ if (strcmp(args[1], "vdd_vddq") == 0)\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);\r
+ }\r
+ else\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 2)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec options_lvdwarn <bank> <vdd|vdd_vddq>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ if (strcmp(args[1], "vdd_vddq") == 0)\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);\r
+ }\r
+ else\r
+ {\r
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ u8 status;\r
+ flash_bank_t *bank;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec lock <bank>");\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
+ status = str9xpec_lock_device(bank);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ u8 status;\r
+ flash_bank_t *bank;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec unlock <bank>");\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
+ status = str9xpec_unlock_device(bank);\r
+ \r
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
+ return ERROR_FLASH_OPERATION_FAILED;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ u32 chain_pos;\r
+ jtag_device_t* dev0;\r
+ jtag_device_t* dev2;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec enable_turbo <bank>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ /* remove arm core from chain - enter turbo mode */\r
+ \r
+ str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI);\r
+ jtag_execute_queue();\r
+ \r
+ /* modify scan chain - str9 core has been removed */\r
+ dev0 = jtag_get_device(chain_pos);\r
+ str9xpec_info->devarm = jtag_get_device(chain_pos+1);\r
+ dev2 = jtag_get_device(chain_pos+2);\r
+ dev0->next = dev2;\r
+ jtag_num_devices--;\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ flash_bank_t *bank;\r
+ u32 chain_pos;\r
+ jtag_device_t* dev0;\r
+ str9xpec_flash_controller_t *str9xpec_info = NULL;\r
+ \r
+ if (argc < 1)\r
+ {\r
+ command_print(cmd_ctx, "str9xpec disable_turbo <bank>");\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
+ str9xpec_info = bank->driver_priv;\r
+ \r
+ chain_pos = str9xpec_info->chain_pos;\r
+ \r
+ dev0 = jtag_get_device(chain_pos);\r
+ \r
+ /* exit turbo mode via TLR */\r
+ str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR);\r
+ jtag_execute_queue();\r
+ \r
+ /* restore previous scan chain */\r
+ if( str9xpec_info->devarm ) {\r
+ dev0->next = str9xpec_info->devarm;\r
+ jtag_num_devices++;\r
+ str9xpec_info->devarm = NULL;\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "interpreter.h"
-#include "configuration.h"
-
-#include "binarybuffer.h"
-#include <stdlib.h>
-#include <string.h>
-
-var_t *variables = NULL;
-
-int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int interpreter_register_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "var", handle_var_command,
- COMMAND_ANY, "allocate, display or delete variable <name> [num_fields|'del'] [size1] ...");
- register_command(cmd_ctx, NULL, "field", handle_field_command,
- COMMAND_ANY, "display/modify variable field <var> <field> [value|'flip']");
- register_command(cmd_ctx, NULL, "script", handle_script_command,
- COMMAND_ANY, "execute commands from <file>");
-
- return ERROR_OK;
-}
-
-var_t* get_var_by_num(int num)
-{
- int count = 0;
- var_t *var = variables;
-
- if (var)
- {
- if (num == count)
- return var;
- while (var->next)
- {
- var = var->next;
- count++;
- if (num == count)
- return var;
- }
- }
- return NULL;
-}
-
-var_t* get_var_by_name(char *name)
-{
- var_t *var = variables;
-
- if (var)
- {
- if (strcmp(var->name, name) == 0)
- return var;
- while (var->next)
- {
- var = var->next;
- if (strcmp(var->name, name) == 0)
- return var;
- }
- }
- return NULL;
-}
-
-var_t* get_var_by_namenum(char *namenum)
-{
- if ((namenum[0] >= '0') && (namenum[0] <= '9'))
- return get_var_by_num(strtol(namenum, NULL, 0));
- else
- return get_var_by_name(namenum);
-
-}
-
-int field_le_to_host(u8 *buffer, void *priv, struct scan_field_s *dummy)
-{
- var_field_t *field = priv;
- field->value = buf_get_u32(buffer, 0, field->num_bits);
-
- return ERROR_OK;
-}
-
-int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- var_t **last_var_p = &variables;
- int i;
-
- if (argc >= 2)
- {
- while (*last_var_p)
- {
- if (strcmp((*last_var_p)->name, args[0]) == 0)
- {
- if (strcmp(args[1], "del") == 0)
- {
- var_t *next = (*last_var_p)->next;
- free ((*last_var_p)->fields);
- free (*last_var_p);
- *last_var_p = next;
- command_print(cmd_ctx, "variable %s deleted", args[0]);
- }
- else
- command_print(cmd_ctx, "variable of that name already exists");
- return ERROR_OK;
- }
- last_var_p = &((*last_var_p)->next);
- }
-
- if ((args[0][0] >= '0') && (args[0][0] <= '9'))
- {
- command_print(cmd_ctx, "invalid name specified (first character may not be a number)");
- return ERROR_OK;
- }
-
- *last_var_p = malloc(sizeof(var_t));
- (*last_var_p)->name = strdup(args[0]);
- (*last_var_p)->num_fields = argc - 1;
- (*last_var_p)->next = NULL;
-
- (*last_var_p)->fields = malloc(sizeof(var_field_t) * (*last_var_p)->num_fields);
- for (i = 0; i < (*last_var_p)->num_fields; i++)
- {
- (*last_var_p)->fields[i].num_bits = strtol(args[1+i], NULL, 0);
- (*last_var_p)->fields[i].value = 0x0;
- }
- return ERROR_OK;
- }
-
- if (argc == 1)
- {
- var_t *var = get_var_by_namenum(args[0]);
- if (var)
- {
- int i;
- command_print(cmd_ctx, "%s (%i fields):", var->name, var->num_fields);
- for (i = 0; i < (var->num_fields); i++)
- {
- command_print(cmd_ctx, "0x%x (/%i)", var->fields[i].value, var->fields[i].num_bits);
- }
- }
- else
- {
- command_print(cmd_ctx, "variable %s doesn't exist", args[0]);
- }
- }
-
- if (argc == 0)
- {
- var_t *var = variables;
- int count = 0;
- while (var)
- {
- command_print(cmd_ctx, "%i: %s (%i fields)", count, var->name, var->num_fields);
- var = var->next;
- count++;
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-
- if (argc < 2)
- command_print(cmd_ctx, "usage: field <var> <field> [value|'flip']");
-
- if (argc >= 2)
- {
- var_t *var = get_var_by_namenum(args[0]);
- int field_num = strtol(args[1], NULL, 0);
- if (!var)
- {
- command_print(cmd_ctx, "variable %s doesn't exist", args[0]);
- return ERROR_OK;
- }
- if (field_num >= var->num_fields)
- command_print(cmd_ctx, "variable field %i is out of bounds (max. %i)", field_num, var->num_fields - 1);
- if ((var) && (field_num < var->num_fields))
- {
- if (argc > 2)
- {
- if (strcmp(args[2], "flip") == 0)
- var->fields[field_num].value = flip_u32(var->fields[field_num].value, var->fields[field_num].num_bits);
- else
- var->fields[field_num].value = strtoul(args[2], NULL, 0);
- }
-
- command_print(cmd_ctx, "%s(%i): 0x%x (/%i)", var->name, field_num, var->fields[field_num].value, var->fields[field_num].num_bits);
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- FILE *script_file;
- int echo;
-
- if (argc != 1)
- command_print(cmd_ctx, "usage: script <file>");
-
- script_file = open_file_from_path(cmd_ctx, args[0], "r");
-
- if (!script_file)
- {
- command_print(cmd_ctx, "couldn't open script file %s", args[0]);
- return ERROR_OK;
- }
-
- echo = cmd_ctx->echo;
- cmd_ctx->echo = 1;
-
- command_run_file(cmd_ctx, script_file, cmd_ctx->mode);
-
- cmd_ctx->echo = echo;
-
- fclose(script_file);
-
- 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 "interpreter.h"\r
+#include "configuration.h"\r
+\r
+#include "binarybuffer.h"\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+var_t *variables = NULL;\r
+\r
+int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+int interpreter_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ register_command(cmd_ctx, NULL, "var", handle_var_command,\r
+ COMMAND_ANY, "allocate, display or delete variable <name> [num_fields|'del'] [size1] ...");\r
+ register_command(cmd_ctx, NULL, "field", handle_field_command,\r
+ COMMAND_ANY, "display/modify variable field <var> <field> [value|'flip']");\r
+ register_command(cmd_ctx, NULL, "script", handle_script_command,\r
+ COMMAND_ANY, "execute commands from <file>");\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+var_t* get_var_by_num(int num)\r
+{\r
+ int count = 0;\r
+ var_t *var = variables;\r
+\r
+ if (var) \r
+ {\r
+ if (num == count)\r
+ return var;\r
+ while (var->next)\r
+ {\r
+ var = var->next;\r
+ count++;\r
+ if (num == count)\r
+ return var;\r
+ }\r
+ }\r
+ return NULL;\r
+}\r
+\r
+var_t* get_var_by_name(char *name)\r
+{\r
+ var_t *var = variables;\r
+\r
+ if (var) \r
+ {\r
+ if (strcmp(var->name, name) == 0)\r
+ return var;\r
+ while (var->next)\r
+ {\r
+ var = var->next;\r
+ if (strcmp(var->name, name) == 0)\r
+ return var;\r
+ }\r
+ }\r
+ return NULL;\r
+}\r
+\r
+var_t* get_var_by_namenum(char *namenum)\r
+{\r
+ if ((namenum[0] >= '0') && (namenum[0] <= '9'))\r
+ return get_var_by_num(strtol(namenum, NULL, 0));\r
+ else\r
+ return get_var_by_name(namenum);\r
+ \r
+}\r
+\r
+int field_le_to_host(u8 *buffer, void *priv, struct scan_field_s *dummy)\r
+{\r
+ var_field_t *field = priv;\r
+ field->value = buf_get_u32(buffer, 0, field->num_bits);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ var_t **last_var_p = &variables;\r
+ int i;\r
+\r
+ if (argc >= 2)\r
+ {\r
+ while (*last_var_p)\r
+ {\r
+ if (strcmp((*last_var_p)->name, args[0]) == 0)\r
+ {\r
+ if (strcmp(args[1], "del") == 0)\r
+ {\r
+ var_t *next = (*last_var_p)->next;\r
+ free ((*last_var_p)->fields);\r
+ free (*last_var_p);\r
+ *last_var_p = next;\r
+ command_print(cmd_ctx, "variable %s deleted", args[0]);\r
+ }\r
+ else\r
+ command_print(cmd_ctx, "variable of that name already exists");\r
+ return ERROR_OK;\r
+ }\r
+ last_var_p = &((*last_var_p)->next);\r
+ }\r
+\r
+ if ((args[0][0] >= '0') && (args[0][0] <= '9'))\r
+ {\r
+ command_print(cmd_ctx, "invalid name specified (first character may not be a number)");\r
+ return ERROR_OK;\r
+ }\r
+\r
+ *last_var_p = malloc(sizeof(var_t));\r
+ (*last_var_p)->name = strdup(args[0]);\r
+ (*last_var_p)->num_fields = argc - 1;\r
+ (*last_var_p)->next = NULL;\r
+\r
+ (*last_var_p)->fields = malloc(sizeof(var_field_t) * (*last_var_p)->num_fields);\r
+ for (i = 0; i < (*last_var_p)->num_fields; i++)\r
+ {\r
+ (*last_var_p)->fields[i].num_bits = strtol(args[1+i], NULL, 0);\r
+ (*last_var_p)->fields[i].value = 0x0;\r
+ }\r
+ return ERROR_OK;\r
+ }\r
+\r
+ if (argc == 1)\r
+ {\r
+ var_t *var = get_var_by_namenum(args[0]);\r
+ if (var)\r
+ {\r
+ int i;\r
+ command_print(cmd_ctx, "%s (%i fields):", var->name, var->num_fields);\r
+ for (i = 0; i < (var->num_fields); i++)\r
+ {\r
+ command_print(cmd_ctx, "0x%x (/%i)", var->fields[i].value, var->fields[i].num_bits);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ command_print(cmd_ctx, "variable %s doesn't exist", args[0]);\r
+ }\r
+ }\r
+\r
+ if (argc == 0)\r
+ {\r
+ var_t *var = variables;\r
+ int count = 0;\r
+ while (var)\r
+ {\r
+ command_print(cmd_ctx, "%i: %s (%i fields)", count, var->name, var->num_fields);\r
+ var = var->next;\r
+ count++;\r
+ }\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+\r
+ if (argc < 2)\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ if (argc >= 2)\r
+ {\r
+ var_t *var = get_var_by_namenum(args[0]);\r
+ int field_num = strtol(args[1], NULL, 0);\r
+ if (!var)\r
+ {\r
+ command_print(cmd_ctx, "variable %s doesn't exist", args[0]);\r
+ return ERROR_OK;\r
+ }\r
+ if (field_num >= var->num_fields)\r
+ command_print(cmd_ctx, "variable field %i is out of bounds (max. %i)", field_num, var->num_fields - 1);\r
+ if ((var) && (field_num < var->num_fields))\r
+ {\r
+ if (argc > 2)\r
+ {\r
+ if (strcmp(args[2], "flip") == 0)\r
+ var->fields[field_num].value = flip_u32(var->fields[field_num].value, var->fields[field_num].num_bits);\r
+ else\r
+ var->fields[field_num].value = strtoul(args[2], NULL, 0);\r
+ }\r
+\r
+ command_print(cmd_ctx, "%s(%i): 0x%x (/%i)", var->name, field_num, var->fields[field_num].value, var->fields[field_num].num_bits);\r
+ }\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ FILE *script_file;\r
+ int echo;\r
+\r
+ if (argc != 1)\r
+ return ERROR_COMMAND_SYNTAX_ERROR;\r
+\r
+ script_file = open_file_from_path(cmd_ctx, args[0], "r");\r
+\r
+ if (!script_file)\r
+ {\r
+ command_print(cmd_ctx, "couldn't open script file %s", args[0]);\r
+ return ERROR_OK;\r
+ }\r
+\r
+ echo = cmd_ctx->echo;\r
+ cmd_ctx->echo = 1;\r
+ \r
+ command_run_file(cmd_ctx, script_file, cmd_ctx->mode);\r
+ \r
+ cmd_ctx->echo = echo;\r
+ \r
+ fclose(script_file);\r
+\r
+ return ERROR_OK;\r
+}\r
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "gdb_server.h"
-
-#include "server.h"
-#include "log.h"
-#include "binarybuffer.h"
-#include "jtag.h"
-#include "breakpoints.h"
-#include "flash.h"
-#include "target_request.h"
-#include "configuration.h"
-
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#if 0
-#define _DEBUG_GDB_IO_
-#endif
-
-static unsigned short gdb_port;
-static const char *DIGITS = "0123456789abcdef";
-
-static void gdb_log_callback(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args);
-
-enum gdb_detach_mode
-{
- GDB_DETACH_RESUME,
- GDB_DETACH_RESET,
- GDB_DETACH_HALT,
- GDB_DETACH_NOTHING
-};
-
-/* target behaviour on gdb detach */
-enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME;
-
-/* set if we are sending a memory map to gdb
- * via qXfer:memory-map:read packet */
-int gdb_use_memory_map = 0;
-int gdb_flash_program = 0;
-
-/* if set, data aborts cause an error to be reported in memory read packets
- * see the code in gdb_read_memory_packet() for further explanations */
-int gdb_report_data_abort = 0;
-
-int gdb_last_signal(target_t *target)
-{
- switch (target->debug_reason)
- {
- case DBG_REASON_DBGRQ:
- return 0x2; /* SIGINT */
- case DBG_REASON_BREAKPOINT:
- case DBG_REASON_WATCHPOINT:
- case DBG_REASON_WPTANDBKPT:
- return 0x05; /* SIGTRAP */
- case DBG_REASON_SINGLESTEP:
- return 0x05; /* SIGTRAP */
- case DBG_REASON_NOTHALTED:
- return 0x0; /* no signal... shouldn't happen */
- default:
- ERROR("BUG: undefined debug reason");
- exit(-1);
- }
-}
-
-int gdb_get_char(connection_t *connection, int* next_char)
-{
- gdb_connection_t *gdb_con = connection->priv;
-
-#ifdef _DEBUG_GDB_IO_
- char *debug_buffer;
-#endif
-
- if (gdb_con->buf_cnt-- > 0)
- {
- *next_char = *(gdb_con->buf_p++);
- if (gdb_con->buf_cnt > 0)
- connection->input_pending = 1;
- else
- connection->input_pending = 0;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
- return ERROR_OK;
- }
-
- for (;;)
- {
-#ifndef _WIN32
- /* a non-blocking socket will block if there is 0 bytes available on the socket,
- * but return with as many bytes as are available immediately
- */
- struct timeval tv;
- fd_set read_fds;
-
- FD_ZERO(&read_fds);
- FD_SET(connection->fd, &read_fds);
-
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)
- {
- /* This can typically be because a "monitor" command took too long
- * before printing any progress messages
- */
- return ERROR_GDB_TIMEOUT;
- }
-#endif
- gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
- if (gdb_con->buf_cnt > 0)
- {
- break;
- }
- if (gdb_con->buf_cnt == 0)
- {
- gdb_con->closed = 1;
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
-#ifdef _WIN32
- errno = WSAGetLastError();
-
- switch(errno)
- {
- case WSAEWOULDBLOCK:
- usleep(1000);
- break;
- case WSAECONNABORTED:
- return ERROR_SERVER_REMOTE_CLOSED;
- case WSAECONNRESET:
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- ERROR("read: %d", errno);
- exit(-1);
- }
-#else
- switch(errno)
- {
- case EAGAIN:
- usleep(1000);
- break;
- case ECONNABORTED:
- return ERROR_SERVER_REMOTE_CLOSED;
- case ECONNRESET:
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- ERROR("read: %s", strerror(errno));
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-#endif
- }
-
-#ifdef _DEBUG_GDB_IO_
- debug_buffer = malloc(gdb_con->buf_cnt + 1);
- memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);
- debug_buffer[gdb_con->buf_cnt] = 0;
- DEBUG("received '%s'", debug_buffer);
- free(debug_buffer);
-#endif
-
- gdb_con->buf_p = gdb_con->buffer;
- gdb_con->buf_cnt--;
- *next_char = *(gdb_con->buf_p++);
- if (gdb_con->buf_cnt > 0)
- connection->input_pending = 1;
- else
- connection->input_pending = 0;
-#ifdef _DEBUG_GDB_IO_
- DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
- return ERROR_OK;
-}
-
-int gdb_putback_char(connection_t *connection, int last_char)
-{
- gdb_connection_t *gdb_con = connection->priv;
-
- if (gdb_con->buf_p > gdb_con->buffer)
- {
- *(--gdb_con->buf_p) = last_char;
- gdb_con->buf_cnt++;
- }
- else
- {
- ERROR("BUG: couldn't put character back");
- }
-
- return ERROR_OK;
-}
-
-/* The only way we can detect that the socket is closed is the first time
- * we write to it, we will fail. Subsequent write operations will
- * succeed. Shudder! */
-int gdb_write(connection_t *connection, void *data, int len)
-{
- gdb_connection_t *gdb_con = connection->priv;
- if (gdb_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- if (write_socket(connection->fd, data, len) == len)
- {
- return ERROR_OK;
- }
- gdb_con->closed = 1;
- return ERROR_SERVER_REMOTE_CLOSED;
-}
-
-int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
-{
- int i;
- unsigned char my_checksum = 0;
-#ifdef _DEBUG_GDB_IO_
- char *debug_buffer;
-#endif
- int reply;
- int retval;
- gdb_connection_t *gdb_con = connection->priv;
-
- for (i = 0; i < len; i++)
- my_checksum += buffer[i];
-
- while (1)
- {
-#ifdef _DEBUG_GDB_IO_
- debug_buffer = malloc(len + 1);
- memcpy(debug_buffer, buffer, len);
- debug_buffer[len] = 0;
- DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
- free(debug_buffer);
-#endif
-#if 0
- char checksum[3];
- gdb_write(connection, "$", 1);
- if (len > 0)
- gdb_write(connection, buffer, len);
- gdb_write(connection, "#", 1);
-
- snprintf(checksum, 3, "%2.2x", my_checksum);
-
- gdb_write(connection, checksum, 2);
-#else
- void *allocated = NULL;
- char stackAlloc[1024];
- char *t = stackAlloc;
- int totalLen = 1 + len + 1 + 2;
- if (totalLen > sizeof(stackAlloc))
- {
- allocated = malloc(totalLen);
- t = allocated;
- if (allocated == NULL)
- {
- ERROR("Ran out of memory trying to reply packet %d\n", totalLen);
- exit(-1);
- }
- }
- t[0] = '$';
- memcpy(t + 1, buffer, len);
- t[1 + len] = '#';
- t[1 + len + 1] = DIGITS[(my_checksum >> 4) & 0xf];
- t[1 + len + 2] = DIGITS[my_checksum & 0xf];
-
- gdb_write(connection, t, totalLen);
-
- if (allocated)
- {
- free(allocated);
- }
-#endif
- if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
- return retval;
-
- if (reply == '+')
- break;
- else if (reply == '-')
- {
- /* Stop sending output packets for now */
- log_setCallback(NULL, NULL);
- WARNING("negative reply, retrying");
- }
- else if (reply == 0x3)
- {
- gdb_con->ctrl_c = 1;
- if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
- return retval;
- if (reply == '+')
- break;
- else if (reply == '-')
- {
- /* Stop sending output packets for now */
- log_setCallback(NULL, NULL);
- WARNING("negative reply, retrying");
- }
- else
- {
- ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- }
- else
- {
- ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- }
- if (gdb_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- return ERROR_OK;
-}
-
-int gdb_put_packet(connection_t *connection, char *buffer, int len)
-{
- gdb_connection_t *gdb_con = connection->priv;
- gdb_con->busy = 1;
- int retval = gdb_put_packet_inner(connection, buffer, len);
- gdb_con->busy = 0;
- return retval;
-}
-
-int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
-{
- int character;
- int count = 0;
- int retval;
- char checksum[3];
- unsigned char my_checksum = 0;
- gdb_connection_t *gdb_con = connection->priv;
-
- while (1)
- {
- do
- {
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("character: '%c'", character);
-#endif
-
- switch (character)
- {
- case '$':
- break;
- case '+':
- WARNING("acknowledgment received, but no packet pending");
- break;
- case '-':
- WARNING("negative acknowledgment, but no packet pending");
- break;
- case 0x3:
- gdb_con->ctrl_c = 1;
- *len = 0;
- return ERROR_OK;
- default:
- WARNING("ignoring character 0x%x", character);
- break;
- }
- } while (character != '$');
-
- my_checksum = 0;
-
- count = 0;
- gdb_connection_t *gdb_con = connection->priv;
- for (;;)
- {
- /* The common case is that we have an entire packet with no escape chars.
- * We need to leave at least 2 bytes in the buffer to have
- * gdb_get_char() update various bits and bobs correctly.
- */
- if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))
- {
- /* The compiler will struggle a bit with constant propagation and
- * aliasing, so we help it by showing that these values do not
- * change inside the loop
- */
- int i;
- char *buf = gdb_con->buf_p;
- int run = gdb_con->buf_cnt - 2;
- i = 0;
- int done = 0;
- while (i < run)
- {
- character = *buf++;
- i++;
- if (character == '#')
- {
- /* Danger! character can be '#' when esc is
- * used so we need an explicit boolean for done here.
- */
- done = 1;
- break;
- }
-
- if (character == '}')
- {
- /* data transmitted in binary mode (X packet)
- * uses 0x7d as escape character */
- my_checksum += character & 0xff;
- character = *buf++;
- i++;
- my_checksum += character & 0xff;
- buffer[count++] = (character ^ 0x20) & 0xff;
- } else
- {
- my_checksum += character & 0xff;
- buffer[count++] = character & 0xff;
- }
- }
- gdb_con->buf_p += i;
- gdb_con->buf_cnt -= i;
- if (done)
- break;
- }
- if (count > *len)
- {
- ERROR("packet buffer too small");
- return ERROR_GDB_BUFFER_TOO_SMALL;
- }
-
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
-
- if (character == '#')
- break;
-
- if (character == '}')
- {
- /* data transmitted in binary mode (X packet)
- * uses 0x7d as escape character */
- my_checksum += character & 0xff;
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
- my_checksum += character & 0xff;
- buffer[count++] = (character ^ 0x20) & 0xff;
- }
- else
- {
- my_checksum += character & 0xff;
- buffer[count++] = character & 0xff;
- }
-
- }
-
- *len = count;
-
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
- checksum[0] = character;
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
- checksum[1] = character;
- checksum[2] = 0;
-
- if (my_checksum == strtoul(checksum, NULL, 16))
- {
- gdb_write(connection, "+", 1);
- break;
- }
-
- WARNING("checksum error, requesting retransmission");
- gdb_write(connection, "-", 1);
- }
- if (gdb_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- return ERROR_OK;
-}
-
-int gdb_get_packet(connection_t *connection, char *buffer, int *len)
-{
- gdb_connection_t *gdb_con = connection->priv;
- gdb_con->busy = 1;
- int retval = gdb_get_packet_inner(connection, buffer, len);
- gdb_con->busy = 0;
- return retval;
-}
-
-int gdb_output_con(connection_t *connection, char* line)
-{
- char *hex_buffer;
- int i, bin_size;
-
- bin_size = strlen(line);
-
- hex_buffer = malloc(bin_size*2 + 4);
-
- hex_buffer[0] = 'O';
- for (i=0; i<bin_size; i++)
- snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);
- hex_buffer[bin_size*2+1] = '0';
- hex_buffer[bin_size*2+2] = 'a';
- hex_buffer[bin_size*2+3] = 0x0;
-
- gdb_put_packet(connection, hex_buffer, bin_size*2 + 3);
-
- free(hex_buffer);
- return ERROR_OK;
-}
-
-int gdb_output(struct command_context_s *context, char* line)
-{
- /* this will be dumped to the log and also sent as an O packet if possible */
- USER(line);
- return ERROR_OK;
-}
-
-int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
-{
- FILE *script;
- struct command_context_s *cmd_ctx = priv;
-
- if (target->gdb_program_script)
- {
- script = open_file_from_path(cmd_ctx, target->gdb_program_script, "r");
- if (!script)
- {
- ERROR("couldn't open script file %s", target->gdb_program_script);
- return ERROR_OK;
- }
-
- INFO("executing gdb_program script '%s'", target->gdb_program_script);
- command_run_file(cmd_ctx, script, COMMAND_EXEC);
- fclose(script);
-
- jtag_execute_queue();
- }
-
- return ERROR_OK;
-}
-
-int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
-{
- connection_t *connection = priv;
- gdb_connection_t *gdb_connection = connection->priv;
- char sig_reply[4];
- int signal;
-
- switch (event)
- {
- case TARGET_EVENT_HALTED:
- /* In the GDB protocol when we are stepping or coninuing execution,
- * we have a lingering reply. Upon receiving a halted event
- * when we have that lingering packet, we reply to the original
- * step or continue packet.
- *
- * Executing monitor commands can bring the target in and
- * out of the running state so we'll see lots of TARGET_EVENT_XXX
- * that are to be ignored.
- */
- if (gdb_connection->frontend_state == TARGET_RUNNING)
- {
- /* stop forwarding log packets! */
- log_setCallback(NULL, NULL);
-
- if (gdb_connection->ctrl_c)
- {
- signal = 0x2;
- gdb_connection->ctrl_c = 0;
- }
- else
- {
- signal = gdb_last_signal(target);
- }
-
- snprintf(sig_reply, 4, "T%2.2x", signal);
- gdb_put_packet(connection, sig_reply, 3);
- gdb_connection->frontend_state = TARGET_HALTED;
- }
- break;
- case TARGET_EVENT_GDB_PROGRAM:
- gdb_program_handler(target, event, connection->cmd_ctx);
- break;
- default:
- break;
- }
-
- return ERROR_OK;
-}
-
-int gdb_new_connection(connection_t *connection)
-{
- gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));
- gdb_service_t *gdb_service = connection->service->priv;
- int retval;
- int initial_ack;
-
- connection->priv = gdb_connection;
-
- /* initialize gdb connection information */
- gdb_connection->buf_p = gdb_connection->buffer;
- gdb_connection->buf_cnt = 0;
- gdb_connection->ctrl_c = 0;
- gdb_connection->frontend_state = TARGET_HALTED;
- gdb_connection->vflash_image = NULL;
- gdb_connection->closed = 0;
- gdb_connection->busy = 0;
-
- /* output goes through gdb connection */
- command_set_output_handler(connection->cmd_ctx, gdb_output, connection);
-
- /* register callback to be informed about target events */
- target_register_event_callback(gdb_target_callback_event_handler, connection);
-
- /* a gdb session just attached, put the target in halt mode */
- if (((retval = gdb_service->target->type->halt(gdb_service->target)) != ERROR_OK) &&
- (retval != ERROR_TARGET_ALREADY_HALTED))
- {
- ERROR("error(%d) when trying to halt target, falling back to \"reset halt\"", retval);
- command_run_line(connection->cmd_ctx, "reset halt");
- }
-
- /* This will time out after 1 second */
- command_run_line(connection->cmd_ctx, "wait_halt 1");
-
- /* remove the initial ACK from the incoming buffer */
- if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
- return retval;
-
- if (initial_ack != '+')
- gdb_putback_char(connection, initial_ack);
-
- return ERROR_OK;
-}
-
-int gdb_connection_closed(connection_t *connection)
-{
- gdb_service_t *gdb_service = connection->service->priv;
- gdb_connection_t *gdb_connection = connection->priv;
-
- /* see if an image built with vFlash commands is left */
- if (gdb_connection->vflash_image)
- {
- image_close(gdb_connection->vflash_image);
- free(gdb_connection->vflash_image);
- gdb_connection->vflash_image = NULL;
- }
-
- /* if this connection registered a debug-message receiver delete it */
- delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);
-
- if (connection->priv)
- {
- free(connection->priv);
- connection->priv = NULL;
- }
- else
- {
- ERROR("BUG: connection->priv == NULL");
- }
-
- target_unregister_event_callback(gdb_target_callback_event_handler, connection);
- log_setCallback(NULL, NULL);
-
- return ERROR_OK;
-}
-
-void gdb_send_error(connection_t *connection, u8 the_error)
-{
- char err[4];
- snprintf(err, 4, "E%2.2X", the_error );
- gdb_put_packet(connection, err, 3);
-}
-
-int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
-{
- char sig_reply[4];
- int signal;
-
- signal = gdb_last_signal(target);
-
- snprintf(sig_reply, 4, "S%2.2x", signal);
- gdb_put_packet(connection, sig_reply, 3);
-
- return ERROR_OK;
-}
-
-/* Convert register to string of bits. NB! The # of bits in the
- * register might be non-divisible by 8(a byte), in which
- * case an entire byte is shown. */
-void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
-{
- int i;
-
- u8 *buf;
- int buf_len;
- buf = reg->value;
- buf_len = CEIL(reg->size, 8);
-
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- {
- for (i = 0; i < buf_len; i++)
- {
- tstr[i*2] = DIGITS[(buf[i]>>4) & 0xf];
- tstr[i*2+1] = DIGITS[buf[i]&0xf];
- }
- }
- else
- {
- for (i = 0; i < buf_len; i++)
- {
- tstr[(buf_len-1-i)*2] = DIGITS[(buf[i]>>4)&0xf];
- tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf];
- }
- }
-}
-
-void gdb_target_to_str(target_t *target, char *tstr, char *str)
-{
- int str_len = strlen(tstr);
- int i;
-
- if (str_len % 2)
- {
- ERROR("BUG: gdb value with uneven number of characters encountered");
- exit(-1);
- }
-
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- {
- for (i = 0; i < str_len; i+=2)
- {
- str[str_len - i - 1] = tstr[i + 1];
- str[str_len - i - 2] = tstr[i];
- }
- }
- else
- {
- for (i = 0; i < str_len; i++)
- {
- str[i] = tstr[i];
- }
- }
-}
-
-int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
-{
- reg_t **reg_list;
- int reg_list_size;
- int retval;
- int reg_packet_size = 0;
- char *reg_packet;
- char *reg_packet_p;
- int i;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("-");
-#endif
-
- if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- ERROR("gdb requested registers but we're not halted, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- /* this is a bug condition - get_gdb_reg_list() may not return any other error */
- ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
- exit(-1);
- }
- }
-
- for (i = 0; i < reg_list_size; i++)
- {
- reg_packet_size += reg_list[i]->size;
- }
-
- reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);
- reg_packet_p = reg_packet;
-
- for (i = 0; i < reg_list_size; i++)
- {
- gdb_str_to_target(target, reg_packet_p, reg_list[i]);
- reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
- }
-
-#ifdef _DEBUG_GDB_IO_
- {
- char *reg_packet_p;
- reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);
- DEBUG("reg_packet: %s", reg_packet_p);
- free(reg_packet_p);
- }
-#endif
-
- gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
- free(reg_packet);
-
- free(reg_list);
-
- return ERROR_OK;
-}
-
-int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- int i;
- reg_t **reg_list;
- int reg_list_size;
- int retval;
- char *packet_p;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("-");
-#endif
-
- /* skip command character */
- packet++;
- packet_size--;
-
- if (packet_size % 2)
- {
- WARNING("GDB set_registers packet with uneven characters received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- ERROR("gdb tried to registers but we're not halted, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- /* this is a bug condition - get_gdb_reg_list() may not return any other error */
- ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
- exit(-1);
- }
- }
-
- packet_p = packet;
- for (i = 0; i < reg_list_size; i++)
- {
- u8 *bin_buf;
- char *hex_buf;
- reg_arch_type_t *arch_type;
-
- /* convert from GDB-string (target-endian) to hex-string (big-endian) */
- hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2);
- gdb_target_to_str(target, packet_p, hex_buf);
-
- /* convert hex-string to binary buffer */
- bin_buf = malloc(CEIL(reg_list[i]->size, 8));
- str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16);
-
- /* get register arch_type, and call set method */
- arch_type = register_get_arch_type(reg_list[i]->arch_type);
- if (arch_type == NULL)
- {
- ERROR("BUG: encountered unregistered arch type");
- exit(-1);
- }
- arch_type->set(reg_list[i], bin_buf);
-
- /* advance packet pointer */
- packet_p += (CEIL(reg_list[i]->size, 8) * 2);
-
- free(bin_buf);
- free(hex_buf);
- }
-
- /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */
- free(reg_list);
-
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
-}
-
-int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *reg_packet;
- int reg_num = strtoul(packet + 1, NULL, 16);
- reg_t **reg_list;
- int reg_list_size;
- int retval;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("-");
-#endif
-
- if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- ERROR("gdb requested registers but we're not halted, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- /* this is a bug condition - get_gdb_reg_list() may not return any other error */
- ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
- exit(-1);
- }
- }
-
- if (reg_list_size <= reg_num)
- {
- ERROR("gdb requested a non-existing register");
- exit(-1);
- }
-
- reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
-
- gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
-
- gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
-
- free(reg_list);
- free(reg_packet);
-
- return ERROR_OK;
-}
-
-int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *separator;
- char *hex_buf;
- u8 *bin_buf;
- int reg_num = strtoul(packet + 1, &separator, 16);
- reg_t **reg_list;
- int reg_list_size;
- int retval;
- reg_arch_type_t *arch_type;
-
- DEBUG("-");
-
- if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- ERROR("gdb tried to set a register but we're not halted, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- /* this is a bug condition - get_gdb_reg_list() may not return any other error */
- ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
- exit(-1);
- }
- }
-
- if (reg_list_size < reg_num)
- {
- ERROR("gdb requested a non-existing register");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- if (*separator != '=')
- {
- ERROR("GDB 'set register packet', but no '=' following the register number");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- /* convert from GDB-string (target-endian) to hex-string (big-endian) */
- hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
- gdb_target_to_str(target, separator + 1, hex_buf);
-
- /* convert hex-string to binary buffer */
- bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));
- str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16);
-
- /* get register arch_type, and call set method */
- arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);
- if (arch_type == NULL)
- {
- ERROR("BUG: encountered unregistered arch type");
- exit(-1);
- }
- arch_type->set(reg_list[reg_num], bin_buf);
-
- gdb_put_packet(connection, "OK", 2);
-
- free(bin_buf);
- free(hex_buf);
- free(reg_list);
-
- return ERROR_OK;
-}
-
-int gdb_memory_packet_error(connection_t *connection, int retval)
-{
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- ERROR("gdb tried to read memory but we're not halted, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- case ERROR_TARGET_DATA_ABORT:
- gdb_send_error(connection, EIO);
- break;
- case ERROR_TARGET_TRANSLATION_FAULT:
- gdb_send_error(connection, EFAULT);
- break;
- case ERROR_TARGET_UNALIGNED_ACCESS:
- gdb_send_error(connection, EFAULT);
- break;
- default:
- /* This could be that the target reset itself. */
- ERROR("unexpected error %i. Dropping connection.", retval);
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- return ERROR_OK;
-}
-
-/* We don't have to worry about the default 2 second timeout for GDB packets,
- * because GDB breaks up large memory reads into smaller reads.
- *
- * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
- */
-int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *separator;
- u32 addr = 0;
- u32 len = 0;
-
- u8 *buffer;
- char *hex_buffer;
-
- int retval = ERROR_OK;
-
- /* skip command character */
- packet++;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete read memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator+1, NULL, 16);
-
- buffer = malloc(len);
-
- DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
- retval = target_read_buffer(target, addr, len, buffer);
-
- if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort))
- {
- /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
- * At some point this might be fixed in GDB, in which case this code can be removed.
- *
- * OpenOCD developers are acutely aware of this problem, but there is nothing
- * gained by involving the user in this problem that hopefully will get resolved
- * eventually
- *
- * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395
- *
- * For now, the default is to fix up things to make current GDB versions work.
- * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command.
- */
- memset(buffer, 0, len);
- retval = ERROR_OK;
- }
-
- if (retval == ERROR_OK)
- {
- hex_buffer = malloc(len * 2 + 1);
-
- int i;
- for (i = 0; i < len; i++)
- {
- u8 t = buffer[i];
- hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];
- hex_buffer[2 * i + 1] = DIGITS[t & 0xf];
- }
-
- gdb_put_packet(connection, hex_buffer, len * 2);
-
- free(hex_buffer);
- }
- else
- {
- retval = gdb_memory_packet_error(connection, retval);
- }
-
- free(buffer);
-
- return retval;
-}
-
-int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *separator;
- u32 addr = 0;
- u32 len = 0;
-
- u8 *buffer;
-
- int i;
- int retval;
-
- /* skip command character */
- packet++;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete write memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator+1, &separator, 16);
-
- if (*(separator++) != ':')
- {
- ERROR("incomplete write memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- buffer = malloc(len);
-
- DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
- for (i=0; i<len; i++)
- {
- u32 tmp;
- sscanf(separator + 2*i, "%2x", &tmp);
- buffer[i] = tmp;
- }
-
- retval = target_write_buffer(target, addr, len, buffer);
-
- if (retval == ERROR_OK)
- {
- gdb_put_packet(connection, "OK", 2);
- }
- else
- {
- if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
- return retval;
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *separator;
- u32 addr = 0;
- u32 len = 0;
-
- int retval;
-
- /* skip command character */
- packet++;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete write memory binary packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator+1, &separator, 16);
-
- if (*(separator++) != ':')
- {
- ERROR("incomplete write memory binary packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- retval = ERROR_OK;
- if (len)
- {
- DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
- retval = target_write_buffer(target, addr, len, (u8*)separator);
- }
-
- if (retval == ERROR_OK)
- {
- gdb_put_packet(connection, "OK", 2);
- }
- else
- {
- if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
- return retval;
- }
-
- return ERROR_OK;
-}
-
-void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- int current = 0;
- u32 address = 0x0;
-
- DEBUG("-");
-
- if (packet_size > 1)
- {
- packet[packet_size] = 0;
- address = strtoul(packet + 1, NULL, 16);
- }
- else
- {
- current = 1;
- }
-
- if (packet[0] == 'c')
- {
- DEBUG("continue");
- target->type->resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
- }
- else if (packet[0] == 's')
- {
- DEBUG("step");
- target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */
- }
-}
-
-int gdb_bp_wp_packet_error(connection_t *connection, int retval)
-{
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- break;
- case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
- gdb_send_error(connection, EBUSY);
- break;
- default:
- ERROR("BUG: unexpected error %i", retval);
- exit(-1);
- }
-
- return ERROR_OK;
-}
-
-int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- int type;
- enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;
- enum watchpoint_rw wp_type;
- u32 address;
- u32 size;
- char *separator;
- int retval;
-
- DEBUG("-");
-
- type = strtoul(packet + 1, &separator, 16);
-
- if (type == 0) /* memory breakpoint */
- bp_type = BKPT_SOFT;
- else if (type == 1) /* hardware breakpoint */
- bp_type = BKPT_HARD;
- else if (type == 2) /* write watchpoint */
- wp_type = WPT_WRITE;
- else if (type == 3) /* read watchpoint */
- wp_type = WPT_READ;
- else if (type == 4) /* access watchpoint */
- wp_type = WPT_ACCESS;
-
- if (*separator != ',')
- {
- ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- address = strtoul(separator+1, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- size = strtoul(separator+1, &separator, 16);
-
- switch (type)
- {
- case 0:
- case 1:
- if (packet[0] == 'Z')
- {
- if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)
- {
- if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
- return retval;
- }
- else
- {
- gdb_put_packet(connection, "OK", 2);
- }
- }
- else
- {
- breakpoint_remove(target, address);
- gdb_put_packet(connection, "OK", 2);
- }
- break;
- case 2:
- case 3:
- case 4:
- {
- if (packet[0] == 'Z')
- {
- if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)
- {
- if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
- return retval;
- }
- else
- {
- gdb_put_packet(connection, "OK", 2);
- }
- }
- else
- {
- watchpoint_remove(target, address);
- gdb_put_packet(connection, "OK", 2);
- }
- break;
- }
- default:
- break;
- }
-
- return ERROR_OK;
-}
-
-/* print out a string and allocate more space as needed, mainly used for XML at this point */
-void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...)
-{
- if (*retval != ERROR_OK)
- {
- return;
- }
- int first = 1;
-
- for (;;)
- {
- if ((*xml == NULL) || (!first))
- {
- /* start by 0 to exercise all the code paths.
- * Need minimum 2 bytes to fit 1 char and 0 terminator. */
-
- *size = *size * 2 + 2;
- char *t = *xml;
- *xml = realloc(*xml, *size);
- if (*xml == NULL)
- {
- if (t)
- free(t);
- *retval = ERROR_SERVER_REMOTE_CLOSED;
- return;
- }
- }
-
- va_list ap;
- int ret;
- va_start(ap, fmt);
- ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap);
- va_end(ap);
- if ((ret > 0) && ((ret + 1) < *size - *pos))
- {
- *pos += ret;
- return;
- }
- /* there was just enough or not enough space, allocate more. */
- first = 0;
- }
-}
-
-static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)
-{
- char *separator;
-
- /* Extract and NUL-terminate the annex. */
- *annex = buf;
- while (*buf && *buf != ':')
- buf++;
- if (*buf == '\0')
- return -1;
- *buf++ = 0;
-
- /* After the read marker and annex, qXfer looks like a
- * traditional 'm' packet. */
-
- *ofs = strtoul(buf, &separator, 16);
-
- if (*separator != ',')
- return -1;
-
- *len = strtoul(separator+1, NULL, 16);
-
- return 0;
-}
-
-int gdb_calc_blocksize(flash_bank_t *bank)
-{
- int i;
- int block_size = 0xffffffff;
-
- /* loop through all sectors and return smallest sector size */
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (bank->sectors[i].size < block_size)
- block_size = bank->sectors[i].size;
- }
-
- return block_size;
-}
-
-int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- command_context_t *cmd_ctx = connection->cmd_ctx;
-
- if (strstr(packet, "qRcmd,"))
- {
- if (packet_size > 6)
- {
- char *cmd;
- int i;
- cmd = malloc((packet_size - 6)/2 + 1);
- for (i=0; i < (packet_size - 6)/2; i++)
- {
- u32 tmp;
- sscanf(packet + 6 + 2*i, "%2x", &tmp);
- cmd[i] = tmp;
- }
- cmd[(packet_size - 6)/2] = 0x0;
-
- /* We want to print all debug output to GDB connection */
- log_setCallback(gdb_log_callback, connection);
- target_call_timer_callbacks();
- command_run_line(cmd_ctx, cmd);
- free(cmd);
- }
- gdb_put_packet(connection, "OK", 2);
- return ERROR_OK;
- }
- else if (strstr(packet, "qCRC:"))
- {
- if (packet_size > 5)
- {
- int retval;
- char gdb_reply[10];
- char *separator;
- u32 checksum;
- u32 addr = 0;
- u32 len = 0;
-
- /* skip command character */
- packet += 5;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete read memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator + 1, NULL, 16);
-
- retval = target_checksum_memory(target, addr, len, &checksum);
-
- if (retval == ERROR_OK)
- {
- snprintf(gdb_reply, 10, "C%8.8x", checksum);
- gdb_put_packet(connection, gdb_reply, 9);
- }
- else
- {
- if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
- return retval;
- }
-
- return ERROR_OK;
- }
- }
- else if (strstr(packet, "qSupported"))
- {
- /* we currently support packet size and qXfer:memory-map:read (if enabled)
- * disable qXfer:features:read for the moment */
- int retval = ERROR_OK;
- char *buffer = NULL;
- int pos = 0;
- int size = 0;
-
- xml_printf(&retval, &buffer, &pos, &size,
- "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",
- (GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-');
-
- if (retval != ERROR_OK)
- {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- gdb_put_packet(connection, buffer, strlen(buffer));
- free(buffer);
-
- return ERROR_OK;
- }
- else if (strstr(packet, "qXfer:memory-map:read::"))
- {
- /* We get away with only specifying flash here. Regions that are not
- * specified are treated as if we provided no memory map(if not we
- * could detect the holes and mark them as RAM).
- * Normally we only execute this code once, but no big deal if we
- * have to regenerate it a couple of times. */
-
- flash_bank_t *p;
- char *xml = NULL;
- int size = 0;
- int pos = 0;
- int retval = ERROR_OK;
-
- int offset;
- int length;
- char *separator;
- int blocksize;
-
- /* skip command character */
- packet += 23;
-
- offset = strtoul(packet, &separator, 16);
- length = strtoul(separator + 1, &separator, 16);
-
- xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");
-
- int i = 0;
- for (;;)
- {
- p = get_flash_bank_by_num(i);
- if (p == NULL)
- break;
-
- /* if device has uneven sector sizes, eg. str7, lpc
- * we pass the smallest sector size to gdb memory map */
- blocksize = gdb_calc_blocksize(p);
-
- xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \
- "<property name=\"blocksize\">0x%x</property>\n" \
- "</memory>\n", \
- p->base, p->size, blocksize);
- i++;
- }
-
- xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");
-
- if (retval != ERROR_OK)
- {
- gdb_send_error(connection, retval);
- return retval;
- }
-
- if (offset + length > pos)
- {
- length = pos - offset;
- }
-
- char *t = malloc(length + 1);
- t[0] = 'l';
- memcpy(t + 1, xml + offset, length);
- gdb_put_packet(connection, t, length + 1);
-
- free(t);
- free(xml);
- return ERROR_OK;
- }
- else if (strstr(packet, "qXfer:features:read:"))
- {
- char *xml = NULL;
- int size = 0;
- int pos = 0;
- int retval = ERROR_OK;
-
- int offset;
- unsigned int length;
- char *annex;
-
- /* skip command character */
- packet += 20;
-
- if (decode_xfer_read(packet, &annex, &offset, &length) < 0)
- {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- if (strcmp(annex, "target.xml") != 0)
- {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- xml_printf(&retval, &xml, &pos, &size, \
- "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");
-
- if (retval != ERROR_OK)
- {
- gdb_send_error(connection, retval);
- return retval;
- }
-
- gdb_put_packet(connection, xml, strlen(xml) + 1);
-
- free(xml);
- return ERROR_OK;
- }
-
- gdb_put_packet(connection, "", 0);
- return ERROR_OK;
-}
-
-int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- gdb_connection_t *gdb_connection = connection->priv;
- gdb_service_t *gdb_service = connection->service->priv;
- int result;
-
- /* if flash programming disabled - send a empty reply */
-
- if (gdb_flash_program == 0)
- {
- gdb_put_packet(connection, "", 0);
- return ERROR_OK;
- }
-
- if (strstr(packet, "vFlashErase:"))
- {
- unsigned long addr;
- unsigned long length;
-
- char *parse = packet + 12;
- if (*parse == '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- addr = strtoul(parse, &parse, 16);
-
- if (*(parse++) != ',' || *parse == '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- length = strtoul(parse, &parse, 16);
-
- if (*parse != '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- /* assume all sectors need erasing - stops any problems
- * when flash_write is called multiple times */
- flash_set_dirty();
-
- /* perform any target specific operations before the erase */
- target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
-
- /* perform erase */
- if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
- {
- /* GDB doesn't evaluate the actual error number returned,
- * treat a failed erase as an I/O error
- */
- gdb_send_error(connection, EIO);
- ERROR("flash_erase returned %i", result);
- }
- else
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
- }
-
- if (strstr(packet, "vFlashWrite:"))
- {
- unsigned long addr;
- unsigned long length;
- char *parse = packet + 12;
-
- if (*parse == '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- addr = strtoul(parse, &parse, 16);
- if (*(parse++) != ':')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- length = packet_size - (parse - packet);
-
- /* create a new image if there isn't already one */
- if (gdb_connection->vflash_image == NULL)
- {
- gdb_connection->vflash_image = malloc(sizeof(image_t));
- image_open(gdb_connection->vflash_image, "", "build");
- }
-
- /* create new section with content from packet buffer */
- image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);
-
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
- }
-
- if (!strcmp(packet, "vFlashDone"))
- {
- u32 written;
- char *error_str;
-
- /* process the flashing buffer. No need to erase as GDB
- * always issues a vFlashErase first. */
- if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, &error_str, NULL, 0)) != ERROR_OK)
- {
- if (result == ERROR_FLASH_DST_OUT_OF_BANK)
- gdb_put_packet(connection, "E.memtype", 9);
- else
- gdb_send_error(connection, EIO);
-
- if (error_str)
- {
- ERROR("flash writing failed: %s", error_str);
- free(error_str);
- }
- }
- else
- {
- DEBUG("wrote %u bytes from vFlash image to flash", written);
- gdb_put_packet(connection, "OK", 2);
- }
-
- image_close(gdb_connection->vflash_image);
- free(gdb_connection->vflash_image);
- gdb_connection->vflash_image = NULL;
-
- return ERROR_OK;
- }
-
- gdb_put_packet(connection, "", 0);
- return ERROR_OK;
-}
-
-int gdb_detach(connection_t *connection, target_t *target)
-{
- switch( detach_mode )
- {
- case GDB_DETACH_RESUME:
- target->type->resume(target, 1, 0, 1, 0);
- break;
-
- case GDB_DETACH_RESET:
- target_process_reset(connection->cmd_ctx);
- break;
-
- case GDB_DETACH_HALT:
- target->type->halt(target);
- break;
-
- case GDB_DETACH_NOTHING:
- break;
- }
-
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
-}
-
-static void gdb_log_callback(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args)
-{
- connection_t *connection = priv;
- gdb_connection_t *gdb_con = connection->priv;
-
- if (gdb_con->busy)
- {
- /* do not reply this using the O packet */
- return;
- }
-
- char *t = allocPrintf(format, args);
- if (t == NULL)
- return;
-
- gdb_output_con(connection, t);
-
- free(t);
-}
-
-int gdb_input_inner(connection_t *connection)
-{
- gdb_service_t *gdb_service = connection->service->priv;
- target_t *target = gdb_service->target;
- char packet[GDB_BUFFER_SIZE];
- int packet_size;
- int retval;
- gdb_connection_t *gdb_con = connection->priv;
- static int extended_protocol = 0;
-
- /* drain input buffer */
- do
- {
- packet_size = GDB_BUFFER_SIZE-1;
- if ((retval = gdb_get_packet(connection, packet, &packet_size)) != ERROR_OK)
- {
- return retval;
- }
-
- /* terminate with zero */
- packet[packet_size] = 0;
-
- DEBUG("received packet: '%s'", packet);
-
- if (packet_size > 0)
- {
- retval = ERROR_OK;
- switch (packet[0])
- {
- case 'H':
- /* Hct... -- set thread
- * we don't have threads, send empty reply */
- gdb_put_packet(connection, NULL, 0);
- break;
- case 'q':
- retval = gdb_query_packet(connection, target, packet, packet_size);
- break;
- case 'g':
- retval = gdb_get_registers_packet(connection, target, packet, packet_size);
- break;
- case 'G':
- retval = gdb_set_registers_packet(connection, target, packet, packet_size);
- break;
- case 'p':
- retval = gdb_get_register_packet(connection, target, packet, packet_size);
- break;
- case 'P':
- retval = gdb_set_register_packet(connection, target, packet, packet_size);
- break;
- case 'm':
- retval = gdb_read_memory_packet(connection, target, packet, packet_size);
- break;
- case 'M':
- retval = gdb_write_memory_packet(connection, target, packet, packet_size);
- break;
- case 'z':
- case 'Z':
- retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
- break;
- case '?':
- gdb_last_signal_packet(connection, target, packet, packet_size);
- break;
- case 'c':
- case 's':
- {
- /* We're running/stepping, in which case we can
- * forward log output until the target is halted */
- gdb_connection_t *gdb_con = connection->priv;
- gdb_con->frontend_state = TARGET_RUNNING;
- log_setCallback(gdb_log_callback, connection);
- gdb_step_continue_packet(connection, target, packet, packet_size);
- }
- break;
- case 'v':
- retval = gdb_v_packet(connection, target, packet, packet_size);
- break;
- case 'D':
- retval = gdb_detach(connection, target);
- extended_protocol = 0;
- break;
- case 'X':
- if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)
- return retval;
- break;
- case 'k':
- if (extended_protocol != 0)
- break;
- gdb_put_packet(connection, "OK", 2);
- return ERROR_SERVER_REMOTE_CLOSED;
- case '!':
- /* handle extended remote protocol */
- extended_protocol = 1;
- gdb_put_packet(connection, "OK", 2);
- break;
- case 'R':
- /* handle extended restart packet */
- target_process_reset(connection->cmd_ctx);
- break;
- default:
- /* ignore unkown packets */
- DEBUG("ignoring 0x%2.2x packet", packet[0]);
- gdb_put_packet(connection, NULL, 0);
- break;
- }
-
- /* if a packet handler returned an error, exit input loop */
- if (retval != ERROR_OK)
- return retval;
- }
-
- if (gdb_con->ctrl_c)
- {
- if (target->state == TARGET_RUNNING)
- {
- target->type->halt(target);
- gdb_con->ctrl_c = 0;
- }
- }
-
- } while (gdb_con->buf_cnt > 0);
-
- return ERROR_OK;
-}
-
-int gdb_input(connection_t *connection)
-{
- int retval = gdb_input_inner(connection);
- if (retval == ERROR_SERVER_REMOTE_CLOSED)
- return retval;
- /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */
- return ERROR_OK;
-}
-
-int gdb_init()
-{
- gdb_service_t *gdb_service;
- target_t *target = targets;
- int i = 0;
-
- if (!target)
- {
- WARNING("no gdb ports allocated as no target has been specified");
- return ERROR_OK;
- }
-
- if (gdb_port == 0)
- {
- WARNING("no gdb port specified, using default port 3333");
- gdb_port = 3333;
- }
-
- while (target)
- {
- char service_name[8];
-
- snprintf(service_name, 8, "gdb-%2.2i", i);
-
- gdb_service = malloc(sizeof(gdb_service_t));
- gdb_service->target = target;
-
- add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
-
- DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
-
- i++;
- target = target->next;
- }
-
- return ERROR_OK;
-}
-
-/* daemon configuration command gdb_port */
-int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 0)
- return ERROR_OK;
-
- /* only if the port wasn't overwritten by cmdline */
- if (gdb_port == 0)
- gdb_port = strtoul(args[0], NULL, 0);
-
- return ERROR_OK;
-}
-
-int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "resume") == 0)
- {
- detach_mode = GDB_DETACH_RESUME;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "reset") == 0)
- {
- detach_mode = GDB_DETACH_RESET;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "halt") == 0)
- {
- detach_mode = GDB_DETACH_HALT;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "nothing") == 0)
- {
- detach_mode = GDB_DETACH_NOTHING;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_detach configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- gdb_use_memory_map = 1;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- gdb_use_memory_map = 0;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- gdb_flash_program = 1;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- gdb_flash_program = 0;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- gdb_report_data_abort = 1;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- gdb_report_data_abort = 0;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int gdb_register_commands(command_context_t *command_context)
-{
- register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,
- COMMAND_CONFIG, "");
- 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 "replacements.h"\r
+\r
+#include "gdb_server.h"\r
+\r
+#include "server.h"\r
+#include "log.h"\r
+#include "binarybuffer.h"\r
+#include "jtag.h"\r
+#include "breakpoints.h"\r
+#include "flash.h"\r
+#include "target_request.h"\r
+#include "configuration.h"\r
+\r
+#include <string.h>\r
+#include <errno.h>\r
+#include <unistd.h>\r
+#include <stdlib.h>\r
+\r
+#if 0\r
+#define _DEBUG_GDB_IO_\r
+#endif\r
+\r
+static unsigned short gdb_port;\r
+static const char *DIGITS = "0123456789abcdef";\r
+\r
+static void gdb_log_callback(void *priv, const char *file, int line, \r
+ const char *function, const char *format, va_list args);\r
+\r
+enum gdb_detach_mode\r
+{\r
+ GDB_DETACH_RESUME,\r
+ GDB_DETACH_RESET,\r
+ GDB_DETACH_HALT,\r
+ GDB_DETACH_NOTHING\r
+};\r
+\r
+/* target behaviour on gdb detach */\r
+enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME;\r
+\r
+/* set if we are sending a memory map to gdb\r
+ * via qXfer:memory-map:read packet */\r
+int gdb_use_memory_map = 0;\r
+int gdb_flash_program = 0;\r
+\r
+/* if set, data aborts cause an error to be reported in memory read packets\r
+ * see the code in gdb_read_memory_packet() for further explanations */\r
+int gdb_report_data_abort = 0;\r
+\r
+int gdb_last_signal(target_t *target)\r
+{\r
+ switch (target->debug_reason)\r
+ {\r
+ case DBG_REASON_DBGRQ:\r
+ return 0x2; /* SIGINT */\r
+ case DBG_REASON_BREAKPOINT:\r
+ case DBG_REASON_WATCHPOINT:\r
+ case DBG_REASON_WPTANDBKPT:\r
+ return 0x05; /* SIGTRAP */\r
+ case DBG_REASON_SINGLESTEP:\r
+ return 0x05; /* SIGTRAP */\r
+ case DBG_REASON_NOTHALTED:\r
+ return 0x0; /* no signal... shouldn't happen */\r
+ default:\r
+ ERROR("BUG: undefined debug reason");\r
+ exit(-1);\r
+ }\r
+}\r
+\r
+int gdb_get_char(connection_t *connection, int* next_char)\r
+{\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ char *debug_buffer;\r
+#endif\r
+\r
+ if (gdb_con->buf_cnt-- > 0)\r
+ {\r
+ *next_char = *(gdb_con->buf_p++);\r
+ if (gdb_con->buf_cnt > 0)\r
+ connection->input_pending = 1;\r
+ else\r
+ connection->input_pending = 0;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);\r
+#endif\r
+\r
+ return ERROR_OK;\r
+ }\r
+\r
+ for (;;)\r
+ {\r
+#ifndef _WIN32\r
+ /* a non-blocking socket will block if there is 0 bytes available on the socket,\r
+ * but return with as many bytes as are available immediately\r
+ */\r
+ struct timeval tv;\r
+ fd_set read_fds;\r
+ \r
+ FD_ZERO(&read_fds);\r
+ FD_SET(connection->fd, &read_fds);\r
+ \r
+ tv.tv_sec = 1;\r
+ tv.tv_usec = 0;\r
+ if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)\r
+ {\r
+ /* This can typically be because a "monitor" command took too long\r
+ * before printing any progress messages\r
+ */\r
+ return ERROR_GDB_TIMEOUT; \r
+ }\r
+#endif\r
+ gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);\r
+ if (gdb_con->buf_cnt > 0)\r
+ {\r
+ break;\r
+ }\r
+ if (gdb_con->buf_cnt == 0)\r
+ {\r
+ gdb_con->closed = 1;\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+#ifdef _WIN32\r
+ errno = WSAGetLastError();\r
+\r
+ switch(errno)\r
+ {\r
+ case WSAEWOULDBLOCK:\r
+ usleep(1000);\r
+ break;\r
+ case WSAECONNABORTED:\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ case WSAECONNRESET:\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ default:\r
+ ERROR("read: %d", errno);\r
+ exit(-1);\r
+ }\r
+#else\r
+ switch(errno)\r
+ {\r
+ case EAGAIN:\r
+ usleep(1000);\r
+ break;\r
+ case ECONNABORTED:\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ case ECONNRESET:\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ default:\r
+ ERROR("read: %s", strerror(errno));\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+#endif\r
+ }\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ debug_buffer = malloc(gdb_con->buf_cnt + 1);\r
+ memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);\r
+ debug_buffer[gdb_con->buf_cnt] = 0;\r
+ DEBUG("received '%s'", debug_buffer);\r
+ free(debug_buffer);\r
+#endif\r
+\r
+ gdb_con->buf_p = gdb_con->buffer;\r
+ gdb_con->buf_cnt--;\r
+ *next_char = *(gdb_con->buf_p++);\r
+ if (gdb_con->buf_cnt > 0)\r
+ connection->input_pending = 1;\r
+ else\r
+ connection->input_pending = 0; \r
+#ifdef _DEBUG_GDB_IO_\r
+ DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);\r
+#endif\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_putback_char(connection_t *connection, int last_char)\r
+{\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+\r
+ if (gdb_con->buf_p > gdb_con->buffer)\r
+ {\r
+ *(--gdb_con->buf_p) = last_char;\r
+ gdb_con->buf_cnt++;\r
+ }\r
+ else\r
+ {\r
+ ERROR("BUG: couldn't put character back"); \r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+/* The only way we can detect that the socket is closed is the first time\r
+ * we write to it, we will fail. Subsequent write operations will\r
+ * succeed. Shudder! */\r
+int gdb_write(connection_t *connection, void *data, int len)\r
+{\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ if (gdb_con->closed)\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+ if (write_socket(connection->fd, data, len) == len)\r
+ {\r
+ return ERROR_OK;\r
+ }\r
+ gdb_con->closed = 1;\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+}\r
+\r
+int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)\r
+{\r
+ int i;\r
+ unsigned char my_checksum = 0;\r
+#ifdef _DEBUG_GDB_IO_\r
+ char *debug_buffer;\r
+#endif\r
+ int reply;\r
+ int retval;\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+\r
+ for (i = 0; i < len; i++)\r
+ my_checksum += buffer[i];\r
+\r
+ while (1)\r
+ {\r
+#ifdef _DEBUG_GDB_IO_\r
+ debug_buffer = malloc(len + 1);\r
+ memcpy(debug_buffer, buffer, len);\r
+ debug_buffer[len] = 0;\r
+ DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);\r
+ free(debug_buffer);\r
+#endif\r
+#if 0\r
+ char checksum[3];\r
+ gdb_write(connection, "$", 1);\r
+ if (len > 0)\r
+ gdb_write(connection, buffer, len);\r
+ gdb_write(connection, "#", 1);\r
+ \r
+ snprintf(checksum, 3, "%2.2x", my_checksum);\r
+ \r
+ gdb_write(connection, checksum, 2);\r
+#else\r
+ void *allocated = NULL;\r
+ char stackAlloc[1024];\r
+ char *t = stackAlloc;\r
+ int totalLen = 1 + len + 1 + 2;\r
+ if (totalLen > sizeof(stackAlloc))\r
+ {\r
+ allocated = malloc(totalLen);\r
+ t = allocated;\r
+ if (allocated == NULL)\r
+ {\r
+ ERROR("Ran out of memory trying to reply packet %d\n", totalLen);\r
+ exit(-1);\r
+ }\r
+ }\r
+ t[0] = '$';\r
+ memcpy(t + 1, buffer, len);\r
+ t[1 + len] = '#';\r
+ t[1 + len + 1] = DIGITS[(my_checksum >> 4) & 0xf];\r
+ t[1 + len + 2] = DIGITS[my_checksum & 0xf];\r
+ \r
+ gdb_write(connection, t, totalLen);\r
+ \r
+ if (allocated)\r
+ {\r
+ free(allocated);\r
+ }\r
+#endif\r
+ if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)\r
+ return retval;\r
+\r
+ if (reply == '+')\r
+ break;\r
+ else if (reply == '-')\r
+ {\r
+ /* Stop sending output packets for now */\r
+ log_setCallback(NULL, NULL);\r
+ WARNING("negative reply, retrying");\r
+ }\r
+ else if (reply == 0x3)\r
+ {\r
+ gdb_con->ctrl_c = 1;\r
+ if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)\r
+ return retval;\r
+ if (reply == '+')\r
+ break;\r
+ else if (reply == '-')\r
+ {\r
+ /* Stop sending output packets for now */\r
+ log_setCallback(NULL, NULL);\r
+ WARNING("negative reply, retrying");\r
+ }\r
+ else\r
+ {\r
+ ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+ }\r
+ if (gdb_con->closed)\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_put_packet(connection_t *connection, char *buffer, int len)\r
+{\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ gdb_con->busy = 1;\r
+ int retval = gdb_put_packet_inner(connection, buffer, len);\r
+ gdb_con->busy = 0;\r
+ return retval;\r
+}\r
+\r
+int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)\r
+{\r
+ int character;\r
+ int count = 0;\r
+ int retval;\r
+ char checksum[3];\r
+ unsigned char my_checksum = 0;\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+\r
+ while (1)\r
+ {\r
+ do\r
+ {\r
+ if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+ return retval;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ DEBUG("character: '%c'", character);\r
+#endif\r
+\r
+ switch (character)\r
+ {\r
+ case '$':\r
+ break;\r
+ case '+':\r
+ WARNING("acknowledgment received, but no packet pending");\r
+ break;\r
+ case '-':\r
+ WARNING("negative acknowledgment, but no packet pending");\r
+ break;\r
+ case 0x3:\r
+ gdb_con->ctrl_c = 1;\r
+ *len = 0;\r
+ return ERROR_OK;\r
+ default:\r
+ WARNING("ignoring character 0x%x", character);\r
+ break;\r
+ }\r
+ } while (character != '$');\r
+\r
+ my_checksum = 0;\r
+ \r
+ count = 0;\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ for (;;)\r
+ {\r
+ /* The common case is that we have an entire packet with no escape chars.\r
+ * We need to leave at least 2 bytes in the buffer to have\r
+ * gdb_get_char() update various bits and bobs correctly. \r
+ */\r
+ if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))\r
+ {\r
+ /* The compiler will struggle a bit with constant propagation and\r
+ * aliasing, so we help it by showing that these values do not\r
+ * change inside the loop \r
+ */ \r
+ int i;\r
+ char *buf = gdb_con->buf_p;\r
+ int run = gdb_con->buf_cnt - 2;\r
+ i = 0;\r
+ int done = 0;\r
+ while (i < run)\r
+ {\r
+ character = *buf++;\r
+ i++;\r
+ if (character == '#')\r
+ {\r
+ /* Danger! character can be '#' when esc is \r
+ * used so we need an explicit boolean for done here.\r
+ */\r
+ done = 1;\r
+ break;\r
+ }\r
+ \r
+ if (character == '}')\r
+ {\r
+ /* data transmitted in binary mode (X packet)\r
+ * uses 0x7d as escape character */\r
+ my_checksum += character & 0xff;\r
+ character = *buf++;\r
+ i++;\r
+ my_checksum += character & 0xff;\r
+ buffer[count++] = (character ^ 0x20) & 0xff;\r
+ } else\r
+ {\r
+ my_checksum += character & 0xff;\r
+ buffer[count++] = character & 0xff;\r
+ }\r
+ }\r
+ gdb_con->buf_p += i;\r
+ gdb_con->buf_cnt -= i;\r
+ if (done) \r
+ break;\r
+ } \r
+ if (count > *len)\r
+ {\r
+ ERROR("packet buffer too small");\r
+ return ERROR_GDB_BUFFER_TOO_SMALL;\r
+ }\r
+ \r
+ if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+ return retval;\r
+\r
+ if (character == '#')\r
+ break;\r
+\r
+ if (character == '}')\r
+ {\r
+ /* data transmitted in binary mode (X packet)\r
+ * uses 0x7d as escape character */\r
+ my_checksum += character & 0xff;\r
+ if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+ return retval;\r
+ my_checksum += character & 0xff;\r
+ buffer[count++] = (character ^ 0x20) & 0xff;\r
+ }\r
+ else\r
+ {\r
+ my_checksum += character & 0xff;\r
+ buffer[count++] = character & 0xff;\r
+ }\r
+\r
+ }\r
+\r
+ *len = count;\r
+\r
+ if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+ return retval;\r
+ checksum[0] = character;\r
+ if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+ return retval;\r
+ checksum[1] = character;\r
+ checksum[2] = 0;\r
+\r
+ if (my_checksum == strtoul(checksum, NULL, 16))\r
+ {\r
+ gdb_write(connection, "+", 1);\r
+ break;\r
+ }\r
+\r
+ WARNING("checksum error, requesting retransmission");\r
+ gdb_write(connection, "-", 1);\r
+ }\r
+ if (gdb_con->closed)\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_get_packet(connection_t *connection, char *buffer, int *len)\r
+{\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ gdb_con->busy = 1;\r
+ int retval = gdb_get_packet_inner(connection, buffer, len);\r
+ gdb_con->busy = 0;\r
+ return retval;\r
+}\r
+ \r
+int gdb_output_con(connection_t *connection, char* line)\r
+{\r
+ char *hex_buffer;\r
+ int i, bin_size;\r
+\r
+ bin_size = strlen(line);\r
+\r
+ hex_buffer = malloc(bin_size*2 + 4);\r
+\r
+ hex_buffer[0] = 'O';\r
+ for (i=0; i<bin_size; i++)\r
+ snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);\r
+ hex_buffer[bin_size*2+1] = '0';\r
+ hex_buffer[bin_size*2+2] = 'a';\r
+ hex_buffer[bin_size*2+3] = 0x0;\r
+\r
+ gdb_put_packet(connection, hex_buffer, bin_size*2 + 3);\r
+\r
+ free(hex_buffer);\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_output(struct command_context_s *context, char* line)\r
+{\r
+ /* this will be dumped to the log and also sent as an O packet if possible */\r
+ USER(line); \r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)\r
+{\r
+ FILE *script;\r
+ struct command_context_s *cmd_ctx = priv;\r
+ \r
+ if (target->gdb_program_script)\r
+ {\r
+ script = open_file_from_path(cmd_ctx, target->gdb_program_script, "r");\r
+ if (!script)\r
+ {\r
+ ERROR("couldn't open script file %s", target->gdb_program_script);\r
+ return ERROR_OK;\r
+ }\r
+\r
+ INFO("executing gdb_program script '%s'", target->gdb_program_script);\r
+ command_run_file(cmd_ctx, script, COMMAND_EXEC);\r
+ fclose(script);\r
+ \r
+ jtag_execute_queue();\r
+ }\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)\r
+{\r
+ connection_t *connection = priv;\r
+ gdb_connection_t *gdb_connection = connection->priv;\r
+ char sig_reply[4];\r
+ int signal;\r
+\r
+ switch (event)\r
+ {\r
+ case TARGET_EVENT_HALTED:\r
+ /* In the GDB protocol when we are stepping or coninuing execution,\r
+ * we have a lingering reply. Upon receiving a halted event \r
+ * when we have that lingering packet, we reply to the original\r
+ * step or continue packet.\r
+ * \r
+ * Executing monitor commands can bring the target in and\r
+ * out of the running state so we'll see lots of TARGET_EVENT_XXX\r
+ * that are to be ignored.\r
+ */\r
+ if (gdb_connection->frontend_state == TARGET_RUNNING)\r
+ {\r
+ /* stop forwarding log packets! */\r
+ log_setCallback(NULL, NULL);\r
+ \r
+ if (gdb_connection->ctrl_c)\r
+ {\r
+ signal = 0x2;\r
+ gdb_connection->ctrl_c = 0;\r
+ }\r
+ else\r
+ {\r
+ signal = gdb_last_signal(target);\r
+ }\r
+\r
+ snprintf(sig_reply, 4, "T%2.2x", signal);\r
+ gdb_put_packet(connection, sig_reply, 3);\r
+ gdb_connection->frontend_state = TARGET_HALTED;\r
+ }\r
+ break;\r
+ case TARGET_EVENT_GDB_PROGRAM:\r
+ gdb_program_handler(target, event, connection->cmd_ctx);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_new_connection(connection_t *connection)\r
+{\r
+ gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));\r
+ gdb_service_t *gdb_service = connection->service->priv;\r
+ int retval;\r
+ int initial_ack;\r
+\r
+ connection->priv = gdb_connection;\r
+\r
+ /* initialize gdb connection information */\r
+ gdb_connection->buf_p = gdb_connection->buffer;\r
+ gdb_connection->buf_cnt = 0;\r
+ gdb_connection->ctrl_c = 0;\r
+ gdb_connection->frontend_state = TARGET_HALTED;\r
+ gdb_connection->vflash_image = NULL;\r
+ gdb_connection->closed = 0;\r
+ gdb_connection->busy = 0;\r
+ \r
+ /* output goes through gdb connection */\r
+ command_set_output_handler(connection->cmd_ctx, gdb_output, connection);\r
+\r
+ /* register callback to be informed about target events */\r
+ target_register_event_callback(gdb_target_callback_event_handler, connection); \r
+\r
+ /* a gdb session just attached, put the target in halt mode */\r
+ if (((retval = gdb_service->target->type->halt(gdb_service->target)) != ERROR_OK) &&\r
+ (retval != ERROR_TARGET_ALREADY_HALTED))\r
+ {\r
+ ERROR("error(%d) when trying to halt target, falling back to \"reset halt\"", retval);\r
+ command_run_line(connection->cmd_ctx, "reset halt");\r
+ }\r
+\r
+ /* This will time out after 1 second */\r
+ command_run_line(connection->cmd_ctx, "wait_halt 1");\r
+\r
+ /* remove the initial ACK from the incoming buffer */\r
+ if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)\r
+ return retval;\r
+\r
+ if (initial_ack != '+')\r
+ gdb_putback_char(connection, initial_ack);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_connection_closed(connection_t *connection)\r
+{\r
+ gdb_service_t *gdb_service = connection->service->priv;\r
+ gdb_connection_t *gdb_connection = connection->priv;\r
+\r
+ /* see if an image built with vFlash commands is left */\r
+ if (gdb_connection->vflash_image)\r
+ {\r
+ image_close(gdb_connection->vflash_image);\r
+ free(gdb_connection->vflash_image);\r
+ gdb_connection->vflash_image = NULL;\r
+ }\r
+\r
+ /* if this connection registered a debug-message receiver delete it */\r
+ delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);\r
+ \r
+ if (connection->priv)\r
+ {\r
+ free(connection->priv);\r
+ connection->priv = NULL;\r
+ }\r
+ else\r
+ {\r
+ ERROR("BUG: connection->priv == NULL");\r
+ }\r
+\r
+ target_unregister_event_callback(gdb_target_callback_event_handler, connection);\r
+ log_setCallback(NULL, NULL);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+void gdb_send_error(connection_t *connection, u8 the_error)\r
+{\r
+ char err[4];\r
+ snprintf(err, 4, "E%2.2X", the_error );\r
+ gdb_put_packet(connection, err, 3);\r
+}\r
+\r
+int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size)\r
+{\r
+ char sig_reply[4];\r
+ int signal;\r
+\r
+ signal = gdb_last_signal(target);\r
+\r
+ snprintf(sig_reply, 4, "S%2.2x", signal);\r
+ gdb_put_packet(connection, sig_reply, 3);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+/* Convert register to string of bits. NB! The # of bits in the\r
+ * register might be non-divisible by 8(a byte), in which\r
+ * case an entire byte is shown. */\r
+void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)\r
+{\r
+ int i;\r
+\r
+ u8 *buf;\r
+ int buf_len;\r
+ buf = reg->value;\r
+ buf_len = CEIL(reg->size, 8); \r
+\r
+ if (target->endianness == TARGET_LITTLE_ENDIAN)\r
+ {\r
+ for (i = 0; i < buf_len; i++)\r
+ {\r
+ tstr[i*2] = DIGITS[(buf[i]>>4) & 0xf];\r
+ tstr[i*2+1] = DIGITS[buf[i]&0xf];\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i = 0; i < buf_len; i++)\r
+ {\r
+ tstr[(buf_len-1-i)*2] = DIGITS[(buf[i]>>4)&0xf];\r
+ tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf];\r
+ }\r
+ } \r
+}\r
+\r
+void gdb_target_to_str(target_t *target, char *tstr, char *str)\r
+{\r
+ int str_len = strlen(tstr);\r
+ int i;\r
+\r
+ if (str_len % 2)\r
+ {\r
+ ERROR("BUG: gdb value with uneven number of characters encountered");\r
+ exit(-1);\r
+ }\r
+\r
+ if (target->endianness == TARGET_LITTLE_ENDIAN)\r
+ {\r
+ for (i = 0; i < str_len; i+=2)\r
+ {\r
+ str[str_len - i - 1] = tstr[i + 1];\r
+ str[str_len - i - 2] = tstr[i];\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i = 0; i < str_len; i++)\r
+ {\r
+ str[i] = tstr[i];\r
+ }\r
+ } \r
+}\r
+\r
+int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)\r
+{\r
+ reg_t **reg_list;\r
+ int reg_list_size;\r
+ int retval;\r
+ int reg_packet_size = 0;\r
+ char *reg_packet;\r
+ char *reg_packet_p;\r
+ int i;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ DEBUG("-");\r
+#endif\r
+\r
+ if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)\r
+ {\r
+ switch (retval)\r
+ {\r
+ case ERROR_TARGET_NOT_HALTED:\r
+ ERROR("gdb requested registers but we're not halted, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ default:\r
+ /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+ ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+ exit(-1);\r
+ }\r
+ }\r
+\r
+ for (i = 0; i < reg_list_size; i++)\r
+ {\r
+ reg_packet_size += reg_list[i]->size;\r
+ }\r
+\r
+ reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);\r
+ reg_packet_p = reg_packet;\r
+\r
+ for (i = 0; i < reg_list_size; i++)\r
+ {\r
+ gdb_str_to_target(target, reg_packet_p, reg_list[i]);\r
+ reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;\r
+ }\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ {\r
+ char *reg_packet_p;\r
+ reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);\r
+ DEBUG("reg_packet: %s", reg_packet_p);\r
+ free(reg_packet_p);\r
+ }\r
+#endif\r
+\r
+ gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);\r
+ free(reg_packet);\r
+\r
+ free(reg_list);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ int i;\r
+ reg_t **reg_list;\r
+ int reg_list_size;\r
+ int retval;\r
+ char *packet_p;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ DEBUG("-");\r
+#endif\r
+\r
+ /* skip command character */\r
+ packet++;\r
+ packet_size--;\r
+\r
+ if (packet_size % 2)\r
+ {\r
+ WARNING("GDB set_registers packet with uneven characters received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)\r
+ {\r
+ switch (retval)\r
+ {\r
+ case ERROR_TARGET_NOT_HALTED:\r
+ ERROR("gdb tried to registers but we're not halted, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ default:\r
+ /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+ ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+ exit(-1);\r
+ }\r
+ }\r
+\r
+ packet_p = packet;\r
+ for (i = 0; i < reg_list_size; i++)\r
+ {\r
+ u8 *bin_buf;\r
+ char *hex_buf;\r
+ reg_arch_type_t *arch_type;\r
+\r
+ /* convert from GDB-string (target-endian) to hex-string (big-endian) */\r
+ hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2);\r
+ gdb_target_to_str(target, packet_p, hex_buf);\r
+\r
+ /* convert hex-string to binary buffer */\r
+ bin_buf = malloc(CEIL(reg_list[i]->size, 8));\r
+ str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16);\r
+\r
+ /* get register arch_type, and call set method */ \r
+ arch_type = register_get_arch_type(reg_list[i]->arch_type);\r
+ if (arch_type == NULL)\r
+ {\r
+ ERROR("BUG: encountered unregistered arch type");\r
+ exit(-1);\r
+ }\r
+ arch_type->set(reg_list[i], bin_buf);\r
+\r
+ /* advance packet pointer */ \r
+ packet_p += (CEIL(reg_list[i]->size, 8) * 2);\r
+\r
+ free(bin_buf);\r
+ free(hex_buf);\r
+ }\r
+\r
+ /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */ \r
+ free(reg_list);\r
+\r
+ gdb_put_packet(connection, "OK", 2);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ char *reg_packet;\r
+ int reg_num = strtoul(packet + 1, NULL, 16);\r
+ reg_t **reg_list;\r
+ int reg_list_size;\r
+ int retval;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+ DEBUG("-");\r
+#endif\r
+\r
+ if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)\r
+ {\r
+ switch (retval)\r
+ {\r
+ case ERROR_TARGET_NOT_HALTED:\r
+ ERROR("gdb requested registers but we're not halted, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ default:\r
+ /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+ ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+ exit(-1);\r
+ }\r
+ }\r
+\r
+ if (reg_list_size <= reg_num)\r
+ {\r
+ ERROR("gdb requested a non-existing register");\r
+ exit(-1);\r
+ }\r
+\r
+ reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);\r
+\r
+ gdb_str_to_target(target, reg_packet, reg_list[reg_num]);\r
+\r
+ gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);\r
+\r
+ free(reg_list);\r
+ free(reg_packet);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ char *separator;\r
+ char *hex_buf;\r
+ u8 *bin_buf;\r
+ int reg_num = strtoul(packet + 1, &separator, 16);\r
+ reg_t **reg_list;\r
+ int reg_list_size;\r
+ int retval;\r
+ reg_arch_type_t *arch_type;\r
+\r
+ DEBUG("-");\r
+\r
+ if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)\r
+ {\r
+ switch (retval)\r
+ {\r
+ case ERROR_TARGET_NOT_HALTED:\r
+ ERROR("gdb tried to set a register but we're not halted, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ default:\r
+ /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+ ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+ exit(-1);\r
+ }\r
+ }\r
+\r
+ if (reg_list_size < reg_num)\r
+ {\r
+ ERROR("gdb requested a non-existing register");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ if (*separator != '=')\r
+ {\r
+ ERROR("GDB 'set register packet', but no '=' following the register number");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ /* convert from GDB-string (target-endian) to hex-string (big-endian) */\r
+ hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);\r
+ gdb_target_to_str(target, separator + 1, hex_buf);\r
+\r
+ /* convert hex-string to binary buffer */\r
+ bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));\r
+ str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16);\r
+\r
+ /* get register arch_type, and call set method */ \r
+ arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);\r
+ if (arch_type == NULL)\r
+ {\r
+ ERROR("BUG: encountered unregistered arch type");\r
+ exit(-1);\r
+ }\r
+ arch_type->set(reg_list[reg_num], bin_buf);\r
+\r
+ gdb_put_packet(connection, "OK", 2);\r
+\r
+ free(bin_buf);\r
+ free(hex_buf);\r
+ free(reg_list);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_memory_packet_error(connection_t *connection, int retval)\r
+{\r
+ switch (retval)\r
+ {\r
+ case ERROR_TARGET_NOT_HALTED:\r
+ ERROR("gdb tried to read memory but we're not halted, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ case ERROR_TARGET_DATA_ABORT:\r
+ gdb_send_error(connection, EIO);\r
+ break;\r
+ case ERROR_TARGET_TRANSLATION_FAULT:\r
+ gdb_send_error(connection, EFAULT);\r
+ break;\r
+ case ERROR_TARGET_UNALIGNED_ACCESS:\r
+ gdb_send_error(connection, EFAULT);\r
+ break;\r
+ default:\r
+ /* This could be that the target reset itself. */\r
+ ERROR("unexpected error %i. Dropping connection.", retval);\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+/* We don't have to worry about the default 2 second timeout for GDB packets,\r
+ * because GDB breaks up large memory reads into smaller reads.\r
+ * \r
+ * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????\r
+ */\r
+int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ char *separator;\r
+ u32 addr = 0;\r
+ u32 len = 0;\r
+\r
+ u8 *buffer;\r
+ char *hex_buffer;\r
+\r
+ int retval = ERROR_OK;\r
+\r
+ /* skip command character */\r
+ packet++;\r
+\r
+ addr = strtoul(packet, &separator, 16);\r
+\r
+ if (*separator != ',')\r
+ {\r
+ ERROR("incomplete read memory packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ len = strtoul(separator+1, NULL, 16);\r
+\r
+ buffer = malloc(len);\r
+\r
+ DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);\r
+\r
+ retval = target_read_buffer(target, addr, len, buffer);\r
+\r
+ if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort))\r
+ {\r
+ /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.\r
+ * At some point this might be fixed in GDB, in which case this code can be removed.\r
+ * \r
+ * OpenOCD developers are acutely aware of this problem, but there is nothing\r
+ * gained by involving the user in this problem that hopefully will get resolved\r
+ * eventually\r
+ * \r
+ * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395\r
+ *\r
+ * For now, the default is to fix up things to make current GDB versions work.\r
+ * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command.\r
+ */\r
+ memset(buffer, 0, len);\r
+ retval = ERROR_OK;\r
+ }\r
+\r
+ if (retval == ERROR_OK)\r
+ {\r
+ hex_buffer = malloc(len * 2 + 1);\r
+\r
+ int i;\r
+ for (i = 0; i < len; i++)\r
+ {\r
+ u8 t = buffer[i];\r
+ hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];\r
+ hex_buffer[2 * i + 1] = DIGITS[t & 0xf];\r
+ }\r
+\r
+ gdb_put_packet(connection, hex_buffer, len * 2);\r
+\r
+ free(hex_buffer);\r
+ }\r
+ else\r
+ {\r
+ retval = gdb_memory_packet_error(connection, retval);\r
+ }\r
+\r
+ free(buffer);\r
+\r
+ return retval;\r
+}\r
+\r
+int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ char *separator;\r
+ u32 addr = 0;\r
+ u32 len = 0;\r
+\r
+ u8 *buffer;\r
+\r
+ int i;\r
+ int retval;\r
+\r
+ /* skip command character */\r
+ packet++;\r
+\r
+ addr = strtoul(packet, &separator, 16);\r
+\r
+ if (*separator != ',')\r
+ {\r
+ ERROR("incomplete write memory packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ len = strtoul(separator+1, &separator, 16);\r
+\r
+ if (*(separator++) != ':')\r
+ {\r
+ ERROR("incomplete write memory packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ buffer = malloc(len);\r
+\r
+ DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);\r
+\r
+ for (i=0; i<len; i++)\r
+ {\r
+ u32 tmp;\r
+ sscanf(separator + 2*i, "%2x", &tmp);\r
+ buffer[i] = tmp;\r
+ }\r
+\r
+ retval = target_write_buffer(target, addr, len, buffer);\r
+\r
+ if (retval == ERROR_OK)\r
+ {\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ else\r
+ {\r
+ if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)\r
+ return retval; \r
+ }\r
+\r
+ free(buffer);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ char *separator;\r
+ u32 addr = 0;\r
+ u32 len = 0;\r
+\r
+ int retval;\r
+\r
+ /* skip command character */\r
+ packet++;\r
+\r
+ addr = strtoul(packet, &separator, 16);\r
+\r
+ if (*separator != ',')\r
+ {\r
+ ERROR("incomplete write memory binary packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ len = strtoul(separator+1, &separator, 16);\r
+\r
+ if (*(separator++) != ':')\r
+ {\r
+ ERROR("incomplete write memory binary packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ retval = ERROR_OK;\r
+ if (len)\r
+ {\r
+ DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);\r
+\r
+ retval = target_write_buffer(target, addr, len, (u8*)separator);\r
+ }\r
+\r
+ if (retval == ERROR_OK)\r
+ {\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ else\r
+ {\r
+ if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)\r
+ return retval; \r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ int current = 0;\r
+ u32 address = 0x0;\r
+\r
+ DEBUG("-");\r
+\r
+ if (packet_size > 1)\r
+ {\r
+ packet[packet_size] = 0;\r
+ address = strtoul(packet + 1, NULL, 16);\r
+ }\r
+ else\r
+ {\r
+ current = 1;\r
+ }\r
+\r
+ if (packet[0] == 'c')\r
+ {\r
+ DEBUG("continue");\r
+ target->type->resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */\r
+ }\r
+ else if (packet[0] == 's')\r
+ {\r
+ DEBUG("step");\r
+ target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */\r
+ }\r
+}\r
+\r
+int gdb_bp_wp_packet_error(connection_t *connection, int retval)\r
+{\r
+ switch (retval)\r
+ {\r
+ case ERROR_TARGET_NOT_HALTED:\r
+ ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ break;\r
+ case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:\r
+ gdb_send_error(connection, EBUSY);\r
+ break;\r
+ default:\r
+ ERROR("BUG: unexpected error %i", retval);\r
+ exit(-1);\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ int type;\r
+ enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;\r
+ enum watchpoint_rw wp_type;\r
+ u32 address;\r
+ u32 size;\r
+ char *separator;\r
+ int retval;\r
+\r
+ DEBUG("-");\r
+\r
+ type = strtoul(packet + 1, &separator, 16);\r
+\r
+ if (type == 0) /* memory breakpoint */\r
+ bp_type = BKPT_SOFT;\r
+ else if (type == 1) /* hardware breakpoint */\r
+ bp_type = BKPT_HARD;\r
+ else if (type == 2) /* write watchpoint */\r
+ wp_type = WPT_WRITE;\r
+ else if (type == 3) /* read watchpoint */\r
+ wp_type = WPT_READ;\r
+ else if (type == 4) /* access watchpoint */\r
+ wp_type = WPT_ACCESS;\r
+\r
+ if (*separator != ',')\r
+ {\r
+ ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ address = strtoul(separator+1, &separator, 16);\r
+\r
+ if (*separator != ',')\r
+ {\r
+ ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ size = strtoul(separator+1, &separator, 16);\r
+\r
+ switch (type)\r
+ {\r
+ case 0:\r
+ case 1:\r
+ if (packet[0] == 'Z')\r
+ {\r
+ if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)\r
+ {\r
+ if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)\r
+ return retval;\r
+ }\r
+ else\r
+ {\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ breakpoint_remove(target, address);\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ break;\r
+ case 2:\r
+ case 3:\r
+ case 4:\r
+ {\r
+ if (packet[0] == 'Z')\r
+ {\r
+ if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)\r
+ {\r
+ if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)\r
+ return retval;\r
+ }\r
+ else\r
+ {\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ watchpoint_remove(target, address);\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ break;\r
+ }\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+/* print out a string and allocate more space as needed, mainly used for XML at this point */\r
+void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...)\r
+{\r
+ if (*retval != ERROR_OK)\r
+ {\r
+ return;\r
+ }\r
+ int first = 1;\r
+ \r
+ for (;;)\r
+ {\r
+ if ((*xml == NULL) || (!first))\r
+ {\r
+ /* start by 0 to exercise all the code paths.\r
+ * Need minimum 2 bytes to fit 1 char and 0 terminator. */\r
+ \r
+ *size = *size * 2 + 2;\r
+ char *t = *xml;\r
+ *xml = realloc(*xml, *size);\r
+ if (*xml == NULL)\r
+ {\r
+ if (t)\r
+ free(t);\r
+ *retval = ERROR_SERVER_REMOTE_CLOSED;\r
+ return;\r
+ }\r
+ }\r
+ \r
+ va_list ap;\r
+ int ret;\r
+ va_start(ap, fmt);\r
+ ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap);\r
+ va_end(ap);\r
+ if ((ret > 0) && ((ret + 1) < *size - *pos))\r
+ {\r
+ *pos += ret;\r
+ return;\r
+ }\r
+ /* there was just enough or not enough space, allocate more. */\r
+ first = 0;\r
+ }\r
+}\r
+\r
+static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)\r
+{\r
+ char *separator;\r
+ \r
+ /* Extract and NUL-terminate the annex. */\r
+ *annex = buf;\r
+ while (*buf && *buf != ':')\r
+ buf++;\r
+ if (*buf == '\0')\r
+ return -1;\r
+ *buf++ = 0;\r
+ \r
+ /* After the read marker and annex, qXfer looks like a\r
+ * traditional 'm' packet. */\r
+ \r
+ *ofs = strtoul(buf, &separator, 16);\r
+\r
+ if (*separator != ',')\r
+ return -1;\r
+\r
+ *len = strtoul(separator+1, NULL, 16);\r
+ \r
+ return 0;\r
+}\r
+\r
+int gdb_calc_blocksize(flash_bank_t *bank)\r
+{\r
+ int i;\r
+ int block_size = 0xffffffff;\r
+ \r
+ /* loop through all sectors and return smallest sector size */\r
+ \r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ if (bank->sectors[i].size < block_size)\r
+ block_size = bank->sectors[i].size;\r
+ }\r
+ \r
+ return block_size;\r
+}\r
+\r
+int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ command_context_t *cmd_ctx = connection->cmd_ctx;\r
+ \r
+ if (strstr(packet, "qRcmd,"))\r
+ {\r
+ if (packet_size > 6)\r
+ {\r
+ char *cmd;\r
+ int i;\r
+ cmd = malloc((packet_size - 6)/2 + 1);\r
+ for (i=0; i < (packet_size - 6)/2; i++)\r
+ {\r
+ u32 tmp;\r
+ sscanf(packet + 6 + 2*i, "%2x", &tmp);\r
+ cmd[i] = tmp;\r
+ }\r
+ cmd[(packet_size - 6)/2] = 0x0;\r
+ \r
+ /* We want to print all debug output to GDB connection */\r
+ log_setCallback(gdb_log_callback, connection);\r
+ target_call_timer_callbacks();\r
+ command_run_line(cmd_ctx, cmd);\r
+ free(cmd);\r
+ }\r
+ gdb_put_packet(connection, "OK", 2);\r
+ return ERROR_OK;\r
+ }\r
+ else if (strstr(packet, "qCRC:"))\r
+ {\r
+ if (packet_size > 5)\r
+ {\r
+ int retval;\r
+ char gdb_reply[10];\r
+ char *separator;\r
+ u32 checksum;\r
+ u32 addr = 0;\r
+ u32 len = 0;\r
+ \r
+ /* skip command character */\r
+ packet += 5;\r
+ \r
+ addr = strtoul(packet, &separator, 16);\r
+ \r
+ if (*separator != ',')\r
+ {\r
+ ERROR("incomplete read memory packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+ \r
+ len = strtoul(separator + 1, NULL, 16);\r
+ \r
+ retval = target_checksum_memory(target, addr, len, &checksum);\r
+ \r
+ if (retval == ERROR_OK)\r
+ {\r
+ snprintf(gdb_reply, 10, "C%8.8x", checksum);\r
+ gdb_put_packet(connection, gdb_reply, 9);\r
+ }\r
+ else\r
+ {\r
+ if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)\r
+ return retval; \r
+ }\r
+ \r
+ return ERROR_OK;\r
+ }\r
+ }\r
+ else if (strstr(packet, "qSupported"))\r
+ {\r
+ /* we currently support packet size and qXfer:memory-map:read (if enabled)\r
+ * disable qXfer:features:read for the moment */\r
+ int retval = ERROR_OK;\r
+ char *buffer = NULL;\r
+ int pos = 0;\r
+ int size = 0;\r
+\r
+ xml_printf(&retval, &buffer, &pos, &size, \r
+ "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",\r
+ (GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-');\r
+ \r
+ if (retval != ERROR_OK)\r
+ {\r
+ gdb_send_error(connection, 01);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ gdb_put_packet(connection, buffer, strlen(buffer));\r
+ free(buffer);\r
+ \r
+ return ERROR_OK;\r
+ }\r
+ else if (strstr(packet, "qXfer:memory-map:read::"))\r
+ {\r
+ /* We get away with only specifying flash here. Regions that are not\r
+ * specified are treated as if we provided no memory map(if not we \r
+ * could detect the holes and mark them as RAM).\r
+ * Normally we only execute this code once, but no big deal if we\r
+ * have to regenerate it a couple of times. */\r
+ \r
+ flash_bank_t *p;\r
+ char *xml = NULL;\r
+ int size = 0;\r
+ int pos = 0;\r
+ int retval = ERROR_OK;\r
+ \r
+ int offset;\r
+ int length;\r
+ char *separator;\r
+ int blocksize;\r
+ \r
+ /* skip command character */\r
+ packet += 23;\r
+ \r
+ offset = strtoul(packet, &separator, 16);\r
+ length = strtoul(separator + 1, &separator, 16);\r
+ \r
+ xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");\r
+ \r
+ int i = 0;\r
+ for (;;)\r
+ {\r
+ p = get_flash_bank_by_num(i);\r
+ if (p == NULL)\r
+ break;\r
+ \r
+ /* if device has uneven sector sizes, eg. str7, lpc\r
+ * we pass the smallest sector size to gdb memory map */\r
+ blocksize = gdb_calc_blocksize(p);\r
+ \r
+ xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \\r
+ "<property name=\"blocksize\">0x%x</property>\n" \\r
+ "</memory>\n", \\r
+ p->base, p->size, blocksize);\r
+ i++;\r
+ }\r
+ \r
+ xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");\r
+\r
+ if (retval != ERROR_OK)\r
+ {\r
+ gdb_send_error(connection, retval);\r
+ return retval;\r
+ }\r
+ \r
+ if (offset + length > pos)\r
+ {\r
+ length = pos - offset;\r
+ }\r
+\r
+ char *t = malloc(length + 1);\r
+ t[0] = 'l';\r
+ memcpy(t + 1, xml + offset, length);\r
+ gdb_put_packet(connection, t, length + 1);\r
+ \r
+ free(t);\r
+ free(xml);\r
+ return ERROR_OK;\r
+ }\r
+ else if (strstr(packet, "qXfer:features:read:"))\r
+ { \r
+ char *xml = NULL;\r
+ int size = 0;\r
+ int pos = 0;\r
+ int retval = ERROR_OK;\r
+ \r
+ int offset;\r
+ unsigned int length;\r
+ char *annex;\r
+ \r
+ /* skip command character */\r
+ packet += 20;\r
+ \r
+ if (decode_xfer_read(packet, &annex, &offset, &length) < 0)\r
+ {\r
+ gdb_send_error(connection, 01);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ if (strcmp(annex, "target.xml") != 0)\r
+ {\r
+ gdb_send_error(connection, 01);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ xml_printf(&retval, &xml, &pos, &size, \\r
+ "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");\r
+ \r
+ if (retval != ERROR_OK)\r
+ {\r
+ gdb_send_error(connection, retval);\r
+ return retval;\r
+ }\r
+ \r
+ gdb_put_packet(connection, xml, strlen(xml) + 1);\r
+ \r
+ free(xml);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ gdb_put_packet(connection, "", 0);\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+ gdb_connection_t *gdb_connection = connection->priv;\r
+ gdb_service_t *gdb_service = connection->service->priv;\r
+ int result;\r
+\r
+ /* if flash programming disabled - send a empty reply */\r
+ \r
+ if (gdb_flash_program == 0)\r
+ {\r
+ gdb_put_packet(connection, "", 0);\r
+ return ERROR_OK;\r
+ }\r
+ \r
+ if (strstr(packet, "vFlashErase:"))\r
+ {\r
+ unsigned long addr;\r
+ unsigned long length;\r
+ \r
+ char *parse = packet + 12;\r
+ if (*parse == '\0')\r
+ {\r
+ ERROR("incomplete vFlashErase packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ addr = strtoul(parse, &parse, 16);\r
+\r
+ if (*(parse++) != ',' || *parse == '\0')\r
+ {\r
+ ERROR("incomplete vFlashErase packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+\r
+ length = strtoul(parse, &parse, 16);\r
+\r
+ if (*parse != '\0')\r
+ {\r
+ ERROR("incomplete vFlashErase packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+ \r
+ /* assume all sectors need erasing - stops any problems\r
+ * when flash_write is called multiple times */\r
+ flash_set_dirty();\r
+ \r
+ /* perform any target specific operations before the erase */\r
+ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);\r
+ \r
+ /* perform erase */\r
+ if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)\r
+ {\r
+ /* GDB doesn't evaluate the actual error number returned,\r
+ * treat a failed erase as an I/O error\r
+ */\r
+ gdb_send_error(connection, EIO);\r
+ ERROR("flash_erase returned %i", result);\r
+ }\r
+ else\r
+ gdb_put_packet(connection, "OK", 2);\r
+ \r
+ return ERROR_OK;\r
+ }\r
+\r
+ if (strstr(packet, "vFlashWrite:"))\r
+ {\r
+ unsigned long addr;\r
+ unsigned long length;\r
+ char *parse = packet + 12;\r
+\r
+ if (*parse == '\0')\r
+ {\r
+ ERROR("incomplete vFlashErase packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+ addr = strtoul(parse, &parse, 16);\r
+ if (*(parse++) != ':')\r
+ {\r
+ ERROR("incomplete vFlashErase packet received, dropping connection");\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ }\r
+ length = packet_size - (parse - packet);\r
+ \r
+ /* create a new image if there isn't already one */\r
+ if (gdb_connection->vflash_image == NULL)\r
+ {\r
+ gdb_connection->vflash_image = malloc(sizeof(image_t));\r
+ image_open(gdb_connection->vflash_image, "", "build");\r
+ }\r
+\r
+ /* create new section with content from packet buffer */\r
+ image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);\r
+\r
+ gdb_put_packet(connection, "OK", 2);\r
+\r
+ return ERROR_OK;\r
+ }\r
+\r
+ if (!strcmp(packet, "vFlashDone"))\r
+ {\r
+ u32 written;\r
+\r
+ /* process the flashing buffer. No need to erase as GDB\r
+ * always issues a vFlashErase first. */\r
+ if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK)\r
+ {\r
+ if (result == ERROR_FLASH_DST_OUT_OF_BANK)\r
+ gdb_put_packet(connection, "E.memtype", 9);\r
+ else\r
+ gdb_send_error(connection, EIO);\r
+ }\r
+ else\r
+ {\r
+ DEBUG("wrote %u bytes from vFlash image to flash", written);\r
+ gdb_put_packet(connection, "OK", 2);\r
+ }\r
+ \r
+ image_close(gdb_connection->vflash_image);\r
+ free(gdb_connection->vflash_image);\r
+ gdb_connection->vflash_image = NULL;\r
+ \r
+ return ERROR_OK;\r
+ }\r
+\r
+ gdb_put_packet(connection, "", 0);\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_detach(connection_t *connection, target_t *target)\r
+{\r
+ switch( detach_mode )\r
+ {\r
+ case GDB_DETACH_RESUME:\r
+ target->type->resume(target, 1, 0, 1, 0);\r
+ break;\r
+ \r
+ case GDB_DETACH_RESET:\r
+ target_process_reset(connection->cmd_ctx);\r
+ break;\r
+ \r
+ case GDB_DETACH_HALT:\r
+ target->type->halt(target);\r
+ break;\r
+ \r
+ case GDB_DETACH_NOTHING:\r
+ break;\r
+ }\r
+ \r
+ gdb_put_packet(connection, "OK", 2);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+static void gdb_log_callback(void *priv, const char *file, int line, \r
+ const char *function, const char *format, va_list args)\r
+{\r
+ connection_t *connection = priv;\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ \r
+ if (gdb_con->busy)\r
+ {\r
+ /* do not reply this using the O packet */\r
+ return;\r
+ }\r
+\r
+ char *t = allocPrintf(format, args);\r
+ if (t == NULL)\r
+ return;\r
+ \r
+ gdb_output_con(connection, t); \r
+ \r
+ free(t);\r
+}\r
+\r
+int gdb_input_inner(connection_t *connection)\r
+{\r
+ gdb_service_t *gdb_service = connection->service->priv;\r
+ target_t *target = gdb_service->target;\r
+ char packet[GDB_BUFFER_SIZE];\r
+ int packet_size;\r
+ int retval;\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ static int extended_protocol = 0;\r
+\r
+ /* drain input buffer */\r
+ do\r
+ {\r
+ packet_size = GDB_BUFFER_SIZE-1;\r
+ if ((retval = gdb_get_packet(connection, packet, &packet_size)) != ERROR_OK)\r
+ {\r
+ return retval;\r
+ }\r
+\r
+ /* terminate with zero */\r
+ packet[packet_size] = 0;\r
+\r
+ DEBUG("received packet: '%s'", packet);\r
+\r
+ if (packet_size > 0)\r
+ {\r
+ retval = ERROR_OK;\r
+ switch (packet[0])\r
+ {\r
+ case 'H':\r
+ /* Hct... -- set thread \r
+ * we don't have threads, send empty reply */\r
+ gdb_put_packet(connection, NULL, 0);\r
+ break;\r
+ case 'q':\r
+ retval = gdb_query_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'g':\r
+ retval = gdb_get_registers_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'G':\r
+ retval = gdb_set_registers_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'p':\r
+ retval = gdb_get_register_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'P':\r
+ retval = gdb_set_register_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'm':\r
+ retval = gdb_read_memory_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'M':\r
+ retval = gdb_write_memory_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'z':\r
+ case 'Z':\r
+ retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case '?':\r
+ gdb_last_signal_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'c':\r
+ case 's':\r
+ {\r
+ /* We're running/stepping, in which case we can \r
+ * forward log output until the target is halted */\r
+ gdb_connection_t *gdb_con = connection->priv;\r
+ gdb_con->frontend_state = TARGET_RUNNING;\r
+ log_setCallback(gdb_log_callback, connection);\r
+ gdb_step_continue_packet(connection, target, packet, packet_size);\r
+ }\r
+ break;\r
+ case 'v':\r
+ retval = gdb_v_packet(connection, target, packet, packet_size);\r
+ break;\r
+ case 'D':\r
+ retval = gdb_detach(connection, target);\r
+ extended_protocol = 0;\r
+ break;\r
+ case 'X':\r
+ if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)\r
+ return retval;\r
+ break;\r
+ case 'k':\r
+ if (extended_protocol != 0)\r
+ break;\r
+ gdb_put_packet(connection, "OK", 2);\r
+ return ERROR_SERVER_REMOTE_CLOSED;\r
+ case '!':\r
+ /* handle extended remote protocol */\r
+ extended_protocol = 1;\r
+ gdb_put_packet(connection, "OK", 2);\r
+ break;\r
+ case 'R':\r
+ /* handle extended restart packet */\r
+ target_process_reset(connection->cmd_ctx);\r
+ break;\r
+ default:\r
+ /* ignore unkown packets */\r
+ DEBUG("ignoring 0x%2.2x packet", packet[0]);\r
+ gdb_put_packet(connection, NULL, 0);\r
+ break;\r
+ }\r
+\r
+ /* if a packet handler returned an error, exit input loop */\r
+ if (retval != ERROR_OK)\r
+ return retval;\r
+ }\r
+\r
+ if (gdb_con->ctrl_c)\r
+ {\r
+ if (target->state == TARGET_RUNNING)\r
+ {\r
+ target->type->halt(target);\r
+ gdb_con->ctrl_c = 0;\r
+ }\r
+ }\r
+\r
+ } while (gdb_con->buf_cnt > 0);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_input(connection_t *connection)\r
+{\r
+ int retval = gdb_input_inner(connection);\r
+ if (retval == ERROR_SERVER_REMOTE_CLOSED)\r
+ return retval;\r
+ /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_init()\r
+{\r
+ gdb_service_t *gdb_service;\r
+ target_t *target = targets;\r
+ int i = 0;\r
+\r
+ if (!target)\r
+ {\r
+ WARNING("no gdb ports allocated as no target has been specified");\r
+ return ERROR_OK;\r
+ }\r
+\r
+ if (gdb_port == 0)\r
+ {\r
+ WARNING("no gdb port specified, using default port 3333");\r
+ gdb_port = 3333;\r
+ }\r
+\r
+ while (target)\r
+ {\r
+ char service_name[8];\r
+\r
+ snprintf(service_name, 8, "gdb-%2.2i", i);\r
+\r
+ gdb_service = malloc(sizeof(gdb_service_t));\r
+ gdb_service->target = target;\r
+\r
+ add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);\r
+\r
+ DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);\r
+\r
+ i++;\r
+ target = target->next;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+/* daemon configuration command gdb_port */\r
+int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ if (argc == 0)\r
+ return ERROR_OK;\r
+\r
+ /* only if the port wasn't overwritten by cmdline */\r
+ if (gdb_port == 0)\r
+ gdb_port = strtoul(args[0], NULL, 0);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ if (argc == 1)\r
+ {\r
+ if (strcmp(args[0], "resume") == 0)\r
+ {\r
+ detach_mode = GDB_DETACH_RESUME;\r
+ return ERROR_OK;\r
+ }\r
+ else if (strcmp(args[0], "reset") == 0)\r
+ {\r
+ detach_mode = GDB_DETACH_RESET;\r
+ return ERROR_OK;\r
+ }\r
+ else if (strcmp(args[0], "halt") == 0)\r
+ {\r
+ detach_mode = GDB_DETACH_HALT;\r
+ return ERROR_OK;\r
+ }\r
+ else if (strcmp(args[0], "nothing") == 0)\r
+ {\r
+ detach_mode = GDB_DETACH_NOTHING;\r
+ return ERROR_OK;\r
+ }\r
+ }\r
+ \r
+ WARNING("invalid gdb_detach configuration directive: %s", args[0]);\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ if (argc == 1)\r
+ {\r
+ if (strcmp(args[0], "enable") == 0)\r
+ {\r
+ gdb_use_memory_map = 1;\r
+ return ERROR_OK;\r
+ }\r
+ else if (strcmp(args[0], "disable") == 0)\r
+ {\r
+ gdb_use_memory_map = 0;\r
+ return ERROR_OK;\r
+ }\r
+ }\r
+ \r
+ WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ if (argc == 1)\r
+ {\r
+ if (strcmp(args[0], "enable") == 0)\r
+ {\r
+ gdb_flash_program = 1;\r
+ return ERROR_OK;\r
+ }\r
+ else if (strcmp(args[0], "disable") == 0)\r
+ {\r
+ gdb_flash_program = 0;\r
+ return ERROR_OK;\r
+ }\r
+ }\r
+ \r
+ WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);\r
+ return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ if (argc == 1)\r
+ {\r
+ if (strcmp(args[0], "enable") == 0)\r
+ {\r
+ gdb_report_data_abort = 1;\r
+ return ERROR_OK;\r
+ }\r
+ else if (strcmp(args[0], "disable") == 0)\r
+ {\r
+ gdb_report_data_abort = 0;\r
+ return ERROR_OK;\r
+ }\r
+ }\r
+ \r
+ WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);\r
+ return ERROR_OK;\r
+}\r
+\r
+int gdb_register_commands(command_context_t *command_context)\r
+{\r
+ register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,\r
+ COMMAND_CONFIG, "");\r
+ register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,\r
+ COMMAND_CONFIG, "");\r
+ register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command,\r
+ COMMAND_CONFIG, "");\r
+ register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,\r
+ COMMAND_CONFIG, "");\r
+ register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,\r
+ COMMAND_CONFIG, "");\r
+ return ERROR_OK;\r
+}\r
int target_write_u16(struct target_s *target, u32 address, u16 value);
int target_write_u8(struct target_s *target, u32 address, u8 value);
+/* Issues USER() statements with target state information */
+int target_arch_state(struct target_s *target);
+
#define ERROR_TARGET_INVALID (-300)
#define ERROR_TARGET_INIT_FAILED (-301)
#define ERROR_TARGET_TIMEOUT (-302)