diff options
Diffstat (limited to 'src/flash')
-rw-r--r-- | src/flash/at91sam7.c | 237 | ||||
-rw-r--r-- | src/flash/at91sam7.h | 21 | ||||
-rw-r--r-- | src/flash/cfi.c | 6 | ||||
-rw-r--r-- | src/flash/flash.c | 6 | ||||
-rw-r--r-- | src/flash/lpc2000.c | 4 | ||||
-rw-r--r-- | src/flash/str7x.c | 5 |
6 files changed, 236 insertions, 43 deletions
diff --git a/src/flash/at91sam7.c b/src/flash/at91sam7.c index 348a8652..59ed2aa0 100644 --- a/src/flash/at91sam7.c +++ b/src/flash/at91sam7.c @@ -33,6 +33,11 @@ There are some things to notice * Lock regions (sectors) are 32 or 64 pages * ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" #include "at91sam7.h" @@ -59,7 +64,7 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size); u32 at91sam7_get_flash_status(flash_bank_t *bank); void at91sam7_set_flash_mode(flash_bank_t *bank,int mode); u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout); -int at91sam7_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); flash_driver_t at91sam7_flash = { @@ -115,6 +120,15 @@ long SRAMSIZ[16] = { 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) { at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; @@ -126,6 +140,69 @@ u32 at91sam7_get_flash_status(flash_bank_t *bank) 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 = at91sam7_info->target; + unsigned long mckr, mcfr, pllr, tmp, status, mainfreq; + unsigned int css, pres, mul, div; + + /* Read main clock freqency register */ + target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr); + /* Read master clock register */ + target->type->read_memory(target, PMC_MCKR, 4, 1, (u8 *)&mckr); + /* Read Clock Generator PLL Register */ + target->type->read_memory(target, CKGR_PLLR, 4, 1, (u8 *)&pllr); + + pres = (mckr>>2)&0x7; + mul = (pllr>>16)&0x7FF; + div = pllr&0xFF; + + at91sam7_info->mck_valid = 0; + switch (mckr & PMC_MCKR_CSS) { + case 0: /* Slow Clock */ + at91sam7_info->mck_valid = 1; + tmp = RC_FREQ; + break; + case 1: /* Main Clock */ + if (mcfr & CKGR_MCFR_MAINRDY) + { + at91sam7_info->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->type->read_memory(target, CKGR_PLLR, 4, 1, + (u8 *)&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 */ + at91sam7_set_flash_mode(bank,0); +} + /* Setup the timimg registers for nvbits or normal flash */ void at91sam7_set_flash_mode(flash_bank_t *bank,int mode) { @@ -133,19 +210,24 @@ void at91sam7_set_flash_mode(flash_bank_t *bank,int mode) at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; target_t *target = at91sam7_info->target; - if (mode != at91sam7_info->flashmode) { - /* mainf contains the number of main clocks in approx 500uS */ + if (mode && (mode != at91sam7_info->flashmode)) { + /* Always round up (ceil) */ if (mode==1) /* main clocks in 1uS */ - fmcn = (at91sam7_info->mainf>>9)+1; - else + fmcn = (at91sam7_info->mck_freq/1000000ul)+1; + else if (mode==2) /* main clocks in 1.5uS */ - fmcn = (at91sam7_info->mainf>>9)+(at91sam7_info->mainf>>10)+1; + fmcn = (at91sam7_info->mck_freq/666666ul)+1; + + /* Only allow fmcn=0 if clock period is > 30 us. */ + if (at91sam7_info->mck_freq <= 33333) + fmcn = 0; + DEBUG("fmcn: %i", fmcn); fmr = fmcn<<16; target->type->write_memory(target, MC_FSR, 4, 1, (u8 *)&fmr); - at91sam7_info->flashmode = mode; } + at91sam7_info->flashmode = mode; } u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout) @@ -174,6 +256,7 @@ u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout) return status; } +/* Send one command to the AT91SAM flash controller */ int at91sam7_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen) { u32 fcr; @@ -222,23 +305,12 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) 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"; DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch ); - /* Read main clock freqency register */ - target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr); - if (mcfr&0x10000) - { - at91sam7_info->mainrdy = 1; - at91sam7_info->mainf = mcfr&0xFFFF; - at91sam7_info->usec_clocks = mcfr>>9; - } - else - { - at91sam7_info->mainrdy = 0; - at91sam7_info->mainf = 0; - at91sam7_info->usec_clocks = 0; - } + /* Read main and master clock freqency register */ + at91sam7_read_clock_info(bank); status = at91sam7_get_flash_status(bank); at91sam7_info->lockbits = status>>16; @@ -252,6 +324,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) bank->bus_width = 4; 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; @@ -259,6 +332,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) } 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; @@ -266,6 +340,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) } 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; @@ -273,6 +348,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) } 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; @@ -290,6 +366,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) bank->bus_width = 4; 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; @@ -297,6 +374,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) } 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; @@ -314,6 +392,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) bank->bus_width = 4; 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; @@ -321,6 +400,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) } 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; @@ -339,6 +419,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank) if (bank->size == 0x40000) /* AT91SAM7A3 */ { + at91sam7_info->target_name = "AT91SAM7A3"; at91sam7_info->num_lockbits = 16; at91sam7_info->pagesize = 256; at91sam7_info->pages_in_lockregion = 64; @@ -392,14 +473,6 @@ int at91sam7_protect_check(struct flash_bank_s *bank) return ERROR_OK; } - -int at91sam7_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, "at91sam7 specific commands"); - - return ERROR_OK; -} - 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; @@ -452,11 +525,15 @@ int at91sam7_erase(struct flash_bank_s *bank, int first, int last) return ERROR_FLASH_SECTOR_INVALID; } + /* Configure the flash controller timing */ + at91sam7_read_clock_info(bank); + at91sam7_set_flash_mode(bank,2); + if ((first == 0) && (last == (at91sam7_info->num_lockbits-1))) { return at91sam7_flash_command(bank, EA, 0); } - + WARNING("Can only erase the whole flash area, pages are autoerased on write"); return ERROR_FLASH_OPERATION_FAILED; } @@ -490,7 +567,8 @@ int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last) return ERROR_FLASH_OPERATION_FAILED; } - /* Configure the flash controller timing */ + /* Configure the flash controller timing */ + at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank,1); for (lockregion=first;lockregion<=last;lockregion++) @@ -560,6 +638,7 @@ int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count); /* Configure the flash controller timing */ + at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank,2); for (pagen=first_page; pagen<last_page; pagen++) { @@ -611,10 +690,7 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size) int printed; at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; - if (at91sam7_info->cidr == 0) - { - at91sam7_read_part_info(bank); - } + at91sam7_read_part_info(bank); if (at91sam7_info->cidr == 0) { @@ -632,7 +708,7 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size) buf += printed; buf_size -= printed; - printed = snprintf(buf, buf_size, "main clock(estimated): %ikHz \n", at91sam7_info->mainf*2); + printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz \n", at91sam7_info->mck_freq / 1000); buf += printed; buf_size -= printed; @@ -648,3 +724,92 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size) return ERROR_OK; } + +/* +* On AT91SAM7S: When the gpnmv 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 (at91sam7_info->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,1); + + if (at91sam7_flash_command(bank, flashcmd, (u16)(bit)) != ERROR_OK) + { + return ERROR_FLASH_OPERATION_FAILED; + } + + status = at91sam7_get_flash_status(bank); + 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; +} diff --git a/src/flash/at91sam7.h b/src/flash/at91sam7.h index 8f9e3db7..c65600eb 100644 --- a/src/flash/at91sam7.h +++ b/src/flash/at91sam7.h @@ -28,7 +28,7 @@ typedef struct at91sam7_flash_bank_s struct target_s *target; u32 working_area; u32 working_area_size; - + /* chip id register */ u32 cidr; u16 cidr_ext; @@ -39,7 +39,8 @@ typedef struct at91sam7_flash_bank_s u16 cidr_nvpsiz2; u16 cidr_eproc; u16 cidr_version; - + char * target_name; + /* flash geometry */ u16 num_pages; u16 pagesize; @@ -54,17 +55,23 @@ typedef struct at91sam7_flash_bank_s u16 nvmbits; u8 securitybit; u8 flashmode; /* 0: not init, 1: fmcn for nvbits (1uS), 2: fmcn for flash (1.5uS) */ - + /* main clock status */ - u8 mainrdy; - u16 mainf; - u16 usec_clocks; + u8 mck_valid; + u32 mck_freq; } at91sam7_flash_bank_t; /* AT91SAM7 control registers */ #define DBGU_CIDR 0xFFFFF240 #define CKGR_MCFR 0xFFFFFC24 +#define CKGR_MCFR_MAINRDY 0x10000 +#define CKGR_PLLR 0xFFFFFC2c +#define CKGR_PLLR_DIV 0xff +#define CKGR_PLLR_MUL 0x07ff0000 +#define PMC_MCKR 0xFFFFFC30 +#define PMC_MCKR_CSS 0x03 +#define PMC_MCKR_PRES 0x1c #define MC_FMR 0xFFFFFF60 #define MC_FCR 0xFFFFFF64 #define MC_FSR 0xFFFFFF68 @@ -79,5 +86,7 @@ typedef struct at91sam7_flash_bank_s #define CGPB 0x0D #define SSB 0x0F +/* AT91SAM7 constants */ +#define RC_FREQ 32000 #endif /* AT91SAM7_H */ diff --git a/src/flash/cfi.c b/src/flash/cfi.c index 5e943676..3dc7885c 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -17,6 +17,12 @@ * 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 "cfi.h" #include "flash.h" diff --git a/src/flash/flash.c b/src/flash/flash.c index a5067cd2..0a713093 100644 --- a/src/flash/flash.c +++ b/src/flash/flash.c @@ -17,6 +17,10 @@ * 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 "log.h" @@ -506,7 +510,7 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha return ERROR_OK; } - if (!(binary = fopen(args[1], "r"))) + if (!(binary = fopen(args[1], "rb"))) { ERROR("couldn't open %s: %s", args[1], strerror(errno)); command_print(cmd_ctx, "couldn't open %s", args[1]); diff --git a/src/flash/lpc2000.c b/src/flash/lpc2000.c index b6fcb30b..68181c6f 100644 --- a/src/flash/lpc2000.c +++ b/src/flash/lpc2000.c @@ -17,6 +17,10 @@ * 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" diff --git a/src/flash/str7x.c b/src/flash/str7x.c index 2e3a6c8c..4d8d02e4 100644 --- a/src/flash/str7x.c +++ b/src/flash/str7x.c @@ -17,6 +17,11 @@ * 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" |