Close dangling file handle
[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 target_write_u16(target, adr, 0xFF);
220
221 for (i = 0; i < bank->num_sectors; i++)
222 {
223 if (status & str9x_info->sector_bits[i])
224 bank->sectors[i].is_protected = 1;
225 else
226 bank->sectors[i].is_protected = 0;
227 }
228
229 return ERROR_OK;
230 }
231
232 int str9x_erase(struct flash_bank_s *bank, int first, int last)
233 {
234 target_t *target = bank->target;
235 int i;
236 u32 adr;
237 u8 status;
238
239 if (bank->target->state != TARGET_HALTED)
240 {
241 return ERROR_TARGET_NOT_HALTED;
242 }
243
244 for (i = first; i <= last; i++)
245 {
246 adr = bank->base + bank->sectors[i].offset;
247
248 /* erase sectors */
249 target_write_u16(target, adr, 0x20);
250 target_write_u16(target, adr, 0xD0);
251
252 /* get status */
253 target_write_u16(target, adr, 0x70);
254
255 while (1) {
256 target_read_u8(target, adr, &status);
257 if( status & 0x80 )
258 break;
259 usleep(1000);
260 }
261
262 /* clear status, also clear read array */
263 target_write_u16(target, adr, 0x50);
264
265 /* read array command */
266 target_write_u16(target, adr, 0xFF);
267
268 if( status & 0x22 )
269 {
270 LOG_ERROR("error erasing flash bank, status: 0x%x", status);
271 return ERROR_FLASH_OPERATION_FAILED;
272 }
273 }
274
275 for (i = first; i <= last; i++)
276 bank->sectors[i].is_erased = 1;
277
278 return ERROR_OK;
279 }
280
281 int str9x_protect(struct flash_bank_s *bank, int set, int first, int last)
282 {
283 target_t *target = bank->target;
284 int i;
285 u32 adr;
286 u8 status;
287
288 if (bank->target->state != TARGET_HALTED)
289 {
290 return ERROR_TARGET_NOT_HALTED;
291 }
292
293 for (i = first; i <= last; i++)
294 {
295 /* Level One Protection */
296
297 adr = bank->base + bank->sectors[i].offset;
298
299 target_write_u16(target, adr, 0x60);
300 if( set )
301 target_write_u16(target, adr, 0x01);
302 else
303 target_write_u16(target, adr, 0xD0);
304
305 /* query status */
306 target_read_u8(target, adr, &status);
307 }
308
309 return ERROR_OK;
310 }
311
312 int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
313 {
314 str9x_flash_bank_t *str9x_info = bank->driver_priv;
315 target_t *target = bank->target;
316 u32 buffer_size = 8192;
317 working_area_t *source;
318 u32 address = bank->base + offset;
319 reg_param_t reg_params[4];
320 armv4_5_algorithm_t armv4_5_info;
321 int retval;
322
323 u32 str9x_flash_write_code[] = {
324 /* write: */
325 0xe3c14003, /* bic r4, r1, #3 */
326 0xe3a03040, /* mov r3, #0x40 */
327 0xe1c430b0, /* strh r3, [r4, #0] */
328 0xe0d030b2, /* ldrh r3, [r0], #2 */
329 0xe0c130b2, /* strh r3, [r1], #2 */
330 0xe3a03070, /* mov r3, #0x70 */
331 0xe1c430b0, /* strh r3, [r4, #0] */
332 /* busy: */
333 0xe5d43000, /* ldrb r3, [r4, #0] */
334 0xe3130080, /* tst r3, #0x80 */
335 0x0afffffc, /* beq busy */
336 0xe3a05050, /* mov r5, #0x50 */
337 0xe1c450b0, /* strh r5, [r4, #0] */
338 0xe3a050ff, /* mov r5, #0xFF */
339 0xe1c450b0, /* strh r5, [r4, #0] */
340 0xe3130012, /* tst r3, #0x12 */
341 0x1a000001, /* bne exit */
342 0xe2522001, /* subs r2, r2, #1 */
343 0x1affffed, /* bne write */
344 /* exit: */
345 0xeafffffe, /* b exit */
346 };
347
348 /* flash write code */
349 if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
350 {
351 LOG_WARNING("no working area available, can't do block memory writes");
352 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
353 };
354
355 target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (u8*)str9x_flash_write_code);
356
357 /* memory buffer */
358 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
359 {
360 buffer_size /= 2;
361 if (buffer_size <= 256)
362 {
363 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
364 if (str9x_info->write_algorithm)
365 target_free_working_area(target, str9x_info->write_algorithm);
366
367 LOG_WARNING("no large enough working area available, can't do block memory writes");
368 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
369 }
370 }
371
372 armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
373 armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
374 armv4_5_info.core_state = ARMV4_5_STATE_ARM;
375
376 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
377 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
378 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
379 init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
380
381 while (count > 0)
382 {
383 u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
384
385 target_write_buffer(target, source->address, thisrun_count * 2, buffer);
386
387 buf_set_u32(reg_params[0].value, 0, 32, source->address);
388 buf_set_u32(reg_params[1].value, 0, 32, address);
389 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
390
391 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)
392 {
393 target_free_working_area(target, source);
394 target_free_working_area(target, str9x_info->write_algorithm);
395 LOG_ERROR("error executing str9x flash write algorithm");
396 return ERROR_FLASH_OPERATION_FAILED;
397 }
398
399 if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
400 {
401 return ERROR_FLASH_OPERATION_FAILED;
402 }
403
404 buffer += thisrun_count * 2;
405 address += thisrun_count * 2;
406 count -= thisrun_count;
407 }
408
409 target_free_working_area(target, source);
410 target_free_working_area(target, str9x_info->write_algorithm);
411
412 destroy_reg_param(&reg_params[0]);
413 destroy_reg_param(&reg_params[1]);
414 destroy_reg_param(&reg_params[2]);
415 destroy_reg_param(&reg_params[3]);
416
417 return ERROR_OK;
418 }
419
420 int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
421 {
422 target_t *target = bank->target;
423 u32 words_remaining = (count / 2);
424 u32 bytes_remaining = (count & 0x00000001);
425 u32 address = bank->base + offset;
426 u32 bytes_written = 0;
427 u8 status;
428 u32 retval;
429 u32 check_address = offset;
430 u32 bank_adr;
431 int i;
432
433 if (bank->target->state != TARGET_HALTED)
434 {
435 return ERROR_TARGET_NOT_HALTED;
436 }
437
438 if (offset & 0x1)
439 {
440 LOG_WARNING("offset 0x%x breaks required 2-byte alignment", offset);
441 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
442 }
443
444 for (i = 0; i < bank->num_sectors; i++)
445 {
446 u32 sec_start = bank->sectors[i].offset;
447 u32 sec_end = sec_start + bank->sectors[i].size;
448
449 /* check if destination falls within the current sector */
450 if ((check_address >= sec_start) && (check_address < sec_end))
451 {
452 /* check if destination ends in the current sector */
453 if (offset + count < sec_end)
454 check_address = offset + count;
455 else
456 check_address = sec_end;
457 }
458 }
459
460 if (check_address != offset + count)
461 return ERROR_FLASH_DST_OUT_OF_BANK;
462
463 /* multiple half words (2-byte) to be programmed? */
464 if (words_remaining > 0)
465 {
466 /* try using a block write */
467 if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
468 {
469 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
470 {
471 /* if block write failed (no sufficient working area),
472 * we use normal (slow) single dword accesses */
473 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
474 }
475 else if (retval == ERROR_FLASH_OPERATION_FAILED)
476 {
477 LOG_ERROR("flash writing failed with error code: 0x%x", retval);
478 return ERROR_FLASH_OPERATION_FAILED;
479 }
480 }
481 else
482 {
483 buffer += words_remaining * 2;
484 address += words_remaining * 2;
485 words_remaining = 0;
486 }
487 }
488
489 while (words_remaining > 0)
490 {
491 bank_adr = address & ~0x03;
492
493 /* write data command */
494 target_write_u16(target, bank_adr, 0x40);
495 target->type->write_memory(target, address, 2, 1, buffer + bytes_written);
496
497 /* get status command */
498 target_write_u16(target, bank_adr, 0x70);
499
500 while (1) {
501 target_read_u8(target, bank_adr, &status);
502 if( status & 0x80 )
503 break;
504 usleep(1000);
505 }
506
507 /* clear status reg and read array */
508 target_write_u16(target, bank_adr, 0x50);
509 target_write_u16(target, bank_adr, 0xFF);
510
511 if (status & 0x10)
512 return ERROR_FLASH_OPERATION_FAILED;
513 else if (status & 0x02)
514 return ERROR_FLASH_OPERATION_FAILED;
515
516 bytes_written += 2;
517 words_remaining--;
518 address += 2;
519 }
520
521 if (bytes_remaining)
522 {
523 u8 last_halfword[2] = {0xff, 0xff};
524 int i = 0;
525
526 while(bytes_remaining > 0)
527 {
528 last_halfword[i++] = *(buffer + bytes_written);
529 bytes_remaining--;
530 bytes_written++;
531 }
532
533 bank_adr = address & ~0x03;
534
535 /* write data comamnd */
536 target_write_u16(target, bank_adr, 0x40);
537 target->type->write_memory(target, address, 2, 1, last_halfword);
538
539 /* query status command */
540 target_write_u16(target, bank_adr, 0x70);
541
542 while (1) {
543 target_read_u8(target, bank_adr, &status);
544 if( status & 0x80 )
545 break;
546 usleep(1000);
547 }
548
549 /* clear status reg and read array */
550 target_write_u16(target, bank_adr, 0x50);
551 target_write_u16(target, bank_adr, 0xFF);
552
553 if (status & 0x10)
554 return ERROR_FLASH_OPERATION_FAILED;
555 else if (status & 0x02)
556 return ERROR_FLASH_OPERATION_FAILED;
557 }
558
559 return ERROR_OK;
560 }
561
562 int str9x_probe(struct flash_bank_s *bank)
563 {
564 return ERROR_OK;
565 }
566
567 int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
568 {
569 return ERROR_OK;
570 }
571
572 int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size)
573 {
574 snprintf(buf, buf_size, "str9x flash driver info" );
575 return ERROR_OK;
576 }
577
578 int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
579 {
580 str9x_flash_bank_t *str9x_info;
581 flash_bank_t *bank;
582 target_t *target = NULL;
583
584 if (argc < 5)
585 {
586 return ERROR_COMMAND_SYNTAX_ERROR;
587 }
588
589 bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
590 if (!bank)
591 {
592 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
593 return ERROR_OK;
594 }
595
596 str9x_info = bank->driver_priv;
597
598 target = bank->target;
599
600 if (bank->target->state != TARGET_HALTED)
601 {
602 return ERROR_TARGET_NOT_HALTED;
603 }
604
605 /* config flash controller */
606 target_write_u32(target, FLASH_BBSR, strtoul(args[1], NULL, 0));
607 target_write_u32(target, FLASH_NBBSR, strtoul(args[2], NULL, 0));
608 target_write_u32(target, FLASH_BBADR, (strtoul(args[3], NULL, 0) >> 2));
609 target_write_u32(target, FLASH_NBBADR, (strtoul(args[4], NULL, 0) >> 2));
610
611 /* set bit 18 instruction TCM order as per flash programming manual */
612 arm966e_write_cp15(target, 62, 0x40000);
613
614 /* enable flash bank 1 */
615 target_write_u32(target, FLASH_CR, 0x18);
616 return ERROR_OK;
617 }

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)