- Added support for native MinGW builds (thanks to Spencer Oliver and Michael Fischer...
[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, 0x10},
48         {0x000C2000, 0x02000, 0x10},
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 '%i' configured", args[6]);
170                 exit(-1);
171         }
172
173         str7x_build_block_list(bank);
174         
175         return ERROR_OK;
176 }
177
178 u32 str7x_status(struct flash_bank_s *bank)
179 {
180         str7x_flash_bank_t *str7x_info = bank->driver_priv;
181         target_t *target = str7x_info->target;
182         u32 retval;
183
184         target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&retval);
185
186         return retval;
187 }
188
189 u32 str7x_result(struct flash_bank_s *bank)
190 {
191         str7x_flash_bank_t *str7x_info = bank->driver_priv;
192         target_t *target = str7x_info->target;
193         u32 retval;
194
195         target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_ER), 4, 1, (u8*)&retval);
196         
197         return retval;
198 }
199
200 int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
201 {
202         str7x_flash_bank_t *str7x_info = bank->driver_priv;
203         target_t *target = str7x_info->target;
204         u8 *buffer;
205         int i;
206         int nBytes;
207         
208         if ((first < 0) || (last > bank->num_sectors))
209                 return ERROR_FLASH_SECTOR_INVALID;
210
211         if (str7x_info->target->state != TARGET_HALTED)
212         {
213                 return ERROR_TARGET_NOT_HALTED;
214         }
215         
216         buffer = malloc(256);
217         
218         for (i = first; i <= last; i++)
219         {
220                 bank->sectors[i].is_erased = 1;
221
222                 target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
223                 
224                 for (nBytes = 0; nBytes < 256; nBytes++)
225                 {
226                         if (buffer[nBytes] != 0xFF)
227                         {
228                                 bank->sectors[i].is_erased = 0;
229                                 break;
230                         }
231                 }       
232         }
233         
234         free(buffer);
235
236         return ERROR_OK;
237 }
238
239 int str7x_protect_check(struct flash_bank_s *bank)
240 {
241         str7x_flash_bank_t *str7x_info = bank->driver_priv;
242         target_t *target = str7x_info->target;
243         
244         int i;
245         int retval;
246
247         if (str7x_info->target->state != TARGET_HALTED)
248         {
249                 return ERROR_TARGET_NOT_HALTED;
250         }
251
252         target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), 4, 1, (u8*)&retval);
253
254         for (i = 0; i < bank->num_sectors; i++)
255         {
256                 if (retval & (mem_layout[i].reg_offset << i))
257                         bank->sectors[i].is_protected = 0;
258                 else
259                         bank->sectors[i].is_protected = 1;
260         }
261
262         return ERROR_OK;
263 }
264
265 int str7x_erase(struct flash_bank_s *bank, int first, int last)
266 {
267         str7x_flash_bank_t *str7x_info = bank->driver_priv;
268         target_t *target = str7x_info->target;
269         
270         int i;
271         u32 cmd;
272         u32 retval;
273         u32 erase_blocks;
274         
275         if (str7x_info->target->state != TARGET_HALTED)
276         {
277                 return ERROR_TARGET_NOT_HALTED;
278         }
279         
280         erase_blocks = 0;
281         
282         for (i = first; i <= last; i++)
283                 erase_blocks |= (mem_layout[i].reg_offset << i);
284         
285         cmd = FLASH_SER;
286         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
287         
288         cmd = erase_blocks;
289         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR1), 4, 1, (u8*)&cmd);
290         
291         cmd = FLASH_SER|FLASH_WMS;
292         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
293         
294         while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
295                 usleep(1000);
296         }
297         
298         retval = str7x_result(bank);
299         
300         if (retval & FLASH_ERER)
301                 return ERROR_FLASH_SECTOR_NOT_ERASED;
302         else if (retval & FLASH_WPF)
303                 return ERROR_FLASH_OPERATION_FAILED;
304         
305         for (i = first; i <= last; i++)
306                 bank->sectors[i].is_erased = 1;
307
308         return ERROR_OK;
309 }
310
311 int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
312 {
313         str7x_flash_bank_t *str7x_info = bank->driver_priv;
314         target_t *target = str7x_info->target;
315         int i;
316         u32 cmd;
317         u32 retval;
318         u32 protect_blocks;
319         
320         if (str7x_info->target->state != TARGET_HALTED)
321         {
322                 return ERROR_TARGET_NOT_HALTED;
323         }
324         
325         protect_blocks = 0xFFFFFFFF;
326
327         if( set )
328         {
329                 for (i = first; i <= last; i++)
330                         protect_blocks &= ~(mem_layout[i].reg_offset << i);
331         }
332
333         cmd = FLASH_SPR;
334         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
335         
336         cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
337         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
338         
339         cmd = protect_blocks;
340         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
341         
342         cmd = FLASH_SPR|FLASH_WMS;
343         target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
344         
345         while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
346                 usleep(1000);
347         }
348         
349         retval = str7x_result(bank);
350         
351         if (retval & FLASH_ERER)
352                 return ERROR_FLASH_SECTOR_NOT_ERASED;
353         else if (retval & FLASH_WPF)
354                 return ERROR_FLASH_OPERATION_FAILED;
355
356         return ERROR_OK;
357 }
358
359 int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
360 {
361         str7x_flash_bank_t *str7x_info = bank->driver_priv;
362         target_t *target = str7x_info->target;
363         u32 dwords_remaining = (count / 8);
364         u32 bytes_remaining = (count & 0x00000007);
365         u32 address = bank->base + offset;
366         u32 *wordbuffer = (u32*)buffer;
367         u32 bytes_written = 0;
368         u32 cmd;
369         u32 retval;
370         
371         if (str7x_info->target->state != TARGET_HALTED)
372         {
373                 return ERROR_TARGET_NOT_HALTED;
374         }
375         
376         if (offset + count > bank->size)
377                 return ERROR_FLASH_DST_OUT_OF_BANK;
378         
379         while (dwords_remaining > 0)
380         {
381                 // command
382                 cmd = FLASH_DWPG;
383                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
384                 
385                 // address
386                 cmd = address;
387                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
388                 
389                 // data byte 1
390                 cmd = wordbuffer[bytes_written/4];
391                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
392                 bytes_written += 4;
393                 
394                 // data byte 2
395                 cmd = wordbuffer[bytes_written/4];
396                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, (u8*)&cmd);
397                 bytes_written += 4;
398                 
399                 /* start programming cycle */
400                 cmd = FLASH_DWPG|FLASH_WMS;
401                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
402                 
403                 while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
404                         usleep(1000);
405                 }
406                 
407                 retval = str7x_result(bank);
408                 
409                 if (retval & FLASH_PGER)
410                         return ERROR_FLASH_OPERATION_FAILED;
411                 else if (retval & FLASH_WPF)
412                         return ERROR_FLASH_OPERATION_FAILED;
413
414                 dwords_remaining--;
415                 address += 8;
416         }
417         
418         while( bytes_remaining > 0 )
419         {
420                 // command
421                 cmd = FLASH_WPG;
422                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
423                 
424                 // address
425                 cmd = address;
426                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
427                 
428                 // data byte
429                 cmd = buffer[bytes_written];
430                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
431                 
432                 /* start programming cycle */
433                 cmd = FLASH_WPG|FLASH_WMS;
434                 target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
435                 
436                 while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
437                         usleep(1000);
438                 }
439                 
440                 retval = str7x_result(bank);
441                 
442                 if (retval & FLASH_PGER)
443                         return ERROR_FLASH_OPERATION_FAILED;
444                 else if (retval & FLASH_WPF)
445                         return ERROR_FLASH_OPERATION_FAILED;
446
447                 address++;
448                 bytes_remaining--;
449                 bytes_written++;
450         }
451         
452         return ERROR_OK;
453 }
454
455 int str7x_probe(struct flash_bank_s *bank)
456 {
457         return ERROR_OK;
458 }
459
460 int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
461 {
462         return ERROR_OK;
463 }
464
465 int str7x_erase_check(struct flash_bank_s *bank)
466 {
467         return str7x_blank_check(bank, 0, bank->num_sectors - 1);
468 }
469
470 int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
471 {
472         snprintf(buf, buf_size, "str7x flash driver info" );
473         return ERROR_OK;
474 }