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

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)