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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)