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

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)