- endianess fixes everywhere but in the flash code. flashing might still be broken...
[fw/openocd] / src / flash / at91sam7.c
1 /***************************************************************************
2  *   Copyright (C) 2006 by Magnus Lundin                                   *
3  *   lundin@mlu.mine.nu                                                        *
4  *                                                                                                             *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 /***************************************************************************
22 There are some things to notice
23
24 * AT91SAM7S64 is tested
25 * All AT91SAM7Sxx  and  AT91SAM7Xxx should work but is not tested
26 * All parameters are identified from onchip configuartion registers 
27 *
28 * The flash controller handles erases automatically on a page (128/265 byte) basis
29 * Only an EraseAll command is supported by the controller
30 * Partial erases can be implemented in software by writing one 0xFFFFFFFF word to 
31 * some location in every page in the region to be erased
32 *  
33 * Lock regions (sectors) are 32 or 64 pages
34 *
35  ***************************************************************************/
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "replacements.h"
41
42 #include "at91sam7.h"
43
44 #include "flash.h"
45 #include "target.h"
46 #include "log.h"
47 #include "binarybuffer.h"
48 #include "types.h"
49
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53
54 int at91sam7_register_commands(struct command_context_s *cmd_ctx);
55 int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
56 int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
57 int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
58 int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
59 int at91sam7_probe(struct flash_bank_s *bank);
60 int at91sam7_erase_check(struct flash_bank_s *bank);
61 int at91sam7_protect_check(struct flash_bank_s *bank);
62 int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
63
64 u32 at91sam7_get_flash_status(flash_bank_t *bank);
65 void at91sam7_set_flash_mode(flash_bank_t *bank,int mode);
66 u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout);
67 int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
68
69 flash_driver_t at91sam7_flash =
70 {
71         .name = "at91sam7",
72         .register_commands = at91sam7_register_commands,
73         .flash_bank_command = at91sam7_flash_bank_command,
74         .erase = at91sam7_erase,
75         .protect = at91sam7_protect,
76         .write = at91sam7_write,
77         .probe = at91sam7_probe,
78         .erase_check = at91sam7_erase_check,
79         .protect_check = at91sam7_protect_check,
80         .info = at91sam7_info
81 };
82
83
84 char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
85 long NVPSIZ[16] = {
86    0,
87    0x2000, /*  8K */
88    0x4000, /* 16K */ 
89    0x8000, /* 32K */
90    -1,
91    0x10000, /* 64K */
92    -1,
93    0x20000, /* 128K */
94    -1,
95    0x40000, /* 256K */
96    0x80000, /* 512K */
97    -1,
98    0x100000, /* 1024K */
99    -1,
100    0x200000, /* 2048K */
101    -1
102 };
103
104 long SRAMSIZ[16] = {
105    -1,
106    0x0400, /*  1K */
107    0x0800, /*  2K */ 
108    -1, 
109    0x1c000,  /* 112K */
110    0x1000,  /*   4K */
111    0x14000, /*  80K */
112    0x28000, /* 160K */
113    0x2000,  /*   8K */
114    0x4000,  /*  16K */
115    0x8000,  /*  32K */
116    0x10000, /*  64K */
117    0x20000, /* 128K */
118    0x40000, /* 256K */
119    0x18000, /* 96K */
120    0x80000, /* 512K */
121 };
122
123 int at91sam7_register_commands(struct command_context_s *cmd_ctx)
124 {
125         command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);
126         register_command(cmd_ctx, at91sam7_cmd, "gpnvm", at91sam7_handle_gpnvm_command, COMMAND_EXEC,
127                         "at91sam7 gpnvm <num> <bit> set|clear, set or clear at91sam7 gpnvm bit");
128
129         return ERROR_OK;
130 }
131
132 u32 at91sam7_get_flash_status(flash_bank_t *bank)
133 {
134         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
135         target_t *target = at91sam7_info->target;
136         u32 fsr;
137         
138         target->type->read_memory(target, MC_FSR, 4, 1, (u8 *)&fsr);
139         fsr = target_buffer_get_u32(target, (u8 *)&fsr);
140         
141         return fsr;
142 }
143
144 /** Read clock configuration and set at91sam7_info->usec_clocks*/ 
145 void at91sam7_read_clock_info(flash_bank_t *bank)
146 {
147         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
148         target_t *target = at91sam7_info->target;
149         unsigned long mckr, mcfr, pllr, tmp, status, mainfreq;
150         unsigned int css, pres, mul, div;
151
152         /* Read main clock freqency register */
153         target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr);
154         /* Read master clock register */
155         target->type->read_memory(target, PMC_MCKR, 4, 1, (u8 *)&mckr);
156         /* Read Clock Generator PLL Register  */
157         target->type->read_memory(target, CKGR_PLLR, 4, 1, (u8 *)&pllr);
158
159         pres = (mckr>>2)&0x7;
160         mul = (pllr>>16)&0x7FF;
161         div = pllr&0xFF;
162
163         at91sam7_info->mck_valid = 0;
164         switch (mckr & PMC_MCKR_CSS) {
165         case 0:                 /* Slow Clock */
166                 at91sam7_info->mck_valid = 1;
167                 tmp = RC_FREQ;
168                 break;
169         case 1:                 /* Main Clock */
170                 if (mcfr & CKGR_MCFR_MAINRDY) 
171                 {
172                         at91sam7_info->mck_valid = 1;
173                         mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
174                         tmp = mainfreq;
175                 }
176                 break;
177                   
178         case 2:                 /* Reserved */
179                 break;
180         case 3:         /* PLL Clock */
181                 if (mcfr & CKGR_MCFR_MAINRDY) 
182                 {
183                         target->type->read_memory(target, CKGR_PLLR, 4, 1,
184                                                   (u8 *)&pllr);
185                         if (!(pllr & CKGR_PLLR_DIV))
186                                 break; /* 0 Hz */
187                         at91sam7_info->mck_valid = 1;
188                         mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
189                         /* Integer arithmetic should have sufficient precision
190                            as long as PLL is properly configured. */
191                         tmp = mainfreq / (pllr & CKGR_PLLR_DIV) *
192                           (((pllr & CKGR_PLLR_MUL) >> 16) + 1);
193                 }
194                 break;
195         }
196         
197         /* Prescaler adjust */
198         if (((mckr & PMC_MCKR_PRES) >> 2) == 7)
199                 at91sam7_info->mck_valid = 0;
200         else
201                 at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
202
203         /* Forget old flash timing */
204         at91sam7_set_flash_mode(bank,0);
205 }
206
207 /* Setup the timimg registers for nvbits or normal flash */
208 void at91sam7_set_flash_mode(flash_bank_t *bank,int mode)
209 {
210         u32 fmr, fmcn = 0, fws = 0;
211         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
212         target_t *target = at91sam7_info->target;
213         
214         if (mode && (mode != at91sam7_info->flashmode)) {
215                 /* Always round up (ceil) */
216                 if (mode==1)
217                         /* main clocks in 1uS */
218                         fmcn = (at91sam7_info->mck_freq/1000000ul)+1;
219                 else if (mode==2)
220                         /* main clocks in 1.5uS */
221                         fmcn = (at91sam7_info->mck_freq/666666ul)+1;
222
223                 /* Only allow fmcn=0 if clock period is > 30 us. */
224                 if (at91sam7_info->mck_freq <= 33333333ul)
225                         fmcn = 0;
226                 else
227                         fws = 1;
228
229                 DEBUG("fmcn: %i", fmcn); 
230                 fmr = fmcn << 16 | fws << 8;
231                 target->type->write_memory(target, MC_FMR, 4, 1, (u8 *)&fmr);
232         }
233         at91sam7_info->flashmode = mode;                
234 }
235
236 u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout)
237 {
238         u32 status;
239         
240         while ((!((status = at91sam7_get_flash_status(bank)) & 0x01)) && (timeout-- > 0))
241         {
242                 DEBUG("status: 0x%x", status);
243                 usleep(1000);
244         }
245         
246         DEBUG("status: 0x%x", status);
247
248         if (status&0x0C)
249         {
250                 ERROR("status register: 0x%x", status);
251                 if (status & 0x4)
252                         ERROR("Lock Error Bit Detected, Operation Abort");
253                 if (status & 0x8)
254                         ERROR("Invalid command and/or bad keyword, Operation Abort");
255                 if (status & 0x10)
256                         ERROR("Security Bit Set, Operation Abort");
257         }
258         
259         return status;
260 }
261
262 /* Send one command to the AT91SAM flash controller */
263 int at91sam7_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen) 
264 {
265         u32 fcr;
266         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
267         target_t *target = at91sam7_info->target;
268
269         fcr = (0x5A<<24) | (pagen<<8) | cmd; 
270         target->type->write_memory(target, MC_FCR, 4, 1, (u8 *)&fcr);
271         DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
272
273         if (at91sam7_wait_status_busy(bank, 10)&0x0C) 
274         {
275                 return ERROR_FLASH_OPERATION_FAILED;
276         }               
277         return ERROR_OK;
278 }
279
280 /* Read device id register, main clock frequency register and fill in driver info structure */
281 int at91sam7_read_part_info(struct flash_bank_s *bank)
282 {
283         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
284         target_t *target = at91sam7_info->target;
285         unsigned long cidr, mcfr, status;
286         
287         if (at91sam7_info->target->state != TARGET_HALTED)
288         {
289                 return ERROR_TARGET_NOT_HALTED;
290         }
291         
292         /* Read and parse chip identification register */
293         target->type->read_memory(target, DBGU_CIDR, 4, 1, (u8 *)&cidr);
294         
295         if (cidr == 0)
296         {
297                 WARNING("Cannot identify target as an AT91SAM");
298                 return ERROR_FLASH_OPERATION_FAILED;
299         }
300         
301         at91sam7_info->cidr = cidr;
302         at91sam7_info->cidr_ext = (cidr>>31)&0x0001;
303         at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;
304         at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;
305         at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;
306         at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
307         at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;
308         at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;
309         at91sam7_info->cidr_version = cidr&0x001F;
310         bank->size = NVPSIZ[at91sam7_info->cidr_nvpsiz];
311         at91sam7_info->target_name = "Unknown";
312         
313         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 );
314
315         /* Read main and master clock freqency register */
316         at91sam7_read_clock_info(bank);
317         
318         status = at91sam7_get_flash_status(bank);
319         at91sam7_info->lockbits = status>>16;
320         at91sam7_info->securitybit = (status>>4)&0x01;
321         
322         if (at91sam7_info->cidr_arch == 0x70 )
323         {
324                 at91sam7_info->num_nvmbits = 2;
325                 at91sam7_info->nvmbits = (status>>8)&0x03;
326                 bank->base = 0x100000;
327                 bank->bus_width = 4;
328                 if (bank->size==0x40000)  /* AT91SAM7S256 */
329                 {
330                         at91sam7_info->target_name = "AT91SAM7S256";
331                         at91sam7_info->num_lockbits = 16;
332                         at91sam7_info->pagesize = 256;
333                         at91sam7_info->pages_in_lockregion = 64;
334                         at91sam7_info->num_pages = 16*64;
335                 }
336                 if (bank->size==0x20000)  /* AT91SAM7S128 */
337                 {
338                         at91sam7_info->target_name = "AT91SAM7S128";
339                         at91sam7_info->num_lockbits = 8;
340                         at91sam7_info->pagesize = 256;
341                         at91sam7_info->pages_in_lockregion = 64;
342                         at91sam7_info->num_pages = 8*64;
343                 }
344                 if (bank->size==0x10000)  /* AT91SAM7S64 */
345                 {
346                         at91sam7_info->target_name = "AT91SAM7S64";
347                         at91sam7_info->num_lockbits = 16;
348                         at91sam7_info->pagesize = 128;
349                         at91sam7_info->pages_in_lockregion = 32;
350                         at91sam7_info->num_pages = 16*32;
351                 }
352                 if (bank->size==0x08000)  /* AT91SAM7S321/32 */
353                 {
354                         at91sam7_info->target_name = "AT91SAM7S321/32";
355                         at91sam7_info->num_lockbits = 8;
356                         at91sam7_info->pagesize = 128;
357                         at91sam7_info->pages_in_lockregion = 32;
358                         at91sam7_info->num_pages = 8*32;
359                 }
360                 
361                 return ERROR_OK;
362         }
363
364         if (at91sam7_info->cidr_arch == 0x71 )
365         {
366                 at91sam7_info->num_nvmbits = 2;
367                 at91sam7_info->nvmbits = (status>>8)&0x03;
368                 bank->base = 0x100000;
369                 bank->bus_width = 4;
370                 if (bank->size==0x40000)  /* AT91SAM7XC256 */
371                 {
372                         at91sam7_info->target_name = "AT91SAM7XC256";
373                         at91sam7_info->num_lockbits = 16;
374                         at91sam7_info->pagesize = 256;
375                         at91sam7_info->pages_in_lockregion = 64;
376                         at91sam7_info->num_pages = 16*64;
377                 }
378                 if (bank->size==0x20000)  /* AT91SAM7XC128 */
379                 {
380                         at91sam7_info->target_name = "AT91SAM7XC128";
381                         at91sam7_info->num_lockbits = 8;
382                         at91sam7_info->pagesize = 256;
383                         at91sam7_info->pages_in_lockregion = 64;
384                         at91sam7_info->num_pages = 8*64;
385                 }
386                 
387                 return ERROR_OK;
388         }
389         
390         if (at91sam7_info->cidr_arch == 0x75 )
391         {
392                 at91sam7_info->num_nvmbits = 3;
393                 at91sam7_info->nvmbits = (status>>8)&0x07;
394                 bank->base = 0x100000;
395                 bank->bus_width = 4;
396                 if (bank->size==0x40000)  /* AT91SAM7X256 */
397                 {
398                         at91sam7_info->target_name = "AT91SAM7X256";
399                         at91sam7_info->num_lockbits = 16;
400                         at91sam7_info->pagesize = 256;
401                         at91sam7_info->pages_in_lockregion = 64;
402                         at91sam7_info->num_pages = 16*64;
403                 }
404                 if (bank->size==0x20000)  /* AT91SAM7X128 */
405                 {
406                         at91sam7_info->target_name = "AT91SAM7X128";
407                         at91sam7_info->num_lockbits = 8;
408                         at91sam7_info->pagesize = 256;
409                         at91sam7_info->pages_in_lockregion = 64;
410                         at91sam7_info->num_pages = 8*64;
411                 }
412         
413                 return ERROR_OK;
414         }
415         
416         if (at91sam7_info->cidr_arch == 0x60 )
417         {
418                 at91sam7_info->num_nvmbits = 3;
419                 at91sam7_info->nvmbits = (status>>8)&0x07;
420                 bank->base = 0x100000;
421                 bank->bus_width = 4;
422                 
423                 if (bank->size == 0x40000)  /* AT91SAM7A3 */
424                 {
425                         at91sam7_info->target_name = "AT91SAM7A3";
426                         at91sam7_info->num_lockbits = 16;
427                         at91sam7_info->pagesize = 256;
428                         at91sam7_info->pages_in_lockregion = 64;
429                         at91sam7_info->num_pages = 16*64;
430                 }
431                 return ERROR_OK;
432         }
433         
434    WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
435         
436    return ERROR_OK;
437 }
438
439 int at91sam7_erase_check(struct flash_bank_s *bank)
440 {
441         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
442         target_t *target = at91sam7_info->target;
443         int i;
444         
445         if (!at91sam7_info->working_area_size)
446         {
447         }
448         else
449         {       
450         }
451         
452         return ERROR_OK;
453 }
454
455 int at91sam7_protect_check(struct flash_bank_s *bank)
456 {
457         u32 status;
458         
459         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
460         target_t *target = at91sam7_info->target;
461
462         if (at91sam7_info->cidr == 0)
463         {
464                 at91sam7_read_part_info(bank);
465         }
466
467         if (at91sam7_info->cidr == 0)
468         {
469                 WARNING("Cannot identify target as an AT91SAM");
470                 return ERROR_FLASH_OPERATION_FAILED;
471         }
472                 
473         status = at91sam7_get_flash_status(bank);
474         at91sam7_info->lockbits = status>>16;
475         
476         return ERROR_OK;
477 }
478
479 int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
480 {
481         at91sam7_flash_bank_t *at91sam7_info;
482         
483         if (argc < 6)
484         {
485                 WARNING("incomplete flash_bank at91sam7 configuration");
486                 return ERROR_FLASH_BANK_INVALID;
487         }
488         
489         at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
490         bank->driver_priv = at91sam7_info;
491         
492         at91sam7_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
493         if (!at91sam7_info->target)
494         {
495                 ERROR("no target '%i' configured", args[5]);
496                 exit(-1);
497         }
498         
499         
500         /* part wasn't probed for info yet */
501         at91sam7_info->cidr = 0;
502         
503         return ERROR_OK;
504 }
505
506 int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
507 {
508         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
509         
510         if (at91sam7_info->target->state != TARGET_HALTED)
511         {
512                 return ERROR_TARGET_NOT_HALTED;
513         }
514         
515         if (at91sam7_info->cidr == 0)
516         {
517                 at91sam7_read_part_info(bank);
518         }
519
520         if (at91sam7_info->cidr == 0)
521         {
522                 WARNING("Cannot identify target as an AT91SAM");
523                 return ERROR_FLASH_OPERATION_FAILED;
524         }       
525         
526         if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
527         {
528                 return ERROR_FLASH_SECTOR_INVALID;
529         }
530
531         /* Configure the flash controller timing */
532         at91sam7_read_clock_info(bank); 
533         at91sam7_set_flash_mode(bank,2);
534
535         if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))
536         {
537                 return at91sam7_flash_command(bank, EA, 0);
538         }
539
540         WARNING("Can only erase the whole flash area, pages are autoerased on write");
541         return ERROR_FLASH_OPERATION_FAILED;
542 }
543
544 int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
545 {
546         u32 cmd, pagen, status;
547         int lockregion;
548         
549         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
550         target_t *target = at91sam7_info->target;
551         
552         if (at91sam7_info->target->state != TARGET_HALTED)
553         {
554                 return ERROR_TARGET_NOT_HALTED;
555         }
556         
557         if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
558         {
559                 return ERROR_FLASH_SECTOR_INVALID;
560         }
561         
562         if (at91sam7_info->cidr == 0)
563         {
564                 at91sam7_read_part_info(bank);
565         }
566
567         if (at91sam7_info->cidr == 0)
568         {
569                 WARNING("Cannot identify target as an AT91SAM");
570                 return ERROR_FLASH_OPERATION_FAILED;
571         }
572         
573         /* Configure the flash controller timing */
574         at91sam7_read_clock_info(bank); 
575         at91sam7_set_flash_mode(bank,1);
576         
577         for (lockregion=first;lockregion<=last;lockregion++) 
578         {
579                 pagen = lockregion*at91sam7_info->pages_in_lockregion;  
580                 if (set)
581                          cmd = SLB; 
582                 else
583                          cmd = CLB;             
584                 if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK) 
585                 {
586                         return ERROR_FLASH_OPERATION_FAILED;
587                 }       
588         }
589         
590         status = at91sam7_get_flash_status(bank);
591         at91sam7_info->lockbits = status>>16;
592                 
593         return ERROR_OK;
594 }
595
596
597 int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
598 {
599         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
600         target_t *target = at91sam7_info->target;
601         u32 dst_min_alignment, wcount, bytes_remaining = count;
602         u32 first_page, last_page, pagen, buffer_pos;
603         u32 fcr;
604         
605         if (at91sam7_info->target->state != TARGET_HALTED)
606         {
607                 return ERROR_TARGET_NOT_HALTED;
608         }
609         
610         if (at91sam7_info->cidr == 0)
611         {
612                 at91sam7_read_part_info(bank);
613         }
614
615         if (at91sam7_info->cidr == 0)
616         {
617                 WARNING("Cannot identify target as an AT91SAM");
618                 return ERROR_FLASH_OPERATION_FAILED;
619         }
620         
621         if (offset + count > bank->size)
622                 return ERROR_FLASH_DST_OUT_OF_BANK;
623         
624         dst_min_alignment = at91sam7_info->pagesize;
625
626         if (offset % dst_min_alignment)
627         {
628                 WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
629                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
630         }
631         
632         if (offset + count > bank->size)
633                 return ERROR_FLASH_DST_OUT_OF_BANK;
634         
635         if (at91sam7_info->cidr_arch == 0)
636                 return ERROR_FLASH_BANK_NOT_PROBED;
637
638         first_page = offset/dst_min_alignment;
639         last_page = CEIL(offset + count, dst_min_alignment);
640         
641         DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
642         
643         /* Configure the flash controller timing */     
644         at91sam7_read_clock_info(bank); 
645         at91sam7_set_flash_mode(bank,2);
646
647         for (pagen=first_page; pagen<last_page; pagen++) {
648                 if (bytes_remaining<dst_min_alignment) 
649                 count = bytes_remaining;
650                 else
651                 count = dst_min_alignment;
652                 bytes_remaining -= count;
653                 
654                 /* Write one block to the PageWriteBuffer */
655                 buffer_pos = (pagen-first_page)*dst_min_alignment;
656                 wcount = CEIL(count,4);
657                 target->type->write_memory(target, bank->base, 4, wcount, buffer+buffer_pos);
658                 
659                 /* Send Write Page command to Flash Controller */
660                 if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK) 
661                 {
662                         return ERROR_FLASH_OPERATION_FAILED;
663                 }       
664                 DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
665         }
666         
667         return ERROR_OK;
668 }
669
670
671 int at91sam7_probe(struct flash_bank_s *bank)
672 {
673         /* we can't probe on an at91sam7
674          * if this is an at91sam7, it has the configured flash
675          */
676         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
677         
678         if (at91sam7_info->cidr == 0)
679         {
680                 at91sam7_read_part_info(bank);
681         }
682
683         if (at91sam7_info->cidr == 0)
684         {
685                 WARNING("Cannot identify target as an AT91SAM");
686                 return ERROR_FLASH_OPERATION_FAILED;
687         }
688         return ERROR_OK;
689 }
690
691 int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
692 {
693         int printed;
694         at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
695         
696         at91sam7_read_part_info(bank);
697
698         if (at91sam7_info->cidr == 0)
699         {
700                 printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");
701                 buf += printed;
702                 buf_size -= printed;
703                 return ERROR_FLASH_OPERATION_FAILED;
704         }
705         
706         printed = snprintf(buf, buf_size, "\nat91sam7 information:\n");
707         buf += printed;
708         buf_size -= printed;
709         
710         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);
711         buf += printed;
712         buf_size -= printed;
713                         
714         printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz \n", at91sam7_info->mck_freq / 1000);
715         buf += printed;
716         buf_size -= printed;
717         
718         if (at91sam7_info->num_lockbits>0) {            
719                 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,at91sam7_info->num_pages/at91sam7_info->num_lockbits);
720                 buf += printed;
721                 buf_size -= printed;
722         }
723                         
724         printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);
725         buf += printed;
726         buf_size -= printed;
727
728         return ERROR_OK;
729 }
730
731 /* 
732 * On AT91SAM7S: When the gpnmv bits are set with 
733 * > at91sam7 gpnvm 0 bitnr set
734 * the changes are not visible in the flash controller status register MC_FSR 
735 * until the processor has been reset.
736 * On the Olimex board this requires a power cycle.
737 * Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3):
738 *       The maximum number of write/erase cycles for Non Volatile Memory bits is 100. This includes
739 *       Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
740 */
741 int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
742 {
743         flash_bank_t *bank;
744         int bit;
745         u8  flashcmd;
746         u32 status;
747         char *value;
748         at91sam7_flash_bank_t *at91sam7_info;
749
750         if (argc < 3)
751         {
752                 command_print(cmd_ctx, "at91sam7 gpnvm <num> <bit> <set|clear>");
753                 return ERROR_OK;
754         }
755         
756         bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
757         bit = atoi(args[1]);
758         value = args[2];
759
760         if (!bank)
761         {
762                 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
763                 return ERROR_OK;
764         }
765
766         at91sam7_info = bank->driver_priv;
767
768         if (at91sam7_info->target->state != TARGET_HALTED)
769         {
770                 return ERROR_TARGET_NOT_HALTED;
771         }
772         
773         if (at91sam7_info->cidr == 0)
774         {
775                 at91sam7_read_part_info(bank);
776         }
777
778         if (at91sam7_info->cidr == 0)
779         {
780                 WARNING("Cannot identify target as an AT91SAM");
781                 return ERROR_FLASH_OPERATION_FAILED;
782         }
783
784         if ((bit<0) || (at91sam7_info->num_nvmbits <= bit))
785         { 
786                 command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[1],at91sam7_info->target_name);
787                 return ERROR_OK;
788         }
789
790         if (strcmp(value, "set") == 0)
791         {
792                 flashcmd = SGPB;
793         }
794         else if (strcmp(value, "clear") == 0)
795         {
796                 flashcmd = CGPB;
797         }
798         else
799         {
800                 command_print(cmd_ctx, "usage: at91sam7 gpnvm <num> <bit> <set|clear>");
801                 return ERROR_OK;
802         }
803
804         /* Configure the flash controller timing */
805         at91sam7_read_clock_info(bank); 
806         at91sam7_set_flash_mode(bank,1);
807         
808         if (at91sam7_flash_command(bank, flashcmd, (u16)(bit)) != ERROR_OK) 
809         {
810                 return ERROR_FLASH_OPERATION_FAILED;
811         }       
812
813         status = at91sam7_get_flash_status(bank);
814         DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value 0x%x, status 0x%x \n",flashcmd,bit,status);
815         at91sam7_info->nvmbits = (status>>8)&((1<<at91sam7_info->num_nvmbits)-1);
816
817         return ERROR_OK;
818 }