]> git.sur5r.net Git - openocd/blob - src/flash/nor/core.c
flash: blank check use default_flash_blank_check
[openocd] / src / flash / nor / core.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de>              *
3  *   Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com>       *
4  *   Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk>           *
5  *   Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net>             *
6  *   Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com>       *
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
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include <flash/common.h>
28 #include <flash/nor/core.h>
29 #include <flash/nor/imp.h>
30 #include <target/image.h>
31
32 /**
33  * @file
34  * Upper level of NOR flash framework.
35  * The lower level interfaces are to drivers.  These upper level ones
36  * primarily support access from Tcl scripts or from GDB.
37  */
38
39 static struct flash_bank *flash_banks;
40
41 int flash_driver_erase(struct flash_bank *bank, int first, int last)
42 {
43         int retval;
44
45         retval = bank->driver->erase(bank, first, last);
46         if (retval != ERROR_OK)
47                 LOG_ERROR("failed erasing sectors %d to %d", first, last);
48
49         return retval;
50 }
51
52 int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
53 {
54         int retval;
55
56         /* callers may not supply illegal parameters ... */
57         if (first < 0 || first > last || last >= bank->num_sectors) {
58                 LOG_ERROR("illegal sector range");
59                 return ERROR_FAIL;
60         }
61
62         /* force "set" to 0/1 */
63         set = !!set;
64
65         /* DANGER!
66          *
67          * We must not use any cached information about protection state!!!!
68          *
69          * There are a million things that could change the protect state:
70          *
71          * the target could have reset, power cycled, been hot plugged,
72          * the application could have run, etc.
73          *
74          * Drivers only receive valid sector range.
75          */
76         retval = bank->driver->protect(bank, set, first, last);
77         if (retval != ERROR_OK)
78                 LOG_ERROR("failed setting protection for areas %d to %d", first, last);
79
80         return retval;
81 }
82
83 int flash_driver_write(struct flash_bank *bank,
84         uint8_t *buffer, uint32_t offset, uint32_t count)
85 {
86         int retval;
87
88         retval = bank->driver->write(bank, buffer, offset, count);
89         if (retval != ERROR_OK) {
90                 LOG_ERROR(
91                         "error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
92                         bank->base,
93                         offset);
94         }
95
96         return retval;
97 }
98
99 int flash_driver_read(struct flash_bank *bank,
100         uint8_t *buffer, uint32_t offset, uint32_t count)
101 {
102         int retval;
103
104         LOG_DEBUG("call flash_driver_read()");
105
106         retval = bank->driver->read(bank, buffer, offset, count);
107         if (retval != ERROR_OK) {
108                 LOG_ERROR(
109                         "error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
110                         bank->base,
111                         offset);
112         }
113
114         return retval;
115 }
116
117 int default_flash_read(struct flash_bank *bank,
118         uint8_t *buffer, uint32_t offset, uint32_t count)
119 {
120         return target_read_buffer(bank->target, offset + bank->base, count, buffer);
121 }
122
123 void flash_bank_add(struct flash_bank *bank)
124 {
125         /* put flash bank in linked list */
126         unsigned bank_num = 0;
127         if (flash_banks) {
128                 /* find last flash bank */
129                 struct flash_bank *p = flash_banks;
130                 while (NULL != p->next) {
131                         bank_num += 1;
132                         p = p->next;
133                 }
134                 p->next = bank;
135                 bank_num += 1;
136         } else
137                 flash_banks = bank;
138
139         bank->bank_number = bank_num;
140 }
141
142 struct flash_bank *flash_bank_list(void)
143 {
144         return flash_banks;
145 }
146
147 struct flash_bank *get_flash_bank_by_num_noprobe(int num)
148 {
149         struct flash_bank *p;
150         int i = 0;
151
152         for (p = flash_banks; p; p = p->next) {
153                 if (i++ == num)
154                         return p;
155         }
156         LOG_ERROR("flash bank %d does not exist", num);
157         return NULL;
158 }
159
160 int flash_get_bank_count(void)
161 {
162         struct flash_bank *p;
163         int i = 0;
164         for (p = flash_banks; p; p = p->next)
165                 i++;
166         return i;
167 }
168
169 struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
170 {
171         unsigned requested = get_flash_name_index(name);
172         unsigned found = 0;
173
174         struct flash_bank *bank;
175         for (bank = flash_banks; NULL != bank; bank = bank->next) {
176                 if (strcmp(bank->name, name) == 0)
177                         return bank;
178                 if (!flash_driver_name_matches(bank->driver->name, name))
179                         continue;
180                 if (++found < requested)
181                         continue;
182                 return bank;
183         }
184         return NULL;
185 }
186
187 int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result)
188 {
189         struct flash_bank *bank;
190         int retval;
191
192         bank = get_flash_bank_by_name_noprobe(name);
193         if (bank != NULL) {
194                 retval = bank->driver->auto_probe(bank);
195
196                 if (retval != ERROR_OK) {
197                         LOG_ERROR("auto_probe failed");
198                         return retval;
199                 }
200         }
201
202         *bank_result = bank;
203         return ERROR_OK;
204 }
205
206 int get_flash_bank_by_num(int num, struct flash_bank **bank)
207 {
208         struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
209         int retval;
210
211         if (p == NULL)
212                 return ERROR_FAIL;
213
214         retval = p->driver->auto_probe(p);
215
216         if (retval != ERROR_OK) {
217                 LOG_ERROR("auto_probe failed");
218                 return retval;
219         }
220         *bank = p;
221         return ERROR_OK;
222 }
223
224 /* lookup flash bank by address, bank not found is success, but
225  * result_bank is set to NULL. */
226 int get_flash_bank_by_addr(struct target *target,
227         uint32_t addr,
228         bool check,
229         struct flash_bank **result_bank)
230 {
231         struct flash_bank *c;
232
233         /* cycle through bank list */
234         for (c = flash_banks; c; c = c->next) {
235                 int retval;
236                 retval = c->driver->auto_probe(c);
237
238                 if (retval != ERROR_OK) {
239                         LOG_ERROR("auto_probe failed");
240                         return retval;
241                 }
242                 /* check whether address belongs to this flash bank */
243                 if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target) {
244                         *result_bank = c;
245                         return ERROR_OK;
246                 }
247         }
248         *result_bank = NULL;
249         if (check) {
250                 LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
251                 return ERROR_FAIL;
252         }
253         return ERROR_OK;
254 }
255
256 static int default_flash_mem_blank_check(struct flash_bank *bank)
257 {
258         struct target *target = bank->target;
259         const int buffer_size = 1024;
260         int i;
261         uint32_t nBytes;
262         int retval = ERROR_OK;
263
264         if (bank->target->state != TARGET_HALTED) {
265                 LOG_ERROR("Target not halted");
266                 return ERROR_TARGET_NOT_HALTED;
267         }
268
269         uint8_t *buffer = malloc(buffer_size);
270
271         for (i = 0; i < bank->num_sectors; i++) {
272                 uint32_t j;
273                 bank->sectors[i].is_erased = 1;
274
275                 for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
276                         uint32_t chunk;
277                         chunk = buffer_size;
278                         if (chunk > (j - bank->sectors[i].size))
279                                 chunk = (j - bank->sectors[i].size);
280
281                         retval = target_read_memory(target,
282                                         bank->base + bank->sectors[i].offset + j,
283                                         4,
284                                         chunk/4,
285                                         buffer);
286                         if (retval != ERROR_OK)
287                                 goto done;
288
289                         for (nBytes = 0; nBytes < chunk; nBytes++) {
290                                 if (buffer[nBytes] != 0xFF) {
291                                         bank->sectors[i].is_erased = 0;
292                                         break;
293                                 }
294                         }
295                 }
296         }
297
298 done:
299         free(buffer);
300
301         return retval;
302 }
303
304 int default_flash_blank_check(struct flash_bank *bank)
305 {
306         struct target *target = bank->target;
307         int i;
308         int retval;
309         int fast_check = 0;
310         uint32_t blank;
311
312         if (bank->target->state != TARGET_HALTED) {
313                 LOG_ERROR("Target not halted");
314                 return ERROR_TARGET_NOT_HALTED;
315         }
316
317         for (i = 0; i < bank->num_sectors; i++) {
318                 uint32_t address = bank->base + bank->sectors[i].offset;
319                 uint32_t size = bank->sectors[i].size;
320
321                 retval = target_blank_check_memory(target, address, size, &blank);
322                 if (retval != ERROR_OK) {
323                         fast_check = 0;
324                         break;
325                 }
326                 if (blank == 0xFF)
327                         bank->sectors[i].is_erased = 1;
328                 else
329                         bank->sectors[i].is_erased = 0;
330                 fast_check = 1;
331         }
332
333         if (!fast_check) {
334                 LOG_USER("Running slow fallback erase check - add working memory");
335                 return default_flash_mem_blank_check(bank);
336         }
337
338         return ERROR_OK;
339 }
340
341 /* Manipulate given flash region, selecting the bank according to target
342  * and address.  Maps an address range to a set of sectors, and issues
343  * the callback() on that set ... e.g. to erase or unprotect its members.
344  *
345  * (Note a current bad assumption:  that protection operates on the same
346  * size sectors as erase operations use.)
347  *
348  * The "pad_reason" parameter is a kind of boolean:  when it's NULL, the
349  * range must fit those sectors exactly.  This is clearly safe; it can't
350  * erase data which the caller said to leave alone, for example.  If it's
351  * non-NULL, rather than failing, extra data in the first and/or last
352  * sectors will be added to the range, and that reason string is used when
353  * warning about those additions.
354  */
355 static int flash_iterate_address_range_inner(struct target *target,
356         char *pad_reason, uint32_t addr, uint32_t length,
357         int (*callback)(struct flash_bank *bank, int first, int last))
358 {
359         struct flash_bank *c;
360         uint32_t last_addr = addr + length;     /* first address AFTER end */
361         int first = -1;
362         int last = -1;
363         int i;
364
365         int retval = get_flash_bank_by_addr(target, addr, true, &c);
366         if (retval != ERROR_OK)
367                 return retval;
368
369         if (c->size == 0 || c->num_sectors == 0) {
370                 LOG_ERROR("Bank is invalid");
371                 return ERROR_FLASH_BANK_INVALID;
372         }
373
374         if (length == 0) {
375                 /* special case, erase whole bank when length is zero */
376                 if (addr != c->base) {
377                         LOG_ERROR("Whole bank access must start at beginning of bank.");
378                         return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
379                 }
380
381                 return callback(c, 0, c->num_sectors - 1);
382         }
383
384         /* check whether it all fits in this bank */
385         if (addr + length - 1 > c->base + c->size - 1) {
386                 LOG_ERROR("Flash access does not fit into bank.");
387                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
388         }
389
390         /** @todo: handle erasures that cross into adjacent banks */
391
392         addr -= c->base;
393         last_addr -= c->base;
394
395         for (i = 0; i < c->num_sectors; i++) {
396                 struct flash_sector *f = c->sectors + i;
397                 uint32_t end = f->offset + f->size;
398
399                 /* start only on a sector boundary */
400                 if (first < 0) {
401                         /* scanned past the first sector? */
402                         if (addr < f->offset)
403                                 break;
404
405                         /* is this the first sector? */
406                         if (addr == f->offset)
407                                 first = i;
408
409                         /* Does this need head-padding?  If so, pad and warn;
410                          * or else force an error.
411                          *
412                          * Such padding can make trouble, since *WE* can't
413                          * ever know if that data was in use.  The warning
414                          * should help users sort out messes later.
415                          */
416                         else if (addr < end && pad_reason) {
417                                 /* FIXME say how many bytes (e.g. 80 KB) */
418                                 LOG_WARNING("Adding extra %s range, "
419                                         "%#8.8x to %#8.8x",
420                                         pad_reason,
421                                         (unsigned) f->offset,
422                                         (unsigned) addr - 1);
423                                 first = i;
424                         } else
425                                 continue;
426                 }
427
428                 /* is this (also?) the last sector? */
429                 if (last_addr == end) {
430                         last = i;
431                         break;
432                 }
433
434                 /* Does this need tail-padding?  If so, pad and warn;
435                  * or else force an error.
436                  */
437                 if (last_addr < end && pad_reason) {
438                         /* FIXME say how many bytes (e.g. 80 KB) */
439                         LOG_WARNING("Adding extra %s range, "
440                                 "%#8.8x to %#8.8x",
441                                 pad_reason,
442                                 (unsigned) last_addr,
443                                 (unsigned) end - 1);
444                         last = i;
445                         break;
446                 }
447
448                 /* MUST finish on a sector boundary */
449                 if (last_addr <= f->offset)
450                         break;
451         }
452
453         /* invalid start or end address? */
454         if (first == -1 || last == -1) {
455                 LOG_ERROR("address range 0x%8.8x .. 0x%8.8x "
456                         "is not sector-aligned",
457                         (unsigned) (c->base + addr),
458                         (unsigned) (c->base + last_addr - 1));
459                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
460         }
461
462         /* The NOR driver may trim this range down, based on what
463          * sectors are already erased/unprotected.  GDB currently
464          * blocks such optimizations.
465          */
466         return callback(c, first, last);
467 }
468
469 /* The inner fn only handles a single bank, we could be spanning
470  * multiple chips.
471  */
472 static int flash_iterate_address_range(struct target *target,
473         char *pad_reason, uint32_t addr, uint32_t length,
474         int (*callback)(struct flash_bank *bank, int first, int last))
475 {
476         struct flash_bank *c;
477         int retval = ERROR_OK;
478
479         /* Danger! zero-length iterations means entire bank! */
480         do {
481                 retval = get_flash_bank_by_addr(target, addr, true, &c);
482                 if (retval != ERROR_OK)
483                         return retval;
484
485                 uint32_t cur_length = length;
486                 /* check whether it all fits in this bank */
487                 if (addr + length - 1 > c->base + c->size - 1) {
488                         LOG_DEBUG("iterating over more than one flash bank.");
489                         cur_length = c->base + c->size - addr;
490                 }
491                 retval = flash_iterate_address_range_inner(target,
492                                 pad_reason, addr, cur_length,
493                                 callback);
494                 if (retval != ERROR_OK)
495                         break;
496
497                 length -= cur_length;
498                 addr += cur_length;
499         } while (length > 0);
500
501         return retval;
502 }
503
504 int flash_erase_address_range(struct target *target,
505         bool pad, uint32_t addr, uint32_t length)
506 {
507         return flash_iterate_address_range(target, pad ? "erase" : NULL,
508                 addr, length, &flash_driver_erase);
509 }
510
511 static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
512 {
513         return flash_driver_protect(bank, 0, first, last);
514 }
515
516 int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
517 {
518         /* By default, pad to sector boundaries ... the real issue here
519          * is that our (only) caller *permanently* removes protection,
520          * and doesn't restore it.
521          */
522         return flash_iterate_address_range(target, "unprotect",
523                 addr, length, &flash_driver_unprotect);
524 }
525
526 static int compare_section(const void *a, const void *b)
527 {
528         struct imagesection *b1, *b2;
529         b1 = *((struct imagesection **)a);
530         b2 = *((struct imagesection **)b);
531
532         if (b1->base_address == b2->base_address)
533                 return 0;
534         else if (b1->base_address > b2->base_address)
535                 return 1;
536         else
537                 return -1;
538 }
539
540 int flash_write_unlock(struct target *target, struct image *image,
541         uint32_t *written, int erase, bool unlock)
542 {
543         int retval = ERROR_OK;
544
545         int section;
546         uint32_t section_offset;
547         struct flash_bank *c;
548         int *padding;
549
550         section = 0;
551         section_offset = 0;
552
553         if (written)
554                 *written = 0;
555
556         if (erase) {
557                 /* assume all sectors need erasing - stops any problems
558                  * when flash_write is called multiple times */
559
560                 flash_set_dirty();
561         }
562
563         /* allocate padding array */
564         padding = calloc(image->num_sections, sizeof(*padding));
565
566         /* This fn requires all sections to be in ascending order of addresses,
567          * whereas an image can have sections out of order. */
568         struct imagesection **sections = malloc(sizeof(struct imagesection *) *
569                         image->num_sections);
570         int i;
571         for (i = 0; i < image->num_sections; i++)
572                 sections[i] = &image->sections[i];
573
574         qsort(sections, image->num_sections, sizeof(struct imagesection *),
575                 compare_section);
576
577         /* loop until we reach end of the image */
578         while (section < image->num_sections) {
579                 uint32_t buffer_size;
580                 uint8_t *buffer;
581                 int section_last;
582                 uint32_t run_address = sections[section]->base_address + section_offset;
583                 uint32_t run_size = sections[section]->size - section_offset;
584                 int pad_bytes = 0;
585
586                 if (sections[section]->size ==  0) {
587                         LOG_WARNING("empty section %d", section);
588                         section++;
589                         section_offset = 0;
590                         continue;
591                 }
592
593                 /* find the corresponding flash bank */
594                 retval = get_flash_bank_by_addr(target, run_address, false, &c);
595                 if (retval != ERROR_OK)
596                         goto done;
597                 if (c == NULL) {
598                         LOG_WARNING("no flash bank found for address %x", run_address);
599                         section++;      /* and skip it */
600                         section_offset = 0;
601                         continue;
602                 }
603
604                 /* collect consecutive sections which fall into the same bank */
605                 section_last = section;
606                 padding[section] = 0;
607                 while ((run_address + run_size - 1 < c->base + c->size - 1) &&
608                                 (section_last + 1 < image->num_sections)) {
609                         /* sections are sorted */
610                         assert(sections[section_last + 1]->base_address >= c->base);
611                         if (sections[section_last + 1]->base_address >= (c->base + c->size)) {
612                                 /* Done with this bank */
613                                 break;
614                         }
615
616                         /* FIXME This needlessly touches sectors BETWEEN the
617                          * sections it's writing.  Without auto erase, it just
618                          * writes ones.  That WILL INVALIDATE data in cases
619                          * like Stellaris Tempest chips, corrupting internal
620                          * ECC codes; and at least FreeScale suggests issues
621                          * with that approach (in HC11 documentation).
622                          *
623                          * With auto erase enabled, data in those sectors will
624                          * be needlessly destroyed; and some of the limited
625                          * number of flash erase cycles will be wasted...
626                          *
627                          * In both cases, the extra writes slow things down.
628                          */
629
630                         /* if we have multiple sections within our image,
631                          * flash programming could fail due to alignment issues
632                          * attempt to rebuild a consecutive buffer for the flash loader */
633                         pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size);
634                         padding[section_last] = pad_bytes;
635                         run_size += sections[++section_last]->size;
636                         run_size += pad_bytes;
637
638                         if (pad_bytes > 0)
639                                 LOG_INFO("Padding image section %d with %d bytes",
640                                         section_last-1,
641                                         pad_bytes);
642                 }
643
644                 if (run_address + run_size - 1 > c->base + c->size - 1) {
645                         /* If we have more than one flash chip back to back, then we limit
646                          * the current write operation to the current chip.
647                          */
648                         LOG_DEBUG("Truncate flash run size to the current flash chip.");
649
650                         run_size = c->base + c->size - run_address;
651                         assert(run_size > 0);
652                 }
653
654                 /* If we're applying any sector automagic, then pad this
655                  * (maybe-combined) segment to the end of its last sector.
656                  */
657                 if (unlock || erase) {
658                         int sector;
659                         uint32_t offset_start = run_address - c->base;
660                         uint32_t offset_end = offset_start + run_size;
661                         uint32_t end = offset_end, delta;
662
663                         for (sector = 0; sector < c->num_sectors; sector++) {
664                                 end = c->sectors[sector].offset
665                                         + c->sectors[sector].size;
666                                 if (offset_end <= end)
667                                         break;
668                         }
669
670                         delta = end - offset_end;
671                         padding[section_last] += delta;
672                         run_size += delta;
673                 }
674
675                 /* allocate buffer */
676                 buffer = malloc(run_size);
677                 if (buffer == NULL) {
678                         LOG_ERROR("Out of memory for flash bank buffer");
679                         retval = ERROR_FAIL;
680                         goto done;
681                 }
682                 buffer_size = 0;
683
684                 /* read sections to the buffer */
685                 while (buffer_size < run_size) {
686                         size_t size_read;
687
688                         size_read = run_size - buffer_size;
689                         if (size_read > sections[section]->size - section_offset)
690                                 size_read = sections[section]->size - section_offset;
691
692                         /* KLUDGE!
693                          *
694                          * #¤%#"%¤% we have to figure out the section # from the sorted
695                          * list of pointers to sections to invoke image_read_section()...
696                          */
697                         intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
698                         int t_section_num = diff / sizeof(struct imagesection);
699
700                         LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, "
701                                         "section_offset = %d, buffer_size = %d, size_read = %d",
702                                 (int)section, (int)t_section_num, (int)section_offset,
703                                 (int)buffer_size, (int)size_read);
704                         retval = image_read_section(image, t_section_num, section_offset,
705                                         size_read, buffer + buffer_size, &size_read);
706                         if (retval != ERROR_OK || size_read == 0) {
707                                 free(buffer);
708                                 goto done;
709                         }
710
711                         /* see if we need to pad the section */
712                         while (padding[section]--)
713                                 (buffer + buffer_size)[size_read++] = 0xff;
714
715                         buffer_size += size_read;
716                         section_offset += size_read;
717
718                         if (section_offset >= sections[section]->size) {
719                                 section++;
720                                 section_offset = 0;
721                         }
722                 }
723
724                 retval = ERROR_OK;
725
726                 if (unlock)
727                         retval = flash_unlock_address_range(target, run_address, run_size);
728                 if (retval == ERROR_OK) {
729                         if (erase) {
730                                 /* calculate and erase sectors */
731                                 retval = flash_erase_address_range(target,
732                                                 true, run_address, run_size);
733                         }
734                 }
735
736                 if (retval == ERROR_OK) {
737                         /* write flash sectors */
738                         retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
739                 }
740
741                 free(buffer);
742
743                 if (retval != ERROR_OK) {
744                         /* abort operation */
745                         goto done;
746                 }
747
748                 if (written != NULL)
749                         *written += run_size;   /* add run size to total written counter */
750         }
751
752 done:
753         free(sections);
754         free(padding);
755
756         return retval;
757 }
758
759 int flash_write(struct target *target, struct image *image,
760         uint32_t *written, int erase)
761 {
762         return flash_write_unlock(target, image, written, erase, false);
763 }