- free working area used to store flash write buffer
[fw/openocd] / src / flash / str7x.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "replacements.h"
25
26 #include "str7x.h"
27 #include "flash.h"
28 #include "target.h"
29 #include "log.h"
30 #include "armv4_5.h"
31 #include "algorithm.h"
32 #include "binarybuffer.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 str7x_mem_layout_t mem_layout[] = {
39         {0x00000000, 0x02000, 0x01},
40         {0x00002000, 0x02000, 0x01},
41         {0x00004000, 0x02000, 0x01},
42         {0x00006000, 0x02000, 0x01},
43         {0x00008000, 0x08000, 0x01},
44         {0x00010000, 0x10000, 0x01},
45         {0x00020000, 0x10000, 0x01},
46         {0x00030000, 0x10000, 0x01},
47         {0x000C0000, 0x02000, 0x100},
48         {0x000C2000, 0x02000, 0x100},
49         {0,0},
50 };
51
52 int str7x_register_commands(struct command_context_s *cmd_ctx);
53 int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
54 int str7x_erase(struct flash_bank_s *bank, int first, int last);
55 int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
56 int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
57 int str7x_probe(struct flash_bank_s *bank);
58 int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
59 int str7x_protect_check(struct flash_bank_s *bank);
60 int str7x_erase_check(struct flash_bank_s *bank);
61 int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
62
63 flash_driver_t str7x_flash =
64 {
65         .name = "str7x",
66         .register_commands = str7x_register_commands,
67         .flash_bank_command = str7x_flash_bank_command,
68         .erase = str7x_erase,
69         .protect = str7x_protect,
70         .write = str7x_write,
71         .probe = str7x_probe,
72         .erase_check = str7x_erase_check,
73         .protect_check = str7x_protect_check,
74         .info = str7x_info
75 };
76
77 int str7x_register_commands(struct command_context_s *cmd_ctx)
78 {
79
80         return ERROR_OK;
81 }
82
83 int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
84 {
85         str7x_flash_bank_t *str7x_info = bank->driver_priv;
86         return (str7x_info->flash_base|reg);
87 }
88
89 int str7x_build_block_list(struct flash_bank_s *bank)
90 {
91         str7x_flash_bank_t *str7x_info = bank->driver_priv;
92
93         int i;
94         int num_sectors;
95                 
96         switch (bank->size)
97         {
98                 case 16 * 1024:
99                         num_sectors = 2;
100                         break;
101                 case 64 * 1024:
102                         num_sectors = 5;
103                         break;
104                 case 128 * 1024:
105                         num_sectors = 6;
106                         break;
107                 case 256 * 1024:
108                         num_sectors = 8;
109                         break;
110                 default:
111                         ERROR("BUG: unknown bank->size encountered");
112                         exit(-1);
113         }
114         
115         if( str7x_info->bank1 == 1 )
116         {
117                 num_sectors += 2;
118         }
119         
120         bank->num_sectors = num_sectors;
121         bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
122         
123         for (i = 0; i < num_sectors; i++)
124         {
125                 bank->sectors[i].offset = mem_layout[i].sector_start;
126                 bank->sectors[i].size = mem_layout[i].sector_size;
127                 bank->sectors[i].is_erased = -1;
128                 bank->sectors[i].is_protected = 1;
129         }
130
131         return ERROR_OK;
132 }
133
134 /* flash bank str7x <base> <size> 0 0 <str71_variant> <target#>
135  */
136 int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
137 {
138         str7x_flash_bank_t *str7x_info;
139         
140         if (argc < 7)
141         {
142                 WARNING("incomplete flash_bank str7x configuration");
143                 return ERROR_FLASH_BANK_INVALID;
144         }
145         
146         str7x_info = malloc(sizeof(str7x_flash_bank_t));
147         bank->driver_priv = str7x_info;
148         
149         if (strcmp(args[5], "STR71x") == 0)
150         {
151                 str7x_info->bank1 = 1;
152                 str7x_info->flash_base = 0x40000000;
153         }
154         else if (strcmp(args[5], "STR73x") == 0)
155         {
156                 str7x_info->bank1 = 0;
157                 str7x_info->flash_base = 0x80000000;
158         }
159         else
160         {
161                 ERROR("unknown STR7x variant");
162                 free(str7x_info);
163                 return ERROR_FLASH_BANK_INVALID;
164         }
165         
166         str7x_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
167         if (!str7x_info->target)
168         {
169                 ERROR("no target '%s' configured", args[6]);
170                 exit(-1);
171         }
172
173         str7x_build_block_list(bank);
174         
175         str7x_info->write_algorithm = NULL;
176         
177         return ERROR_OK;
178 }
179
180 u32 str7x_status(struct flash_bank_s *bank)
181 {
182         str7x_flash_bank_t *str7x_info = bank->driver_priv;
183         target_t *target = str7x_info->target;
184         u32 retval;
185
186         target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
187
188         return retval;
189 }
190
191 u32 str7x_result(struct flash_bank_s *bank)
192 {
193         str7x_flash_bank_t *str7x_info = bank->driver_priv;
194         target_t *target = str7x_info->target;
195         u32 retval;
196
197         target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
198         
199         return retval;
200 }
201
202 int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
203 {
204         str7x_flash_bank_t *str7x_info = bank->driver_priv;
205         target_t *target = str7x_info->target;
206         u8 *buffer;
207         int i;
208         int nBytes;
209         
210         if ((first < 0) || (last > bank->num_sectors))
211                 return ERROR_FLASH_SECTOR_INVALID;
212
213         if (str7x_info->target->state != TARGET_HALTED)
214         {
215                 return ERROR_TARGET_NOT_HALTED;
216         }
217         
218         buffer = malloc(256);
219         
220         for (i = first; i <= last; i++)
221         {
222                 bank->sectors[i].is_erased = 1;
223
224                 target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
225                 
226                 for (nBytes = 0; nBytes < 256; nBytes++)
227                 {
228                         if (buffer[nBytes] != 0xFF)
229                         {
230                                 bank->sectors[i].is_erased = 0;
231                                 break;
232                         }
233                 }       
234         }
235         
236         free(buffer);
237
238         return ERROR_OK;
239 }
240
241 int str7x_protect_check(struct flash_bank_s *bank)
242 {
243         str7x_flash_bank_t *str7x_info = bank->driver_priv;
244         target_t *target = str7x_info->target;
245         
246         int i;
247         u32 retval;
248
249         if (str7x_info->target->state != TARGET_HALTED)
250         {
251                 return ERROR_TARGET_NOT_HALTED;
252         }
253
254         target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &retval);
255
256         for (i = 0; i < bank->num_sectors; i++)
257         {
258                 if (retval & (mem_layout[i].reg_offset << i))
259                         bank->sectors[i].is_protected = 0;
260                 else
261                         bank->sectors[i].is_protected = 1;
262         }
263
264         return ERROR_OK;
265 }
266
267 int str7x_erase(struct flash_bank_s *bank, int first, int last)
268 {
269         str7x_flash_bank_t *str7x_info = bank->driver_priv;
270         target_t *target = str7x_info->target;
271         
272         int i;
273         u32 cmd;
274         u32 retval;
275         u32 erase_blocks;
276         
277         if (str7x_info->target->state != TARGET_HALTED)
278         {
279                 return ERROR_TARGET_NOT_HALTED;
280         }
281         
282         erase_blocks = 0;
283         
284         for (i = first; i <= last; i++)
285                 erase_blocks |= (mem_layout[i].reg_offset << i);
286         
287         /* clear FLASH_ER register */   
288         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
289         
290         cmd = FLASH_SER;
291         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
292         
293         cmd = erase_blocks;
294         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
295         
296         cmd = FLASH_SER|FLASH_WMS;
297         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
298         
299         while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
300                 usleep(1000);
301         }
302         
303         retval = str7x_result(bank);
304         
305         if (retval & FLASH_ERER)
306                 return ERROR_FLASH_SECTOR_NOT_ERASED;
307         else if (retval & FLASH_WPF)
308                 return ERROR_FLASH_OPERATION_FAILED;
309         
310         for (i = first; i <= last; i++)
311                 bank->sectors[i].is_erased = 1;
312
313         return ERROR_OK;
314 }
315
316 int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
317 {
318         str7x_flash_bank_t *str7x_info = bank->driver_priv;
319         target_t *target = str7x_info->target;
320         int i;
321         u32 cmd;
322         u32 retval;
323         u32 protect_blocks;
324         
325         if (str7x_info->target->state != TARGET_HALTED)
326         {
327                 return ERROR_TARGET_NOT_HALTED;
328         }
329         
330         protect_blocks = 0xFFFFFFFF;
331
332         if (set)
333         {
334                 for (i = first; i <= last; i++)
335                         protect_blocks &= ~(mem_layout[i].reg_offset << i);
336         }
337         
338         /* clear FLASH_ER register */   
339         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
340
341         cmd = FLASH_SPR;
342         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
343         
344         cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
345         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
346         
347         cmd = protect_blocks;
348         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
349         
350         cmd = FLASH_SPR|FLASH_WMS;
351         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
352         
353         while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
354                 usleep(1000);
355         }
356         
357         retval = str7x_result(bank);
358         
359         DEBUG("retval: 0x%8.8x", retval);
360         
361         if (retval & FLASH_ERER)
362                 return ERROR_FLASH_SECTOR_NOT_ERASED;
363         else if (retval & FLASH_WPF)
364                 return ERROR_FLASH_OPERATION_FAILED;
365
366         return ERROR_OK;
367 }
368
369 int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
370 {
371         str7x_flash_bank_t *str7x_info = bank->driver_priv;
372         target_t *target = str7x_info->target;
373         u32 buffer_size = 8192;
374         working_area_t *source;
375         u32 address = bank->base + offset;
376         reg_param_t reg_params[5];
377         armv4_5_algorithm_t armv4_5_info;
378         int retval;
379         
380         u32 str7x_flash_write_code[] = {
381                                         /* write:                               */
382                 0xe3a04201, /*  mov r4, #0x10000000     */
383                 0xe5824000, /*  str r4, [r2, #0x0]      */
384                 0xe5821010, /*  str r1, [r2, #0x10]     */
385                 0xe4904004, /*  ldr r4, [r0], #4        */
386                 0xe5824008, /*  str r4, [r2, #0x8]      */
387                 0xe4904004, /*  ldr r4, [r0], #4        */
388                 0xe582400c, /*  str r4, [r2, #0xc]      */
389                 0xe3a04209, /*  mov r4, #0x90000000     */
390                 0xe5824000, /*  str r4, [r2, #0x0]      */
391                             /* busy:                            */
392                 0xe5924000, /*  ldr r4, [r2, #0x0]      */
393                 0xe3140016, /*  tst r4, #0x16           */
394                 0x1afffffc, /*  bne busy                        */
395                 0xe5924014, /*  ldr r4, [r2, #0x14]     */
396                 0xe31400ff, /*  tst r4, #0xff           */
397                 0x03140c01, /*  tsteq r4, #0x100        */
398                 0x1a000002, /*  bne exit                        */
399                 0xe2811008, /*  add r1, r1, #0x8        */
400                 0xe2533001, /*  subs r3, r3, #1         */
401                 0x1affffec, /*  bne write                       */
402                                         /* exit:                                */
403                 0xeafffffe, /*  b exit                          */
404         };
405         
406         u8 str7x_flash_write_code_buf[80];
407         int i;
408         
409         /* flash write code */
410         if (!str7x_info->write_algorithm)
411         {
412                 if (target_alloc_working_area(target, 4 * 20, &str7x_info->write_algorithm) != ERROR_OK)
413                 {
414                         WARNING("no working area available, can't do block memory writes");
415                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
416                 };
417
418                 /* convert flash writing code into a buffer in target endianness */
419                 for (i = 0; i < 20; i++)
420                         target_buffer_set_u32(target, str7x_flash_write_code_buf + i*4, str7x_flash_write_code[i]);
421                         
422                 target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, str7x_flash_write_code_buf);
423         }
424
425         /* memory buffer */
426         while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
427         {
428                 buffer_size /= 2;
429                 if (buffer_size <= 256)
430                 {
431                         /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
432                         if (str7x_info->write_algorithm)
433                                 target_free_working_area(target, str7x_info->write_algorithm);
434                         
435                         WARNING("no large enough working area available, can't do block memory writes");
436                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
437                 }
438         };
439         
440         armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
441         armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
442         armv4_5_info.core_state = ARMV4_5_STATE_ARM;
443         
444         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
445         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
446         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
447         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
448         init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
449         
450         while (count > 0)
451         {
452                 u32 thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
453                 
454                 target_write_buffer(target, source->address, thisrun_count * 8, buffer);
455                 
456                 buf_set_u32(reg_params[0].value, 0, 32, source->address);
457                 buf_set_u32(reg_params[1].value, 0, 32, address);
458                 buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
459                 buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
460         
461                 if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
462                 {
463                         ERROR("error executing str7x flash write algorithm");
464                         return ERROR_FLASH_OPERATION_FAILED;
465                 }
466         
467                 if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
468                 {
469                         return ERROR_FLASH_OPERATION_FAILED;
470                 }
471                 
472                 buffer += thisrun_count * 8;
473                 address += thisrun_count * 8;
474                 count -= thisrun_count;
475         }
476         
477         target_free_working_area(target, source);
478         
479         destroy_reg_param(&reg_params[0]);
480         destroy_reg_param(&reg_params[1]);
481         destroy_reg_param(&reg_params[2]);
482         destroy_reg_param(&reg_params[3]);
483         destroy_reg_param(&reg_params[4]);
484         
485         return ERROR_OK;
486 }
487
488 int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
489 {
490         str7x_flash_bank_t *str7x_info = bank->driver_priv;
491         target_t *target = str7x_info->target;
492         u32 dwords_remaining = (count / 8);
493         u32 bytes_remaining = (count & 0x00000007);
494         u32 address = bank->base + offset;
495         u32 bytes_written = 0;
496         u32 cmd;
497         u32 retval;
498
499         
500         if (str7x_info->target->state != TARGET_HALTED)
501         {
502                 return ERROR_TARGET_NOT_HALTED;
503         }
504         
505         if (offset & 0x7)
506         {
507                 WARNING("offset 0x%x breaks required 8-byte alignment", offset);
508                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
509         }
510         
511         if (offset + count > bank->size)
512                 return ERROR_FLASH_DST_OUT_OF_BANK;
513
514         /* clear FLASH_ER register */   
515         target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
516
517         /* multiple dwords (8-byte) to be programmed? */
518         if (dwords_remaining > 0) 
519         {
520                 /* try using a block write */
521                 if ((retval = str7x_write_block(bank, buffer, offset, dwords_remaining)) != ERROR_OK)
522                 {
523                         if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
524                         {
525                                 /* if block write failed (no sufficient working area),
526                                  * we use normal (slow) single dword accesses */ 
527                                 WARNING("couldn't use block writes, falling back to single memory accesses");
528                         }
529                         else if (retval == ERROR_FLASH_OPERATION_FAILED)
530                         {
531                                 /* if an error occured, we examine the reason, and quit */
532                                 retval = str7x_result(bank);
533                                 
534                                 ERROR("flash writing failed with error code: 0x%x", retval);
535                                 return ERROR_FLASH_OPERATION_FAILED;
536                         }
537                 }
538                 else
539                 {
540                         buffer += dwords_remaining * 8;
541                         address += dwords_remaining * 8;
542                         dwords_remaining = 0;
543                 }
544         }
545
546         while (dwords_remaining > 0)
547         {
548                 // command
549                 cmd = FLASH_DWPG;
550                 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
551                 
552                 // address
553                 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
554                 
555                 // data word 1
556                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
557                 bytes_written += 4;
558                 
559                 // data word 2
560                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
561                 bytes_written += 4;
562                 
563                 /* start programming cycle */
564                 cmd = FLASH_DWPG | FLASH_WMS;
565                 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
566                 
567                 while (((retval = str7x_status(bank)) & (FLASH_BSYA1 | FLASH_BSYA2)))
568                 {
569                         usleep(1000);
570                 }
571                 
572                 retval = str7x_result(bank);
573                 
574                 if (retval & FLASH_PGER)
575                         return ERROR_FLASH_OPERATION_FAILED;
576                 else if (retval & FLASH_WPF)
577                         return ERROR_FLASH_OPERATION_FAILED;
578
579                 dwords_remaining--;
580                 address += 8;
581         }
582         
583         if (bytes_remaining)
584         {
585                 u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
586                 int i = 0;
587                                 
588                 while(bytes_remaining > 0)
589                 {
590                         last_dword[i++] = *(buffer + bytes_written); 
591                         bytes_remaining--;
592                         bytes_written++;
593                 }
594                 
595                 // command
596                 cmd = FLASH_DWPG;
597                 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
598                 
599                 // address
600                 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
601                 
602                 // data word 1
603                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
604                 bytes_written += 4;
605                 
606                 // data word 2
607                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
608                 bytes_written += 4;
609                 
610                 /* start programming cycle */
611                 cmd = FLASH_DWPG | FLASH_WMS;
612                 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
613                 
614                 while (((retval = str7x_status(bank)) & (FLASH_BSYA1 | FLASH_BSYA2)))
615                 {
616                         usleep(1000);
617                 }
618                 
619                 retval = str7x_result(bank);
620                 
621                 if (retval & FLASH_PGER)
622                         return ERROR_FLASH_OPERATION_FAILED;
623                 else if (retval & FLASH_WPF)
624                         return ERROR_FLASH_OPERATION_FAILED;
625         }
626                 
627         return ERROR_OK;
628 }
629
630 int str7x_probe(struct flash_bank_s *bank)
631 {
632         return ERROR_OK;
633 }
634
635 int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
636 {
637         return ERROR_OK;
638 }
639
640 int str7x_erase_check(struct flash_bank_s *bank)
641 {
642         return str7x_blank_check(bank, 0, bank->num_sectors - 1);
643 }
644
645 int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
646 {
647         snprintf(buf, buf_size, "str7x flash driver info" );
648         return ERROR_OK;
649 }