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

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)