- prepare OpenOCD for branching, created ./trunk/
[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
21 #include "str7x.h"
22 #include "flash.h"
23 #include "target.h"
24 #include "log.h"
25 #include "armv4_5.h"
26 #include "algorithm.h"
27 #include "binarybuffer.h"
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 str7x_mem_layout_t mem_layout[] = {
34         {0x00000000, 0x02000, 0x01},
35         {0x00002000, 0x02000, 0x01},
36         {0x00004000, 0x02000, 0x01},
37         {0x00006000, 0x02000, 0x01},
38         {0x00008000, 0x08000, 0x01},
39         {0x00010000, 0x10000, 0x01},
40         {0x00020000, 0x10000, 0x01},
41         {0x00030000, 0x10000, 0x01},
42         {0x000C0000, 0x02000, 0x10},
43         {0x000C2000, 0x02000, 0x10},
44         {0,0},
45 };
46
47 int str7x_register_commands(struct command_context_s *cmd_ctx);
48 int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
49 int str7x_erase(struct flash_bank_s *bank, int first, int last);
50 int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
51 int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
52 int str7x_probe(struct flash_bank_s *bank);
53 int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
54 int str7x_protect_check(struct flash_bank_s *bank);
55 int str7x_erase_check(struct flash_bank_s *bank);
56 int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
57
58 flash_driver_t str7x_flash =
59 {
60         .name = "str7x",
61         .register_commands = str7x_register_commands,
62         .flash_bank_command = str7x_flash_bank_command,
63         .erase = str7x_erase,
64         .protect = str7x_protect,
65         .write = str7x_write,
66         .probe = str7x_probe,
67         .erase_check = str7x_erase_check,
68         .protect_check = str7x_protect_check,
69         .info = str7x_info
70 };
71
72 int str7x_register_commands(struct command_context_s *cmd_ctx)
73 {
74
75         return ERROR_OK;
76 }
77
78 int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
79 {
80         str7x_flash_bank_t *str7x_info = bank->driver_priv;
81         return (str7x_info->flash_base|reg);
82 }
83
84 int str7x_build_block_list(struct flash_bank_s *bank)
85 {
86         str7x_flash_bank_t *str7x_info = bank->driver_priv;
87
88         int i;
89         int num_sectors;
90                 
91         switch (bank->size)
92         {
93                 case 16 * 1024:
94                         num_sectors = 2;
95                         break;
96                 case 64 * 1024:
97                         num_sectors = 5;
98                         break;
99                 case 128 * 1024:
100                         num_sectors = 6;
101                         break;
102                 case 256 * 1024:
103                         num_sectors = 8;
104                         break;
105                 default:
106                         ERROR("BUG: unknown bank->size encountered");
107                         exit(-1);
108         }
109         
110         if( str7x_info->bank1 == 1 )
111         {
112                 num_sectors += 2;
113         }
114         
115         bank->num_sectors = num_sectors;
116         bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
117         
118         for (i = 0; i < num_sectors; i++)
119         {
120                 bank->sectors[i].offset = mem_layout[i].sector_start;
121                 bank->sectors[i].size = mem_layout[i].sector_size;
122                 bank->sectors[i].is_erased = -1;
123                 bank->sectors[i].is_protected = 1;
124         }
125
126         return ERROR_OK;
127 }
128
129 /* flash bank str7x <base> <size> 0 0 <str71_variant> <target#>
130  */
131 int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
132 {
133         str7x_flash_bank_t *str7x_info;
134         
135         if (argc < 7)
136         {
137                 WARNING("incomplete flash_bank str7x configuration");
138                 return ERROR_FLASH_BANK_INVALID;
139         }
140         
141         str7x_info = malloc(sizeof(str7x_flash_bank_t));
142         bank->driver_priv = str7x_info;
143         
144         if (strcmp(args[5], "STR71x") == 0)
145         {
146                 str7x_info->bank1 = 1;
147                 str7x_info->flash_base = 0x40000000;
148         }
149         else if (strcmp(args[5], "STR73x") == 0)
150         {
151                 str7x_info->bank1 = 0;
152                 str7x_info->flash_base = 0x80000000;
153         }
154         else
155         {
156                 ERROR("unknown STR7x variant");
157                 free(str7x_info);
158                 return ERROR_FLASH_BANK_INVALID;
159         }
160         
161         str7x_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
162         if (!str7x_info->target)
163         {
164                 ERROR("no target '%i' configured", args[6]);
165                 exit(-1);
166         }
167
168         str7x_build_block_list(bank);
169         
170         return ERROR_OK;
171 }
172
173 u32 str7x_status(struct flash_bank_s *bank)
174 {
175         str7x_flash_bank_t *str7x_info = bank->driver_priv;
176         target_t *target = str7x_info->target;
177         u32 retval;
178
179         target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&retval);
180
181         return retval;
182 }
183
184 u32 str7x_result(struct flash_bank_s *bank)
185 {
186         str7x_flash_bank_t *str7x_info = bank->driver_priv;
187         target_t *target = str7x_info->target;
188         u32 retval;
189
190         target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_ER), 4, 1, (u8*)&retval);
191         
192         return retval;
193 }
194
195 int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
196 {
197         str7x_flash_bank_t *str7x_info = bank->driver_priv;
198         target_t *target = str7x_info->target;
199         u8 *buffer;
200         int i;
201         int nBytes;
202         
203         if ((first < 0) || (last > bank->num_sectors))
204                 return ERROR_FLASH_SECTOR_INVALID;
205
206         if (str7x_info->target->state != TARGET_HALTED)
207         {
208                 return ERROR_TARGET_NOT_HALTED;
209         }
210         
211         buffer = malloc(256);
212         
213         for (i = first; i <= last; i++)
214         {
215                 bank->sectors[i].is_erased = 1;
216
217                 target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
218                 
219                 for (nBytes = 0; nBytes < 256; nBytes++)
220                 {
221                         if (buffer[nBytes] != 0xFF)
222                         {
223                                 bank->sectors[i].is_erased = 0;
224                                 break;
225                         }
226                 }       
227         }
228         
229         free(buffer);
230
231         return ERROR_OK;
232 }
233
234 int str7x_protect_check(struct flash_bank_s *bank)
235 {
236         str7x_flash_bank_t *str7x_info = bank->driver_priv;
237         target_t *target = str7x_info->target;
238         
239         int i;
240         int retval;
241
242         if (str7x_info->target->state != TARGET_HALTED)
243         {
244                 return ERROR_TARGET_NOT_HALTED;
245         }
246
247         target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), 4, 1, (u8*)&retval);
248
249         for (i = 0; i < bank->num_sectors; i++)
250         {
251                 if (retval & (mem_layout[i].reg_offset << i))
252                         bank->sectors[i].is_protected = 0;
253                 else
254                         bank->sectors[i].is_protected = 1;
255         }
256
257         return ERROR_OK;
258 }
259
260 int str7x_erase(struct flash_bank_s *bank, int first, int last)
261 {
262         str7x_flash_bank_t *str7x_info = bank->driver_priv;
263         target_t *target = str7x_info->target;
264         
265         int i;
266         u32 cmd;
267         u32 retval;
268         u32 erase_blocks;
269         
270         if (str7x_info->target->state != TARGET_HALTED)
271         {
272                 return ERROR_TARGET_NOT_HALTED;
273         }
274         
275         erase_blocks = 0;
276         
277         for (i = first; i <= last; i++)
278                 erase_blocks |= (mem_layout[i].reg_offset << i);
279         
280         cmd = FLASH_SER;
281         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
282         
283         cmd = erase_blocks;
284         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR1), 4, 1, (u8*)&cmd);
285         
286         cmd = FLASH_SER|FLASH_WMS;
287         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
288         
289         while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
290                 usleep(1000);
291         }
292         
293         retval = str7x_result(bank);
294         
295         if (retval & FLASH_ERER)
296                 return ERROR_FLASH_SECTOR_NOT_ERASED;
297         else if (retval & FLASH_WPF)
298                 return ERROR_FLASH_OPERATION_FAILED;
299         
300         for (i = first; i <= last; i++)
301                 bank->sectors[i].is_erased = 1;
302
303         return ERROR_OK;
304 }
305
306 int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
307 {
308         str7x_flash_bank_t *str7x_info = bank->driver_priv;
309         target_t *target = str7x_info->target;
310         int i;
311         u32 cmd;
312         u32 retval;
313         u32 protect_blocks;
314         
315         if (str7x_info->target->state != TARGET_HALTED)
316         {
317                 return ERROR_TARGET_NOT_HALTED;
318         }
319         
320         protect_blocks = 0xFFFFFFFF;
321
322         if( set )
323         {
324                 for (i = first; i <= last; i++)
325                         protect_blocks &= ~(mem_layout[i].reg_offset << i);
326         }
327
328         cmd = FLASH_SPR;
329         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
330         
331         cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
332         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
333         
334         cmd = protect_blocks;
335         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
336         
337         cmd = FLASH_SPR|FLASH_WMS;
338         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
339         
340         while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
341                 usleep(1000);
342         }
343         
344         retval = str7x_result(bank);
345         
346         if (retval & FLASH_ERER)
347                 return ERROR_FLASH_SECTOR_NOT_ERASED;
348         else if (retval & FLASH_WPF)
349                 return ERROR_FLASH_OPERATION_FAILED;
350
351         return ERROR_OK;
352 }
353
354 int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
355 {
356         str7x_flash_bank_t *str7x_info = bank->driver_priv;
357         target_t *target = str7x_info->target;
358         u32 dwords_remaining = (count / 8);
359         u32 bytes_remaining = (count & 0x00000007);
360         u32 address = bank->base + offset;
361         u32 *wordbuffer = (u32*)buffer;
362         u32 bytes_written = 0;
363         u32 cmd;
364         u32 retval;
365         
366         if (str7x_info->target->state != TARGET_HALTED)
367         {
368                 return ERROR_TARGET_NOT_HALTED;
369         }
370         
371         if (offset + count > bank->size)
372                 return ERROR_FLASH_DST_OUT_OF_BANK;
373         
374         while (dwords_remaining > 0)
375         {
376                 // command
377                 cmd = FLASH_DWPG;
378                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
379                 
380                 // address
381                 cmd = address;
382                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
383                 
384                 // data byte 1
385                 cmd = wordbuffer[bytes_written/4];
386                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
387                 bytes_written += 4;
388                 
389                 // data byte 2
390                 cmd = wordbuffer[bytes_written/4];
391                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, (u8*)&cmd);
392                 bytes_written += 4;
393                 
394                 /* start programming cycle */
395                 cmd = FLASH_DWPG|FLASH_WMS;
396                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
397                 
398                 while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
399                         usleep(1000);
400                 }
401                 
402                 retval = str7x_result(bank);
403                 
404                 if (retval & FLASH_PGER)
405                         return ERROR_FLASH_OPERATION_FAILED;
406                 else if (retval & FLASH_WPF)
407                         return ERROR_FLASH_OPERATION_FAILED;
408
409                 dwords_remaining--;
410                 address += 8;
411         }
412         
413         while( bytes_remaining > 0 )
414         {
415                 // command
416                 cmd = FLASH_WPG;
417                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
418                 
419                 // address
420                 cmd = address;
421                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
422                 
423                 // data byte
424                 cmd = buffer[bytes_written];
425                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
426                 
427                 /* start programming cycle */
428                 cmd = FLASH_WPG|FLASH_WMS;
429                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
430                 
431                 while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
432                         usleep(1000);
433                 }
434                 
435                 retval = str7x_result(bank);
436                 
437                 if (retval & FLASH_PGER)
438                         return ERROR_FLASH_OPERATION_FAILED;
439                 else if (retval & FLASH_WPF)
440                         return ERROR_FLASH_OPERATION_FAILED;
441
442                 address++;
443                 bytes_remaining--;
444                 bytes_written++;
445         }
446         
447         return ERROR_OK;
448 }
449
450 int str7x_probe(struct flash_bank_s *bank)
451 {
452         return ERROR_OK;
453 }
454
455 int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
456 {
457         return ERROR_OK;
458 }
459
460 int str7x_erase_check(struct flash_bank_s *bank)
461 {
462         return str7x_blank_check(bank, 0, bank->num_sectors - 1);
463 }
464
465 int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
466 {
467         snprintf(buf, buf_size, "str7x flash driver info" );
468         return ERROR_OK;
469 }