X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fat91sam7.c;h=dd8bdeb5e1c354b4f8dcccbb08bb1c189fc0d9a9;hb=3acb107b9ae4e3d38d3fcfd29b455ebcfb444696;hp=348a8652d6824ac4dfab0d3f6a2661902e493d07;hpb=ef139a3a5e41fbcbabdf4be0ecbbb5591448ad2e;p=openocd.git diff --git a/src/flash/at91sam7.c b/src/flash/at91sam7.c index 348a8652d6..dd8bdeb5e1 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,37 +120,117 @@ 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 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; target_t *target = at91sam7_info->target; - long fsr; + u32 fsr; target->type->read_memory(target, MC_FSR, 4, 1, (u8 *)&fsr); + fsr = target_buffer_get_u32(target, (u8 *)&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 = 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) { - u32 fmcn, fmr; + u32 fmr, fmcn = 0, fws = 0; 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 <= 33333333ul) + fmcn = 0; + else + fws = 1; + DEBUG("fmcn: %i", fmcn); - fmr = fmcn<<16; - target->type->write_memory(target, MC_FSR, 4, 1, (u8 *)&fmr); - at91sam7_info->flashmode = mode; + fmr = fmcn << 16 | fws << 8; + target->type->write_memory(target, MC_FMR, 4, 1, (u8 *)&fmr); } + at91sam7_info->flashmode = mode; } u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout) @@ -174,6 +259,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 +308,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 +327,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 +335,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 +343,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 +351,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 +369,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 +377,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 +395,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 +403,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 +422,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 +476,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 +528,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 +570,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 +641,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; pagendriver_priv; - if (at91sam7_info->cidr == 0) - { - at91sam7_read_part_info(bank); - } + at91sam7_read_part_info(bank); if (at91sam7_info->cidr == 0) { @@ -632,7 +711,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 +727,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 "); + 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 "); + 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<num_nvmbits)-1); + + return ERROR_OK; +}