]> git.sur5r.net Git - openocd/blob - src/flash/stellaris.c
376a80fd84b05a83041dc2f2ccfdc3b57bb67e30
[openocd] / src / flash / stellaris.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 * STELLARIS is tested on LM3S811
23
24 *
25 *
26  ***************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "replacements.h"
32
33 #include "stellaris.h"
34 #include "cortex_m3.h"
35
36 #include "flash.h"
37 #include "target.h"
38 #include "log.h"
39 #include "binarybuffer.h"
40 #include "types.h"
41
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 int stellaris_register_commands(struct command_context_s *cmd_ctx);
47 int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
48 int stellaris_erase(struct flash_bank_s *bank, int first, int last);
49 int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last);
50 int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
51 int stellaris_probe(struct flash_bank_s *bank);
52 int stellaris_erase_check(struct flash_bank_s *bank);
53 int stellaris_protect_check(struct flash_bank_s *bank);
54 int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size);
55
56 u32 stellaris_get_flash_status(flash_bank_t *bank);
57 void stellaris_set_flash_mode(flash_bank_t *bank,int mode);
58 u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);
59
60 flash_driver_t stellaris_flash =
61 {
62         .name = "stellaris",
63         .register_commands = stellaris_register_commands,
64         .flash_bank_command = stellaris_flash_bank_command,
65         .erase = stellaris_erase,
66         .protect = stellaris_protect,
67         .write = stellaris_write,
68         .probe = stellaris_probe,
69         .erase_check = stellaris_erase_check,
70         .protect_check = stellaris_protect_check,
71         .info = stellaris_info
72 };
73
74
75 struct {
76         u32 partno;
77     char *partname;
78 }       StellarisParts[] =
79 {
80         {0x01,"LM3S101"},
81         {0x02,"LM3S102"},
82         {0x11,"LM3S301"},
83         {0x12,"LM3S310"},
84         {0x13,"LM3S315"},
85         {0x14,"LM3S316"},
86         {0x15,"LM3S328"},
87         {0x21,"LM3S601"},
88         {0x22,"LM3S610"},
89         {0x23,"LM3S611"},
90         {0x24,"LM3S612"},
91         {0x25,"LM3S613"},
92         {0x26,"LM3S615"},
93         {0x27,"LM3S628"},
94         {0x31,"LM3S801"},
95         {0x32,"LM3S811"},
96         {0x33,"LM3S812"},
97         {0x34,"LM3S815"},
98         {0x35,"LM3S828"},
99     {0x51,"LM3S2110"},
100     {0x84,"LM3S2139"},
101     {0xa2,"LM3S2410"},
102     {0x59,"LM3S2412"},
103     {0x56,"LM3S2432"},
104     {0x5a,"LM3S2533"},
105     {0x57,"LM3S2620"},
106     {0x85,"LM3S2637"},
107     {0x53,"LM3S2651"},
108     {0xa4,"LM3S2730"},
109     {0x52,"LM3S2739"},
110     {0x54,"LM3S2939"},
111     {0x8f,"LM3S2948"},
112     {0x58,"LM3S2950"},
113     {0x55,"LM3S2965"},
114     {0xa1,"LM3S6100"},
115     {0x74,"LM3S6110"},
116     {0xa5,"LM3S6420"},
117     {0x82,"LM3S6422"},
118     {0x75,"LM3S6432"},
119     {0x71,"LM3S6610"},
120     {0x83,"LM3S6633"},
121     {0x8b,"LM3S6637"},
122     {0xa3,"LM3S6730"},
123     {0x89,"LM3S6938"},
124     {0x78,"LM3S6952"},
125     {0x73,"LM3S6965"},
126         {0,"Unknown part"}
127 };
128
129 /***************************************************************************
130 *       openocd command interface                                              *
131 ***************************************************************************/
132
133 int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
134 {
135         stellaris_flash_bank_t *stellaris_info;
136         
137         if (argc < 6)
138         {
139                 WARNING("incomplete flash_bank stellaris configuration");
140                 return ERROR_FLASH_BANK_INVALID;
141         }
142         
143         stellaris_info = calloc(sizeof(stellaris_flash_bank_t),1);
144         bank->base = 0x0;
145         bank->driver_priv = stellaris_info;
146         
147         stellaris_info->target_name ="Unknown target";
148         stellaris_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
149         if (!stellaris_info->target)
150         {
151                 ERROR("no target '%s' configured", args[5]);
152                 exit(-1);
153         }
154         
155         /* part wasn't probed for info yet */
156         stellaris_info->did1 = 0;
157         
158         /* TODO Use an optional main oscillator clock rate in kHz from arg[6] */ 
159         return ERROR_OK;
160 }
161
162 int stellaris_register_commands(struct command_context_s *cmd_ctx)
163 {
164 /*
165         command_t *stellaris_cmd = register_command(cmd_ctx, NULL, "stellaris", NULL, COMMAND_ANY, NULL);
166         register_command(cmd_ctx, stellaris_cmd, "gpnvm", stellaris_handle_gpnvm_command, COMMAND_EXEC,
167                         "stellaris gpnvm <num> <bit> set|clear, set or clear stellaris gpnvm bit");
168 */
169         return ERROR_OK;
170 }
171
172 int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
173 {
174         int printed;
175         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
176         
177         stellaris_read_part_info(bank);
178
179         if (stellaris_info->did1 == 0)
180         {
181                 printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");
182                 buf += printed;
183                 buf_size -= printed;
184                 return ERROR_FLASH_OPERATION_FAILED;
185         }
186         
187     printed = snprintf(buf, buf_size, "\nLMI Stellaris information: Chip is class %i %s v%c.%i\n",
188          (stellaris_info->did0>>16)&0xff, stellaris_info->target_name,
189          'A' + (stellaris_info->did0>>8)&0xFF, (stellaris_info->did0)&0xFF);
190         buf += printed;
191         buf_size -= printed;
192
193         printed = snprintf(buf, buf_size, "did1: 0x%8.8x, arch: 0x%4.4x, eproc: %s, ramsize:%ik,  flashsize: %ik\n", 
194          stellaris_info->did1, stellaris_info->did1, "ARMV7M", (1+(stellaris_info->dc0>>16)&0xFFFF)/4, (1+stellaris_info->dc0&0xFFFF)*2);
195         buf += printed;
196         buf_size -= printed;
197
198         printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz,  rcc is 0x%x \n", stellaris_info->mck_freq / 1000, stellaris_info->rcc);
199         buf += printed;
200         buf_size -= printed;
201
202         if (stellaris_info->num_lockbits>0) {           
203                 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);
204                 buf += printed;
205                 buf_size -= printed;
206         }
207         return ERROR_OK;
208 }
209
210 /***************************************************************************
211 *       chip identification and status                                         *
212 ***************************************************************************/
213
214 u32 stellaris_get_flash_status(flash_bank_t *bank)
215 {
216         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
217         target_t *target = stellaris_info->target;
218         u32 fmc;
219         
220         target_read_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, &fmc);
221         
222         return fmc;
223 }
224
225 /** Read clock configuration and set stellaris_info->usec_clocks*/
226  
227 void stellaris_read_clock_info(flash_bank_t *bank)
228 {
229         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
230         target_t *target = stellaris_info->target;
231         u32 rcc, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
232         unsigned long tmp, mainfreq;
233
234         target_read_u32(target, SCB_BASE|RCC, &rcc);
235         DEBUG("Stellaris RCC %x",rcc);
236         target_read_u32(target, SCB_BASE|PLLCFG, &pllcfg);
237         DEBUG("Stellaris PLLCFG %x",pllcfg);
238         stellaris_info->rcc = rcc;
239         
240         sysdiv = (rcc>>23)&0xF;
241         usesysdiv = (rcc>>22)&0x1;
242         bypass = (rcc>>11)&0x1;
243         oscsrc = (rcc>>4)&0x3;
244         /* xtal = (rcc>>6)&0xF; */
245         switch (oscsrc)
246         {
247                 case 0:
248                         mainfreq = 6000000;  /* Default xtal */
249                         break;
250                 case 1:
251                         mainfreq = 22500000; /* Internal osc. 15 MHz +- 50% */
252                         break;
253                 case 2:
254                         mainfreq = 5625000;  /* Internal osc. / 4 */
255                         break;
256                 case 3:
257                         WARNING("Invalid oscsrc (3) in rcc register");
258                         mainfreq = 6000000;
259                         break;
260         }
261         
262         if (!bypass)
263                 mainfreq = 200000000; /* PLL out frec */
264                 
265         if (usesysdiv)
266                 stellaris_info->mck_freq = mainfreq/(1+sysdiv);
267         else
268                 stellaris_info->mck_freq = mainfreq;
269         
270         /* Forget old flash timing */
271        stellaris_set_flash_mode(bank,0);
272 }
273
274 /* Setup the timimg registers */
275 void stellaris_set_flash_mode(flash_bank_t *bank,int mode)
276 {
277         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
278         target_t *target = stellaris_info->target;
279
280         u32 usecrl = (stellaris_info->mck_freq/1000000ul-1);
281         DEBUG("usecrl = %i",usecrl);    
282         target_write_u32(target, SCB_BASE|USECRL , usecrl);
283         
284 }
285
286 u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
287 {
288         u32 status;
289         
290         /* Stellaris waits for cmdbit to clear */
291         while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
292         {
293                 DEBUG("status: 0x%x", status);
294                 usleep(1000);
295         }
296         
297         /* Flash errors are reflected in the FLASH_CRIS register */
298
299         return status;
300 }
301
302
303 /* Send one command to the flash controller */
304 int stellaris_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen) 
305 {
306         u32 fmc;
307         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
308         target_t *target = stellaris_info->target;
309
310         fmc = FMC_WRKEY | cmd; 
311         target_write_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, fmc);
312         DEBUG("Flash command: 0x%x", fmc);
313
314         if (stellaris_wait_status_busy(bank, cmd, 100)) 
315         {
316                 return ERROR_FLASH_OPERATION_FAILED;
317         }               
318
319         return ERROR_OK;
320 }
321
322 /* Read device id register, main clock frequency register and fill in driver info structure */
323 int stellaris_read_part_info(struct flash_bank_s *bank)
324 {
325         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
326         target_t *target = stellaris_info->target;
327     u32 did0,did1, ver, fam, status;
328         int i;
329         
330         /* Read and parse chip identification register */
331         target_read_u32(target, SCB_BASE|DID0, &did0);
332         target_read_u32(target, SCB_BASE|DID1, &did1);
333         target_read_u32(target, SCB_BASE|DC0, &stellaris_info->dc0);
334         target_read_u32(target, SCB_BASE|DC1, &stellaris_info->dc1);
335         DEBUG("did0 0x%x, did1 0x%x, dc0 0x%x, dc1 0x%x",did0, did1, stellaris_info->dc0,stellaris_info->dc1);
336
337     ver = did0 >> 28;
338     if((ver != 0) && (ver != 1))
339         {
340         WARNING("Unknown did0 version, cannot identify target");
341                 return ERROR_FLASH_OPERATION_FAILED;
342         
343         }
344
345     ver = did1 >> 28;
346     fam = (did1 >> 24) & 0xF;
347     if(((ver != 0) && (ver != 1)) || (fam != 0))
348         {
349         WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
350         }
351
352         if (did1 == 0)
353         {
354                 WARNING("Cannot identify target as a Stellaris");
355                 return ERROR_FLASH_OPERATION_FAILED;
356         }
357         
358         for (i=0;StellarisParts[i].partno;i++)
359         {
360                 if (StellarisParts[i].partno==((did1>>16)&0xFF))
361                         break;
362         }
363         
364         stellaris_info->target_name = StellarisParts[i].partname;
365         
366         stellaris_info->did0 = did0;
367         stellaris_info->did1 = did1;
368         
369         stellaris_info->num_lockbits = 1+stellaris_info->dc0&0xFFFF;
370         stellaris_info->num_pages = 2*(1+stellaris_info->dc0&0xFFFF);
371         stellaris_info->pagesize = 1024;
372         bank->size = 1024*stellaris_info->num_pages;
373         stellaris_info->pages_in_lockregion = 2;
374         target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);
375
376         // Read main and master clock freqency register 
377         stellaris_read_clock_info(bank);
378         
379         status = stellaris_get_flash_status(bank);
380         
381         WARNING("stellaris flash only tested for LM3S811 series");
382         
383         return ERROR_OK;
384 }
385
386 /***************************************************************************
387 *       flash operations                                         *
388 ***************************************************************************/
389
390 int stellaris_erase_check(struct flash_bank_s *bank)
391 {
392         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
393         target_t *target = stellaris_info->target;
394         int i;
395         
396         /* */
397         
398         return ERROR_OK;
399 }
400
401 int stellaris_protect_check(struct flash_bank_s *bank)
402 {
403         u32 status;
404         
405         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
406         target_t *target = stellaris_info->target;
407
408         if (stellaris_info->did1 == 0)
409         {
410                 stellaris_read_part_info(bank);
411         }
412
413         if (stellaris_info->did1 == 0)
414         {
415                 WARNING("Cannot identify target as an AT91SAM");
416                 return ERROR_FLASH_OPERATION_FAILED;
417         }
418                 
419         status = stellaris_get_flash_status(bank);
420         stellaris_info->lockbits = status >> 16;
421         
422         return ERROR_OK;
423 }
424
425 int stellaris_erase(struct flash_bank_s *bank, int first, int last)
426 {
427         int banknr;
428         u32 flash_fmc, flash_cris;
429         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
430         target_t *target = stellaris_info->target;
431         
432         if (stellaris_info->target->state != TARGET_HALTED)
433         {
434                 return ERROR_TARGET_NOT_HALTED;
435         }
436         
437         if (stellaris_info->did1 == 0)
438         {
439                 stellaris_read_part_info(bank);
440         }
441
442         if (stellaris_info->did1 == 0)
443         {
444         WARNING("Cannot identify target as Stellaris");
445                 return ERROR_FLASH_OPERATION_FAILED;
446         }       
447         
448         if ((first < 0) || (last < first) || (last >= stellaris_info->num_pages))
449         {
450                 return ERROR_FLASH_SECTOR_INVALID;
451         }
452
453         /* Configure the flash controller timing */
454         stellaris_read_clock_info(bank);        
455         stellaris_set_flash_mode(bank,0);
456
457         /* Clear and disable flash programming interrupts */
458         target_write_u32(target, FLASH_CIM, 0);
459         target_write_u32(target, FLASH_MISC, PMISC|AMISC);
460
461         if ((first == 0) && (last == (stellaris_info->num_pages-1)))
462         {
463         target_write_u32(target, FLASH_FMA, 0);
464                 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
465                 /* Wait until erase complete */
466                 do
467                 {
468                         target_read_u32(target, FLASH_FMC, &flash_fmc);
469                 }
470                 while(flash_fmc & FMC_MERASE);
471                 
472         /* if device has > 128k, then second erase cycle is needed */
473         if(stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
474         {
475             target_write_u32(target, FLASH_FMA, 0x20000);
476             target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
477             /* Wait until erase complete */
478             do
479             {
480                 target_read_u32(target, FLASH_FMC, &flash_fmc);
481             }
482             while(flash_fmc & FMC_MERASE);
483         }
484
485                 return ERROR_OK;
486         }
487
488         for (banknr=first;banknr<=last;banknr++)
489         {
490                 /* Address is first word in page */
491                 target_write_u32(target, FLASH_FMA, banknr*stellaris_info->pagesize);
492                 /* Write erase command */
493                 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);
494                 /* Wait until erase complete */
495                 do
496                 {
497                         target_read_u32(target, FLASH_FMC, &flash_fmc);
498                 }
499                 while(flash_fmc & FMC_ERASE);
500
501                 /* Check acess violations */
502                 target_read_u32(target, FLASH_CRIS, &flash_cris);
503                 if(flash_cris & (AMASK))
504                 {
505                         WARNING("Error erasing flash page %i,  flash_cris 0x%x", banknr, flash_cris);
506                         target_write_u32(target, FLASH_CRIS, 0);
507                         return ERROR_FLASH_OPERATION_FAILED;
508                 }
509         }
510
511         return ERROR_OK;
512 }
513
514 int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)
515 {
516         u32 cmd, fmppe, flash_fmc, flash_cris;
517         int lockregion;
518         
519         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
520         target_t *target = stellaris_info->target;
521         
522         if (stellaris_info->target->state != TARGET_HALTED)
523         {
524                 return ERROR_TARGET_NOT_HALTED;
525         }
526         
527         if ((first < 0) || (last < first) || (last >= stellaris_info->num_lockbits))
528         {
529                 return ERROR_FLASH_SECTOR_INVALID;
530         }
531         
532         if (stellaris_info->did1 == 0)
533         {
534                 stellaris_read_part_info(bank);
535         }
536
537         if (stellaris_info->did1 == 0)
538         {
539                 WARNING("Cannot identify target as an Stellaris MCU");
540                 return ERROR_FLASH_OPERATION_FAILED;
541         }
542         
543         /* Configure the flash controller timing */
544         stellaris_read_clock_info(bank);        
545         stellaris_set_flash_mode(bank,0);
546
547         fmppe = stellaris_info->lockbits;       
548         for (lockregion=first;lockregion<=last;lockregion++) 
549         {
550                 if (set)
551                          fmppe &= ~(1<<lockregion); 
552                 else
553                          fmppe |= (1<<lockregion); 
554         }
555
556         /* Clear and disable flash programming interrupts */
557         target_write_u32(target, FLASH_CIM, 0);
558         target_write_u32(target, FLASH_MISC, PMISC|AMISC);
559         
560         DEBUG("fmppe 0x%x",fmppe);
561         target_write_u32(target, SCB_BASE|FMPPE, fmppe);
562         /* Commit FMPPE */
563         target_write_u32(target, FLASH_FMA, 1);
564         /* Write commit command */
565         /* TODO safety check, sice this cannot be undone */
566         WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
567         /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
568         /* Wait until erase complete */
569         do
570         {
571                 target_read_u32(target, FLASH_FMC, &flash_fmc);
572         }
573         while(flash_fmc & FMC_COMT);
574
575         /* Check acess violations */
576         target_read_u32(target, FLASH_CRIS, &flash_cris);
577         if(flash_cris & (AMASK))
578         {
579                 WARNING("Error setting flash page protection,  flash_cris 0x%x", flash_cris);
580                 target_write_u32(target, FLASH_CRIS, 0);
581                 return ERROR_FLASH_OPERATION_FAILED;
582         }
583         
584         target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);
585                 
586         return ERROR_OK;
587 }
588
589 u8 stellaris_write_code[] = 
590 {
591 /* Call with :  
592         r0 = buffer address
593         r1 = destination address
594         r2 = bytecount (in) - endaddr (work) 
595         r3 = pFLASH_CTRL_BASE
596         r4 = FLASHWRITECMD
597         r5 = #1
598         r6 = scratch
599         r7
600 */
601         0x07,0x4B,              /* ldr r3,pFLASH_CTRL_BASE */
602         0x08,0x4C,              /* ldr r4,FLASHWRITECMD */
603         0x01,0x25,              /* movs r5, 1 */
604         0x00,0x26,              /* movs r6, #0 */
605 /* mainloop: */
606         0x19,0x60,              /* str  r1, [r3, #0] */
607         0x87,0x59,              /* ldr  r7, [r0, r6] */
608         0x5F,0x60,              /* str  r7, [r3, #4] */
609         0x9C,0x60,              /* str  r4, [r3, #8] */
610 /* waitloop: */
611         0x9F,0x68,              /* ldr  r7, [r3, #8] */
612         0x2F,0x42,              /* tst  r7, r5 */
613         0xFC,0xD1,              /* bne  waitloop */
614         0x04,0x31,              /* adds r1, r1, #4 */
615         0x04,0x36,              /* adds r6, r6, #4 */
616         0x96,0x42,              /* cmp  r6, r2 */
617         0xF4,0xD1,              /* bne  mainloop */
618         0x00,0xBE,              /* bkpt #0 */
619 /* pFLASH_CTRL_BASE: */
620         0x00,0xD0,0x0F,0x40,    /* .word        0x400FD000 */
621 /* FLASHWRITECMD: */
622         0x01,0x00,0x42,0xA4     /* .word        0xA4420001 */
623 };
624
625 int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 wcount)
626 {
627         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
628         target_t *target = stellaris_info->target;
629         u32 buffer_size = 8192;
630         working_area_t *source;
631         working_area_t *write_algorithm;
632         u32 address = bank->base + offset;
633         reg_param_t reg_params[8];
634         armv7m_algorithm_t armv7m_info;
635         int retval;
636         
637     DEBUG("(bank=%08X buffer=%08X offset=%08X wcount=%08X)",
638                                   bank, buffer, offset, wcount);
639
640         /* flash write code */
641         if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
642                 {
643                         WARNING("no working area available, can't do block memory writes");
644                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
645                 };
646
647         target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), stellaris_write_code);
648
649         /* memory buffer */
650         while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
651         {
652         DEBUG("called target_alloc_working_area(target=%08X buffer_size=%08X source=%08X)",
653                              target, buffer_size, source); 
654                 buffer_size /= 2;
655                 if (buffer_size <= 256)
656                 {
657                         /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
658                         if (write_algorithm)
659                                 target_free_working_area(target, write_algorithm);
660                         
661                         WARNING("no large enough working area available, can't do block memory writes");
662                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
663                 }
664         };
665         
666         armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
667         armv7m_info.core_mode = ARMV7M_MODE_ANY;
668         armv7m_info.core_state = ARMV7M_STATE_THUMB;
669         
670         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
671         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
672         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
673         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
674         init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
675         init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
676         init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT);
677         init_reg_param(&reg_params[7], "r7", 32, PARAM_OUT);
678
679         while (wcount > 0)
680         {
681                 u32 thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
682                 
683                 target_write_buffer(target, source->address, thisrun_count * 4, buffer);
684                 
685                 buf_set_u32(reg_params[0].value, 0, 32, source->address);
686                 buf_set_u32(reg_params[1].value, 0, 32, address);
687                 buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
688                 WARNING("Algorithm flash write  %i words to 0x%x, %i remaining",thisrun_count,address, wcount);
689                 DEBUG("Algorithm flash write  %i words to 0x%x, %i remaining",thisrun_count,address, wcount);
690                 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)
691                 {
692                         ERROR("error executing stellaris flash write algorithm");
693                         target_free_working_area(target, source);
694                         destroy_reg_param(&reg_params[0]);
695                         destroy_reg_param(&reg_params[1]);
696                         destroy_reg_param(&reg_params[2]);
697                         return ERROR_FLASH_OPERATION_FAILED;
698                 }
699         
700                 buffer += thisrun_count * 4;
701                 address += thisrun_count * 4;
702                 wcount -= thisrun_count;
703         }
704         
705
706         target_free_working_area(target, write_algorithm);
707         target_free_working_area(target, source);
708         
709         destroy_reg_param(&reg_params[0]);
710         destroy_reg_param(&reg_params[1]);
711         destroy_reg_param(&reg_params[2]);
712         destroy_reg_param(&reg_params[3]);
713         destroy_reg_param(&reg_params[4]);
714         destroy_reg_param(&reg_params[5]);
715         destroy_reg_param(&reg_params[6]);
716         destroy_reg_param(&reg_params[7]);
717         
718         return ERROR_OK;
719 }
720
721 int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
722 {
723         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
724         target_t *target = stellaris_info->target;
725         u32 dst_min_alignment, wcount, bytes_remaining = count;
726         u32 address = offset;
727         u32 fcr,flash_cris,flash_fmc;
728         u32 retval;
729         
730     DEBUG("(bank=%08X buffer=%08X offset=%08X count=%08X)",
731                             bank, buffer, offset, count);
732
733         if (stellaris_info->target->state != TARGET_HALTED)
734         {
735                 return ERROR_TARGET_NOT_HALTED;
736         }
737         
738         if (stellaris_info->did1 == 0)
739         {
740                 stellaris_read_part_info(bank);
741         }
742
743         if (stellaris_info->did1 == 0)
744         {
745                 WARNING("Cannot identify target as a Stellaris processor");
746                 return ERROR_FLASH_OPERATION_FAILED;
747         }
748         
749         if((offset & 3) || (count & 3))
750         {
751                 WARNING("offset size must be word aligned");
752                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
753         }
754         
755         if (offset + count > bank->size)
756                 return ERROR_FLASH_DST_OUT_OF_BANK;
757
758         /* Configure the flash controller timing */     
759         stellaris_read_clock_info(bank);        
760         stellaris_set_flash_mode(bank,0);
761
762         
763         /* Clear and disable flash programming interrupts */
764         target_write_u32(target, FLASH_CIM, 0);
765         target_write_u32(target, FLASH_MISC, PMISC|AMISC);
766
767         /* multiple words to be programmed? */
768         if (count > 0) 
769         {
770                 /* try using a block write */
771                 if ((retval = stellaris_write_block(bank, buffer, offset, count/4)) != ERROR_OK)
772                 {
773                         if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
774                         {
775                                 /* if block write failed (no sufficient working area),
776                                  * we use normal (slow) single dword accesses */ 
777                                 WARNING("couldn't use block writes, falling back to single memory accesses");
778                         }
779                         else if (retval == ERROR_FLASH_OPERATION_FAILED)
780                         {
781                                 /* if an error occured, we examine the reason, and quit */
782                                 target_read_u32(target, FLASH_CRIS, &flash_cris);
783                                 
784                                 ERROR("flash writing failed with CRIS: 0x%x", flash_cris);
785                                 return ERROR_FLASH_OPERATION_FAILED;
786                         }
787                 }
788                 else
789                 {
790                         buffer += count * 4;
791                         address += count * 4;
792                         count = 0;
793                 }
794         }
795
796
797
798         while(count>0)
799         {
800                 if (!(address&0xff)) DEBUG("0x%x",address);
801                 /* Program one word */
802                 target_write_u32(target, FLASH_FMA, address);
803                 target_write_buffer(target, FLASH_FMD, 4, buffer);
804                 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
805                 //DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE);
806                 /* Wait until write complete */
807                 do
808                 {
809                         target_read_u32(target, FLASH_FMC, &flash_fmc);
810                 }
811                 while(flash_fmc & FMC_WRITE);
812                 buffer += 4;
813                 address += 4;
814                 count -= 4;
815         }
816         /* Check acess violations */
817         target_read_u32(target, FLASH_CRIS, &flash_cris);
818         if(flash_cris & (AMASK))
819         {
820                 DEBUG("flash_cris 0x%x", flash_cris);
821                 return ERROR_FLASH_OPERATION_FAILED;
822         }
823         return ERROR_OK;
824 }
825
826
827 int stellaris_probe(struct flash_bank_s *bank)
828 {
829         /* we can't probe on an stellaris
830          * if this is an stellaris, it has the configured flash
831          */
832         stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
833         
834         if (stellaris_info->did1 == 0)
835         {
836                 stellaris_read_part_info(bank);
837         }
838
839         if (stellaris_info->did1 == 0)
840         {
841                 WARNING("Cannot identify target as a LMI Stellaris");
842                 return ERROR_FLASH_OPERATION_FAILED;
843         }
844         
845         return ERROR_OK;
846 }