]> git.gag.com Git - fw/openocd/blob - src/flash/str9x.c
- "flash write_binary" is now "flash write_bank" to clarify the focus of the
[fw/openocd] / src / flash / str9x.c
1 /***************************************************************************\r
2  *   Copyright (C) 2005 by Dominic Rath                                    *\r
3  *   Dominic.Rath@gmx.de                                                   *\r
4  *                                                                         *\r
5  *   This program is free software; you can redistribute it and/or modify  *\r
6  *   it under the terms of the GNU General Public License as published by  *\r
7  *   the Free Software Foundation; either version 2 of the License, or     *\r
8  *   (at your option) any later version.                                   *\r
9  *                                                                         *\r
10  *   This program is distributed in the hope that it will be useful,       *\r
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
13  *   GNU General Public License for more details.                          *\r
14  *                                                                         *\r
15  *   You should have received a copy of the GNU General Public License     *\r
16  *   along with this program; if not, write to the                         *\r
17  *   Free Software Foundation, Inc.,                                       *\r
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
19  ***************************************************************************/\r
20 #ifdef HAVE_CONFIG_H\r
21 #include "config.h"\r
22 #endif\r
23 \r
24 #include "replacements.h"\r
25 \r
26 #include "str9x.h"\r
27 #include "flash.h"\r
28 #include "target.h"\r
29 #include "log.h"\r
30 #include "armv4_5.h"\r
31 #include "arm966e.h"\r
32 #include "algorithm.h"\r
33 #include "binarybuffer.h"\r
34 \r
35 #include <stdlib.h>\r
36 #include <string.h>\r
37 #include <unistd.h>\r
38 \r
39 str9x_mem_layout_t mem_layout_str9bank0[] = {\r
40         {0x00000000, 0x10000, 0x01},\r
41         {0x00010000, 0x10000, 0x02},\r
42         {0x00020000, 0x10000, 0x04},\r
43         {0x00030000, 0x10000, 0x08},\r
44         {0x00040000, 0x10000, 0x10},\r
45         {0x00050000, 0x10000, 0x20},\r
46         {0x00060000, 0x10000, 0x40},\r
47         {0x00070000, 0x10000, 0x80},\r
48 };\r
49 \r
50 str9x_mem_layout_t mem_layout_str9bank1[] = {\r
51         {0x00000000, 0x02000, 0x100},\r
52         {0x00002000, 0x02000, 0x200},\r
53         {0x00004000, 0x02000, 0x400},\r
54         {0x00006000, 0x02000, 0x800}\r
55 };\r
56 \r
57 static u32 bank1start = 0x00080000;\r
58 \r
59 int str9x_register_commands(struct command_context_s *cmd_ctx);\r
60 int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
61 int str9x_erase(struct flash_bank_s *bank, int first, int last);\r
62 int str9x_protect(struct flash_bank_s *bank, int set, int first, int last);\r
63 int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
64 int str9x_probe(struct flash_bank_s *bank);\r
65 int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
66 int str9x_protect_check(struct flash_bank_s *bank);\r
67 int str9x_erase_check(struct flash_bank_s *bank);\r
68 int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
69 \r
70 int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
71 \r
72 flash_driver_t str9x_flash =\r
73 {\r
74         .name = "str9x",\r
75         .register_commands = str9x_register_commands,\r
76         .flash_bank_command = str9x_flash_bank_command,\r
77         .erase = str9x_erase,\r
78         .protect = str9x_protect,\r
79         .write = str9x_write,\r
80         .probe = str9x_probe,\r
81         .auto_probe = str9x_probe,\r
82         .erase_check = str9x_erase_check,\r
83         .protect_check = str9x_protect_check,\r
84         .info = str9x_info\r
85 };\r
86 \r
87 int str9x_register_commands(struct command_context_s *cmd_ctx)\r
88 {\r
89         command_t *str9x_cmd = register_command(cmd_ctx, NULL, "str9x", NULL, COMMAND_ANY, NULL);\r
90         \r
91         register_command(cmd_ctx, str9x_cmd, "flash_config", str9x_handle_flash_config_command, COMMAND_EXEC,\r
92                                          "configure str9 flash controller");\r
93                                          \r
94         return ERROR_OK;\r
95 }\r
96 \r
97 int str9x_build_block_list(struct flash_bank_s *bank)\r
98 {\r
99         str9x_flash_bank_t *str9x_info = bank->driver_priv;\r
100         \r
101         int i;\r
102         int num_sectors = 0;\r
103         int b0_sectors = 0, b1_sectors = 0;\r
104                 \r
105         switch (bank->size)\r
106         {\r
107                 case (256 * 1024):\r
108                         b0_sectors = 4;\r
109                         break;\r
110                 case (512 * 1024):\r
111                         b0_sectors = 8;\r
112                         break;\r
113                 case (32 * 1024):\r
114                         b1_sectors = 4;\r
115                         bank1start = bank->base;\r
116                         break;\r
117                 default:\r
118                         ERROR("BUG: unknown bank->size encountered");\r
119                         exit(-1);\r
120         }\r
121                 \r
122         num_sectors = b0_sectors + b1_sectors;\r
123         \r
124         bank->num_sectors = num_sectors;\r
125         bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);\r
126         str9x_info->sector_bits = malloc(sizeof(u32) * num_sectors);\r
127         \r
128         num_sectors = 0;\r
129         \r
130         for (i = 0; i < b0_sectors; i++)\r
131         {\r
132                 bank->sectors[num_sectors].offset = mem_layout_str9bank0[i].sector_start;\r
133                 bank->sectors[num_sectors].size = mem_layout_str9bank0[i].sector_size;\r
134                 bank->sectors[num_sectors].is_erased = -1;\r
135                 bank->sectors[num_sectors].is_protected = 1;\r
136                 str9x_info->sector_bits[num_sectors++] = mem_layout_str9bank0[i].sector_bit;\r
137         }\r
138 \r
139         for (i = 0; i < b1_sectors; i++)\r
140         {\r
141                 bank->sectors[num_sectors].offset = mem_layout_str9bank1[i].sector_start;\r
142                 bank->sectors[num_sectors].size = mem_layout_str9bank1[i].sector_size;\r
143                 bank->sectors[num_sectors].is_erased = -1;\r
144                 bank->sectors[num_sectors].is_protected = 1;\r
145                 str9x_info->sector_bits[num_sectors++] = mem_layout_str9bank1[i].sector_bit;\r
146         }\r
147         \r
148         return ERROR_OK;\r
149 }\r
150 \r
151 /* flash bank str9x <base> <size> 0 0 <target#>\r
152  */\r
153 int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
154 {\r
155         str9x_flash_bank_t *str9x_info;\r
156         \r
157         if (argc < 6)\r
158         {\r
159                 WARNING("incomplete flash_bank str9x configuration");\r
160                 return ERROR_FLASH_BANK_INVALID;\r
161         }\r
162         \r
163         str9x_info = malloc(sizeof(str9x_flash_bank_t));\r
164         bank->driver_priv = str9x_info;\r
165         \r
166         str9x_build_block_list(bank);\r
167         \r
168         str9x_info->write_algorithm = NULL;\r
169         \r
170         return ERROR_OK;\r
171 }\r
172 \r
173 int str9x_blank_check(struct flash_bank_s *bank, int first, int last)\r
174 {\r
175         target_t *target = bank->target;\r
176         u8 *buffer;\r
177         int i;\r
178         int nBytes;\r
179         \r
180         if ((first < 0) || (last > bank->num_sectors))\r
181                 return ERROR_FLASH_SECTOR_INVALID;\r
182 \r
183         if (bank->target->state != TARGET_HALTED)\r
184         {\r
185                 return ERROR_TARGET_NOT_HALTED;\r
186         }\r
187         \r
188         buffer = malloc(256);\r
189         \r
190         for (i = first; i <= last; i++)\r
191         {\r
192                 bank->sectors[i].is_erased = 1;\r
193 \r
194                 target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);\r
195                 \r
196                 for (nBytes = 0; nBytes < 256; nBytes++)\r
197                 {\r
198                         if (buffer[nBytes] != 0xFF)\r
199                         {\r
200                                 bank->sectors[i].is_erased = 0;\r
201                                 break;\r
202                         }\r
203                 }       \r
204         }\r
205         \r
206         free(buffer);\r
207 \r
208         return ERROR_OK;\r
209 }\r
210 \r
211 int str9x_protect_check(struct flash_bank_s *bank)\r
212 {\r
213         str9x_flash_bank_t *str9x_info = bank->driver_priv;\r
214         target_t *target = bank->target;\r
215         \r
216         int i;\r
217         u32 adr;\r
218         u16 status;\r
219 \r
220         if (bank->target->state != TARGET_HALTED)\r
221         {\r
222                 return ERROR_TARGET_NOT_HALTED;\r
223         }\r
224 \r
225         /* read level one protection */\r
226         \r
227         adr = bank1start + 0x10;\r
228         \r
229         target_write_u16(target, adr, 0x90);\r
230         target_read_u16(target, adr, &status);\r
231         target_write_u16(target, adr, 0xFF);\r
232         \r
233         for (i = 0; i < bank->num_sectors; i++)\r
234         {\r
235                 if (status & str9x_info->sector_bits[i])\r
236                         bank->sectors[i].is_protected = 1;\r
237                 else\r
238                         bank->sectors[i].is_protected = 0;\r
239         }\r
240         \r
241         return ERROR_OK;\r
242 }\r
243 \r
244 int str9x_erase(struct flash_bank_s *bank, int first, int last)\r
245 {\r
246         target_t *target = bank->target;\r
247         int i;\r
248         u32 adr;\r
249         u8 status;\r
250         \r
251         for (i = first; i <= last; i++)\r
252         {\r
253                 adr = bank->base + bank->sectors[i].offset;\r
254                 \r
255         /* erase sectors */\r
256                 target_write_u16(target, adr, 0x20);\r
257                 target_write_u16(target, adr, 0xD0);\r
258                 \r
259                 /* get status */\r
260                 target_write_u16(target, adr, 0x70);\r
261                 \r
262                 while (1) {\r
263                         target_read_u8(target, adr, &status);\r
264                         if( status & 0x80 )\r
265                                 break;\r
266                         usleep(1000);\r
267                 }\r
268                 \r
269                 /* clear status, also clear read array */\r
270                 target_write_u16(target, adr, 0x50);\r
271                 \r
272                 /* read array command */\r
273                 target_write_u16(target, adr, 0xFF);\r
274                 \r
275                 if( status & 0x22 )\r
276                 {\r
277                         ERROR("error erasing flash bank, status: 0x%x", status);\r
278                         return ERROR_FLASH_OPERATION_FAILED;\r
279                 }\r
280         }\r
281         \r
282         for (i = first; i <= last; i++)\r
283                 bank->sectors[i].is_erased = 1;\r
284 \r
285         return ERROR_OK;\r
286 }\r
287 \r
288 int str9x_protect(struct flash_bank_s *bank, int set, int first, int last)\r
289 {\r
290         target_t *target = bank->target;\r
291         int i;\r
292         u32 adr;\r
293         u8 status;\r
294         \r
295         if (bank->target->state != TARGET_HALTED)\r
296         {\r
297                 return ERROR_TARGET_NOT_HALTED;\r
298         }\r
299         \r
300         for (i = first; i <= last; i++)\r
301         {\r
302                 /* Level One Protection */\r
303         \r
304                 adr = bank->base + bank->sectors[i].offset;\r
305                 \r
306                 target_write_u16(target, adr, 0x60);\r
307                 if( set )\r
308                         target_write_u16(target, adr, 0x01);\r
309                 else\r
310                         target_write_u16(target, adr, 0xD0);\r
311                 \r
312                 /* query status */\r
313                 target_read_u8(target, adr, &status);\r
314         }\r
315         \r
316         return ERROR_OK;\r
317 }\r
318 \r
319 int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
320 {\r
321         str9x_flash_bank_t *str9x_info = bank->driver_priv;\r
322         target_t *target = bank->target;\r
323         u32 buffer_size = 8192;\r
324         working_area_t *source;\r
325         u32 address = bank->base + offset;\r
326         reg_param_t reg_params[4];\r
327         armv4_5_algorithm_t armv4_5_info;\r
328         int retval;\r
329         \r
330         u32 str9x_flash_write_code[] = {\r
331                                         /* write:                               */\r
332                 0xe3c14003,     /*      bic     r4, r1, #3              */\r
333                 0xe3a03040,     /*      mov     r3, #0x40               */\r
334                 0xe1c430b0,     /*      strh r3, [r4, #0]       */\r
335                 0xe0d030b2,     /*      ldrh r3, [r0], #2       */\r
336                 0xe0c130b2,     /*      strh r3, [r1], #2       */\r
337                 0xe3a03070,     /*      mov r3, #0x70           */\r
338                 0xe1c430b0,     /*      strh r3, [r4, #0]       */\r
339                                         /* busy:                                */\r
340                 0xe5d43000,     /*      ldrb r3, [r4, #0]       */\r
341                 0xe3130080,     /*      tst r3, #0x80           */\r
342                 0x0afffffc,     /*      beq busy                        */\r
343                 0xe3a05050,     /*      mov     r5, #0x50               */\r
344                 0xe1c450b0,     /*      strh r5, [r4, #0]       */\r
345                 0xe3a050ff,     /*      mov     r5, #0xFF               */\r
346                 0xe1c450b0,     /*      strh r5, [r4, #0]       */\r
347                 0xe3130012,     /*      tst     r3, #0x12               */\r
348                 0x1a000001,     /*      bne exit                        */\r
349                 0xe2522001,     /*      subs r2, r2, #1         */\r
350                 0x1affffed,     /*      bne write                       */\r
351                                         /* exit:                                */\r
352                 0xeafffffe,     /*      b exit                          */\r
353         };\r
354         \r
355         /* flash write code */\r
356         if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)\r
357         {\r
358                 WARNING("no working area available, can't do block memory writes");\r
359                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
360         };\r
361                 \r
362         target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (u8*)str9x_flash_write_code);\r
363 \r
364         /* memory buffer */\r
365         while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)\r
366         {\r
367                 buffer_size /= 2;\r
368                 if (buffer_size <= 256)\r
369                 {\r
370                         /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */\r
371                         if (str9x_info->write_algorithm)\r
372                                 target_free_working_area(target, str9x_info->write_algorithm);\r
373                         \r
374                         WARNING("no large enough working area available, can't do block memory writes");\r
375                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
376                 }\r
377         }\r
378         \r
379         armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;\r
380         armv4_5_info.core_mode = ARMV4_5_MODE_SVC;\r
381         armv4_5_info.core_state = ARMV4_5_STATE_ARM;\r
382         \r
383         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);\r
384         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);\r
385         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);\r
386         init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);\r
387         \r
388         while (count > 0)\r
389         {\r
390                 u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;\r
391                 \r
392                 target_write_buffer(target, source->address, thisrun_count * 2, buffer);\r
393                 \r
394                 buf_set_u32(reg_params[0].value, 0, 32, source->address);\r
395                 buf_set_u32(reg_params[1].value, 0, 32, address);\r
396                 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);\r
397 \r
398                 if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)\r
399                 {\r
400                         target_free_working_area(target, source);\r
401                         target_free_working_area(target, str9x_info->write_algorithm);\r
402                         ERROR("error executing str9x flash write algorithm");\r
403                         return ERROR_FLASH_OPERATION_FAILED;\r
404                 }\r
405         \r
406                 if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)\r
407                 {\r
408                         return ERROR_FLASH_OPERATION_FAILED;\r
409                 }\r
410                 \r
411                 buffer += thisrun_count * 2;\r
412                 address += thisrun_count * 2;\r
413                 count -= thisrun_count;\r
414         }\r
415         \r
416         target_free_working_area(target, source);\r
417         target_free_working_area(target, str9x_info->write_algorithm);\r
418         \r
419         destroy_reg_param(&reg_params[0]);\r
420         destroy_reg_param(&reg_params[1]);\r
421         destroy_reg_param(&reg_params[2]);\r
422         destroy_reg_param(&reg_params[3]);\r
423         \r
424         return ERROR_OK;\r
425 }\r
426 \r
427 int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
428 {\r
429         target_t *target = bank->target;\r
430         u32 words_remaining = (count / 2);\r
431         u32 bytes_remaining = (count & 0x00000001);\r
432         u32 address = bank->base + offset;\r
433         u32 bytes_written = 0;\r
434         u8 status;\r
435         u32 retval;\r
436         u32 check_address = offset;\r
437         u32 bank_adr;\r
438         int i;\r
439         \r
440         if (offset & 0x1)\r
441         {\r
442                 WARNING("offset 0x%x breaks required 2-byte alignment", offset);\r
443                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
444         }\r
445         \r
446         for (i = 0; i < bank->num_sectors; i++)\r
447         {\r
448                 u32 sec_start = bank->sectors[i].offset;\r
449                 u32 sec_end = sec_start + bank->sectors[i].size;\r
450                 \r
451                 /* check if destination falls within the current sector */\r
452                 if ((check_address >= sec_start) && (check_address < sec_end))\r
453                 {\r
454                         /* check if destination ends in the current sector */\r
455                         if (offset + count < sec_end)\r
456                                 check_address = offset + count;\r
457                         else\r
458                                 check_address = sec_end;\r
459                 }\r
460         }\r
461         \r
462         if (check_address != offset + count)\r
463                 return ERROR_FLASH_DST_OUT_OF_BANK;\r
464         \r
465         /* multiple half words (2-byte) to be programmed? */\r
466         if (words_remaining > 0) \r
467         {\r
468                 /* try using a block write */\r
469                 if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)\r
470                 {\r
471                         if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)\r
472                         {\r
473                                 /* if block write failed (no sufficient working area),\r
474                                  * we use normal (slow) single dword accesses */ \r
475                                 WARNING("couldn't use block writes, falling back to single memory accesses");\r
476                         }\r
477                         else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
478                         {\r
479                                 ERROR("flash writing failed with error code: 0x%x", retval);\r
480                                 return ERROR_FLASH_OPERATION_FAILED;\r
481                         }\r
482                 }\r
483                 else\r
484                 {\r
485                         buffer += words_remaining * 2;\r
486                         address += words_remaining * 2;\r
487                         words_remaining = 0;\r
488                 }\r
489         }\r
490 \r
491         while (words_remaining > 0)\r
492         {\r
493                 bank_adr = address & ~0x03;\r
494                 \r
495                 /* write data command */\r
496                 target_write_u16(target, bank_adr, 0x40);\r
497                 target->type->write_memory(target, address, 2, 1, buffer + bytes_written);\r
498                 \r
499                 /* get status command */\r
500                 target_write_u16(target, bank_adr, 0x70);\r
501                 \r
502                 while (1) {\r
503                         target_read_u8(target, bank_adr, &status);\r
504                         if( status & 0x80 )\r
505                                 break;\r
506                         usleep(1000);\r
507                 }\r
508                 \r
509                 /* clear status reg and read array */\r
510                 target_write_u16(target, bank_adr, 0x50);\r
511                 target_write_u16(target, bank_adr, 0xFF);\r
512                 \r
513                 if (status & 0x10)\r
514                         return ERROR_FLASH_OPERATION_FAILED;\r
515                 else if (status & 0x02)\r
516                         return ERROR_FLASH_OPERATION_FAILED;\r
517 \r
518                 bytes_written += 2;\r
519                 words_remaining--;\r
520                 address += 2;\r
521         }\r
522         \r
523         if (bytes_remaining)\r
524         {\r
525                 u8 last_halfword[2] = {0xff, 0xff};\r
526                 int i = 0;\r
527                                 \r
528                 while(bytes_remaining > 0)\r
529                 {\r
530                         last_halfword[i++] = *(buffer + bytes_written); \r
531                         bytes_remaining--;\r
532                         bytes_written++;\r
533                 }\r
534                 \r
535                 bank_adr = address & ~0x03;\r
536                 \r
537                 /* write data comamnd */\r
538                 target_write_u16(target, bank_adr, 0x40);\r
539                 target->type->write_memory(target, address, 2, 1, last_halfword);\r
540                 \r
541                 /* query status command */\r
542                 target_write_u16(target, bank_adr, 0x70);\r
543                 \r
544                 while (1) {\r
545                         target_read_u8(target, bank_adr, &status);\r
546                         if( status & 0x80 )\r
547                                 break;\r
548                         usleep(1000);\r
549                 }\r
550                 \r
551                 /* clear status reg and read array */\r
552                 target_write_u16(target, bank_adr, 0x50);\r
553                 target_write_u16(target, bank_adr, 0xFF);\r
554                 \r
555                 if (status & 0x10)\r
556                         return ERROR_FLASH_OPERATION_FAILED;\r
557                 else if (status & 0x02)\r
558                         return ERROR_FLASH_OPERATION_FAILED;\r
559         }\r
560                 \r
561         return ERROR_OK;\r
562 }\r
563 \r
564 int str9x_probe(struct flash_bank_s *bank)\r
565 {\r
566         return ERROR_OK;\r
567 }\r
568 \r
569 int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
570 {\r
571         return ERROR_OK;\r
572 }\r
573 \r
574 int str9x_erase_check(struct flash_bank_s *bank)\r
575 {\r
576         return str9x_blank_check(bank, 0, bank->num_sectors - 1);\r
577 }\r
578 \r
579 int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
580 {\r
581         snprintf(buf, buf_size, "str9x flash driver info" );\r
582         return ERROR_OK;\r
583 }\r
584 \r
585 int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
586 {\r
587         str9x_flash_bank_t *str9x_info;\r
588         flash_bank_t *bank;\r
589         target_t *target = NULL;\r
590         \r
591         if (argc < 5)\r
592         {\r
593                 return ERROR_COMMAND_SYNTAX_ERROR;\r
594         }\r
595         \r
596         bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
597         if (!bank)\r
598         {\r
599                 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
600                 return ERROR_OK;\r
601         }\r
602         \r
603         str9x_info = bank->driver_priv;\r
604         \r
605         target = bank->target;\r
606         \r
607         if (bank->target->state != TARGET_HALTED)\r
608         {\r
609                 return ERROR_TARGET_NOT_HALTED;\r
610         }\r
611         \r
612         /* config flash controller */\r
613         target_write_u32(target, FLASH_BBSR, strtoul(args[1], NULL, 0));\r
614         target_write_u32(target, FLASH_NBBSR, strtoul(args[2], NULL, 0));\r
615         target_write_u32(target, FLASH_BBADR, (strtoul(args[3], NULL, 0) >> 2));\r
616         target_write_u32(target, FLASH_NBBADR, (strtoul(args[4], NULL, 0) >> 2));\r
617 \r
618         /* set bit 18 instruction TCM order as per flash programming manual */\r
619         arm966e_write_cp15(target, 62, 0x40000);\r
620         \r
621         /* enable flash bank 1 */\r
622         target_write_u32(target, FLASH_CR, 0x18);\r
623         return ERROR_OK;\r
624 }\r