- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# flashcdw.c

Go to the documentation of this file.

    00001 /*This file is prepared for Doxygen automatic documentation generation.*/
    00017 /* Copyright (c) 2009 Atmel Corporation. All rights reserved.
    00018  *
    00019  * Redistribution and use in source and binary forms, with or without
    00020  * modification, are permitted provided that the following conditions are met:
    00021  *
    00022  * 1. Redistributions of source code must retain the above copyright notice, this
    00023  * list of conditions and the following disclaimer.
    00024  *
    00025  * 2. Redistributions in binary form must reproduce the above copyright notice,
    00026  * this list of conditions and the following disclaimer in the documentation
    00027  * and/or other materials provided with the distribution.
    00028  *
    00029  * 3. The name of Atmel may not be used to endorse or promote products derived
    00030  * from this software without specific prior written permission.
    00031  *
    00032  * 4. This software may only be redistributed and used in connection with an Atmel
    00033  * AVR product.
    00034  *
    00035  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
    00036  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00037  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
    00038  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
    00039  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    00040  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    00041  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    00042  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00043  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00044  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
    00045  *
    00046  */
    00047
    00048 #include <avr32/io.h>
    00049 #include <stddef.h>
    00050 #include "compiler.h"
    00051 #include "flashcdw.h"
    00052
    00053
    00056
    00057
    00058 typedef union
    00059 {
    00060   unsigned long                   fcr;
    00061   avr32_flashcdw_fcr_t            FCR;
    00062 } u_avr32_flashcdw_fcr_t;
    00063
    00064 typedef union
    00065 {
    00066   unsigned long                   fcmd;
    00067   avr32_flashcdw_fcmd_t           FCMD;
    00068 } u_avr32_flashcdw_fcmd_t;
    00069
    00071
    00072
    00075
    00076
    00077
    00078 unsigned int flashcdw_get_flash_size(void)
    00079 {
    00080   static const unsigned int FLASH_SIZE[1 << AVR32_FLASHCDW_FPR_FSZ_SIZE] =
    00081   {
    00082       4 << 10,
    00083       8 << 10,
    00084       16 << 10,
    00085       32 << 10,
    00086       48 << 10,
    00087       64 << 10,
    00088       96 << 10,
    00089      128 << 10,
    00090      192 << 10,
    00091      256 << 10,
    00092      384 << 10,
    00093      512 << 10,
    00094      768 << 10,
    00095     1024 << 10,
    00096     2048 << 10
    00097   };
    00098   return FLASH_SIZE[(AVR32_FLASHCDW.fpr & AVR32_FLASHCDW_FPR_FSZ_MASK) >> AVR32_FLASHCDW_FPR_FSZ_OFFSET];
    00099 }
    00100
    00101
    00102 unsigned int flashcdw_get_page_count(void)
    00103 {
    00104   return flashcdw_get_flash_size() / AVR32_FLASHCDW_PAGE_SIZE;
    00105 }
    00106
    00107
    00108 unsigned int flashcdw_get_page_count_per_region(void)
    00109 {
    00110   return flashcdw_get_page_count() / AVR32_FLASHCDW_REGIONS;
    00111 }
    00112
    00113
    00114 unsigned int flashcdw_get_page_region(int page_number)
    00115 {
    00116   return ((page_number >= 0) ? page_number : flashcdw_get_page_number()) / flashcdw_get_page_count_per_region();
    00117 }
    00118
    00119
    00120 unsigned int flashcdw_get_region_first_page_number(unsigned int region)
    00121 {
    00122   return region * flashcdw_get_page_count_per_region();
    00123 }
    00124
    00125
    00127
    00128
    00131
    00132
    00133
    00134 unsigned int flashcdw_get_wait_state(void)
    00135 {
    00136   return (AVR32_FLASHCDW.fcr & AVR32_FLASHCDW_FCR_FWS_MASK) >> AVR32_FLASHCDW_FCR_FWS_OFFSET;
    00137 }
    00138
    00139
    00140 void flashcdw_set_wait_state(unsigned int wait_state)
    00141 {
    00142   u_avr32_flashcdw_fcr_t u_avr32_flashcdw_fcr = {AVR32_FLASHCDW.fcr};
    00143   u_avr32_flashcdw_fcr.FCR.fws = wait_state;
    00144   AVR32_FLASHCDW.fcr = u_avr32_flashcdw_fcr.fcr;
    00145 }
    00146
    00147
    00148 void flashcdw_set_flash_waitstate_and_readmode(unsigned long cpu_f_hz)
    00149 {
    00150   if(cpu_f_hz > AVR32_FLASHCDW_FWS_0_MAX_FREQ)    // > 15MHz
    00151   {
    00152     if(cpu_f_hz <= AVR32_FLASHCDW_FWS_1_MAX_FREQ) // <= 30MHz
    00153     {
    00154       // Set a wait-state, disable the high-speed read mode.
    00155       flashcdw_set_wait_state(1);
    00156       flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_HSDIS, -1);
    00157     }
    00158     else
    00159     {
    00160       // Set a wait-state, enable the high-speed read mode.
    00161       flashcdw_set_wait_state(1);
    00162       flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_HSEN, -1);
    00163     }
    00164   }
    00165   else  // <= 15MHz
    00166   {
    00167     // No wait-state, disable the high-speed read mode
    00168     flashcdw_set_wait_state(0);
    00169     flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_HSDIS, -1);
    00170   }
    00171 }
    00172
    00173
    00174 Bool flashcdw_is_ready_int_enabled(void)
    00175 {
    00176   return ((AVR32_FLASHCDW.fcr & AVR32_FLASHCDW_FCR_FRDY_MASK) != 0);
    00177 }
    00178
    00179
    00180 void flashcdw_enable_ready_int(Bool enable)
    00181 {
    00182   u_avr32_flashcdw_fcr_t u_avr32_flashcdw_fcr = {AVR32_FLASHCDW.fcr};
    00183   u_avr32_flashcdw_fcr.FCR.frdy = (enable != FALSE);
    00184   AVR32_FLASHCDW.fcr = u_avr32_flashcdw_fcr.fcr;
    00185 }
    00186
    00187
    00188 Bool flashcdw_is_lock_error_int_enabled(void)
    00189 {
    00190   return ((AVR32_FLASHCDW.fcr & AVR32_FLASHCDW_FCR_LOCKE_MASK) != 0);
    00191 }
    00192
    00193
    00194 void flashcdw_enable_lock_error_int(Bool enable)
    00195 {
    00196   u_avr32_flashcdw_fcr_t u_avr32_flashcdw_fcr = {AVR32_FLASHCDW.fcr};
    00197   u_avr32_flashcdw_fcr.FCR.locke = (enable != FALSE);
    00198   AVR32_FLASHCDW.fcr = u_avr32_flashcdw_fcr.fcr;
    00199 }
    00200
    00201
    00202 Bool flashcdw_is_prog_error_int_enabled(void)
    00203 {
    00204   return ((AVR32_FLASHCDW.fcr & AVR32_FLASHCDW_FCR_PROGE_MASK) != 0);
    00205 }
    00206
    00207
    00208 void flashcdw_enable_prog_error_int(Bool enable)
    00209 {
    00210   u_avr32_flashcdw_fcr_t u_avr32_flashcdw_fcr = {AVR32_FLASHCDW.fcr};
    00211   u_avr32_flashcdw_fcr.FCR.proge = (enable != FALSE);
    00212   AVR32_FLASHCDW.fcr = u_avr32_flashcdw_fcr.fcr;
    00213 }
    00214
    00215
    00217
    00218
    00221
    00222
    00223
    00224 Bool flashcdw_is_ready(void)
    00225 {
    00226   return ((AVR32_FLASHCDW.fsr & AVR32_FLASHCDW_FSR_FRDY_MASK) != 0);
    00227 }
    00228
    00229
    00230 void flashcdw_default_wait_until_ready(void)
    00231 {
    00232   while (!flashcdw_is_ready());
    00233 }
    00234
    00235
    00236 void (*volatile flashcdw_wait_until_ready)(void) = flashcdw_default_wait_until_ready;
    00237
    00238
    00249 static unsigned int flashcdw_get_error_status(void)
    00250 {
    00251   return AVR32_FLASHCDW.fsr & (AVR32_FLASHCDW_FSR_LOCKE_MASK |
    00252                              AVR32_FLASHCDW_FSR_PROGE_MASK);
    00253 }
    00254
    00255
    00260 static unsigned int flashcdw_error_status = 0;
    00261
    00262
    00263 Bool flashcdw_is_lock_error(void)
    00264 {
    00265   return ((flashcdw_error_status & AVR32_FLASHCDW_FSR_LOCKE_MASK) != 0);
    00266 }
    00267
    00268
    00269 Bool flashcdw_is_programming_error(void)
    00270 {
    00271   return ((flashcdw_error_status & AVR32_FLASHCDW_FSR_PROGE_MASK) != 0);
    00272 }
    00273
    00274
    00275 Bool flashcdw_is_high_speed_enabled(void)
    00276 {
    00277   return ((AVR32_FLASHCDW.fsr & AVR32_FLASHCDW_FSR_HSMODE_MASK) != 0);
    00278 }
    00279
    00280
    00282
    00283
    00286
    00287
    00288
    00289 unsigned int flashcdw_get_command(void)
    00290 {
    00291   return (AVR32_FLASHCDW.fcmd & AVR32_FLASHCDW_FCMD_CMD_MASK) >> AVR32_FLASHCDW_FCMD_CMD_OFFSET;
    00292 }
    00293
    00294
    00295 unsigned int flashcdw_get_page_number(void)
    00296 {
    00297   return (AVR32_FLASHCDW.fcmd & AVR32_FLASHCDW_FCMD_PAGEN_MASK) >> AVR32_FLASHCDW_FCMD_PAGEN_OFFSET;
    00298 }
    00299
    00300
    00301 void flashcdw_issue_command(unsigned int command, int page_number)
    00302 {
    00303   u_avr32_flashcdw_fcmd_t u_avr32_flashcdw_fcmd;
    00304   flashcdw_wait_until_ready();
    00305   u_avr32_flashcdw_fcmd.fcmd = AVR32_FLASHCDW.fcmd;
    00306   u_avr32_flashcdw_fcmd.FCMD.cmd = command;
    00307   if (page_number >= 0) u_avr32_flashcdw_fcmd.FCMD.pagen = page_number;
    00308   u_avr32_flashcdw_fcmd.FCMD.key = AVR32_FLASHCDW_FCMD_KEY_KEY;
    00309   AVR32_FLASHCDW.fcmd = u_avr32_flashcdw_fcmd.fcmd;
    00310   flashcdw_error_status = flashcdw_get_error_status();
    00311   flashcdw_wait_until_ready();
    00312 }
    00313
    00314
    00316
    00317
    00320
    00321
    00322
    00323 void flashcdw_no_operation(void)
    00324 {
    00325   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_NOP, -1);
    00326 }
    00327
    00328
    00329 void flashcdw_erase_all(void)
    00330 {
    00331   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_EA, -1);
    00332 }
    00333
    00334
    00336
    00337
    00340
    00341
    00342
    00343 Bool flashcdw_is_security_bit_active(void)
    00344 {
    00345   return ((AVR32_FLASHCDW.fsr & AVR32_FLASHCDW_FSR_SECURITY_MASK) != 0);
    00346 }
    00347
    00348
    00349 void flashcdw_activate_security_bit(void)
    00350 {
    00351   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_SSB, -1);
    00352 }
    00353
    00354
    00355 unsigned int flashcdw_get_bootloader_protected_size(void)
    00356 {
    00357   unsigned int bootprot = (1 << AVR32_FLASHCDW_FGPFRLO_BOOTPROT_SIZE) - 1 -
    00358                           flashcdw_read_gp_fuse_bitfield(AVR32_FLASHCDW_FGPFRLO_BOOTPROT_OFFSET,
    00359                                                        AVR32_FLASHCDW_FGPFRLO_BOOTPROT_SIZE);
    00360   return (bootprot) ? AVR32_FLASHCDW_PAGE_SIZE << bootprot : 0;
    00361 }
    00362
    00363
    00364 unsigned int flashcdw_set_bootloader_protected_size(unsigned int bootprot_size)
    00365 {
    00366   flashcdw_set_gp_fuse_bitfield(AVR32_FLASHCDW_FGPFRLO_BOOTPROT_OFFSET,
    00367                               AVR32_FLASHCDW_FGPFRLO_BOOTPROT_SIZE,
    00368                               (1 << AVR32_FLASHCDW_FGPFRLO_BOOTPROT_SIZE) - 1 -
    00369                               ((bootprot_size) ?
    00370                                32 - clz((((min(max(bootprot_size, AVR32_FLASHCDW_PAGE_SIZE << 1),
    00371                                                AVR32_FLASHCDW_PAGE_SIZE <<
    00372                                                ((1 << AVR32_FLASHCDW_FGPFRLO_BOOTPROT_SIZE) - 1)) +
    00373                                            AVR32_FLASHCDW_PAGE_SIZE - 1) /
    00374                                           AVR32_FLASHCDW_PAGE_SIZE) << 1) - 1) - 1 :
    00375                                0));
    00376   return flashcdw_get_bootloader_protected_size();
    00377 }
    00378
    00379
    00380 Bool flashcdw_is_external_privileged_fetch_locked(void)
    00381 {
    00382   return (!flashcdw_read_gp_fuse_bit(AVR32_FLASHCDW_FGPFRLO_EPFL_OFFSET));
    00383 }
    00384
    00385
    00386 void flashcdw_lock_external_privileged_fetch(Bool lock)
    00387 {
    00388   flashcdw_set_gp_fuse_bit(AVR32_FLASHCDW_FGPFRLO_EPFL_OFFSET, !lock);
    00389 }
    00390
    00391 Bool flashcdw_is_jtag_user_protection_enabled(void)
    00392 {
    00393   return (!flashcdw_read_gp_fuse_bit(AVR32_FLASHCDW_FGPFRLO_UPROT_OFFSET));
    00394 }
    00395
    00396 void flashcdw_enable_jtag_user_protection(void)
    00397 {
    00398   flashcdw_set_gp_fuse_bit(AVR32_FLASHCDW_FGPFRLO_UPROT_OFFSET, FALSE);
    00399 }
    00400
    00401 void flashcdw_disable_jtag_user_protection(void)
    00402 {
    00403   flashcdw_set_gp_fuse_bit(AVR32_FLASHCDW_FGPFRLO_UPROT_OFFSET, TRUE);
    00404 }
    00405
    00406 Bool flashcdw_is_secure_state_enabled(void)
    00407 {
    00408   U64 temp = flashcdw_read_gp_fuse_bitfield(AVR32_FLASHCDW_FGPFRLO_SECURE_OFFSET,
    00409                                             AVR32_FLASHCDW_FGPFRLO_SECURE_SIZE);
    00410   if((AVR32_FLASHCDW_FGPFRLO_SECURE_SSEN_SSDDIS == temp) || (AVR32_FLASHCDW_FGPFRLO_SECURE_SSEN_SSDEN == temp))
    00411     return TRUE;
    00412   else
    00413     return FALSE;
    00414 }
    00415
    00416 Bool flashcdw_is_secure_state_debug_enabled(void)
    00417 {
    00418   return( AVR32_FLASHCDW_FGPFRLO_SECURE_SSEN_SSDEN
    00419           == flashcdw_read_gp_fuse_bitfield(AVR32_FLASHCDW_FGPFRLO_SECURE_OFFSET,
    00420                                             AVR32_FLASHCDW_FGPFRLO_SECURE_SIZE) );
    00421 }
    00422
    00423 void flashcdw_enable_secure_state_no_debug(void)
    00424 {
    00425   flashcdw_write_gp_fuse_bitfield(AVR32_FLASHCDW_FGPFRLO_SECURE_OFFSET,
    00426                                   AVR32_FLASHCDW_FGPFRLO_SECURE_SIZE,
    00427                                   AVR32_FLASHCDW_FGPFRLO_SECURE_SSEN_SSDDIS);
    00428 }
    00429
    00430 void flashcdw_enable_secure_state_with_debug(void)
    00431 {
    00432   flashcdw_write_gp_fuse_bitfield(AVR32_FLASHCDW_FGPFRLO_SECURE_OFFSET,
    00433                                   AVR32_FLASHCDW_FGPFRLO_SECURE_SIZE,
    00434                                   AVR32_FLASHCDW_FGPFRLO_SECURE_SSEN_SSDEN);
    00435 }
    00436
    00437 Bool flashcdw_is_page_region_locked(int page_number)
    00438 {
    00439   return flashcdw_is_region_locked(flashcdw_get_page_region(page_number));
    00440 }
    00441
    00442
    00443 Bool flashcdw_is_region_locked(unsigned int region)
    00444 {
    00445   return ((AVR32_FLASHCDW.fsr & AVR32_FLASHCDW_FSR_LOCK0_MASK << (region & (AVR32_FLASHCDW_REGIONS - 1))) != 0);
    00446 }
    00447
    00448
    00449 void flashcdw_lock_page_region(int page_number, Bool lock)
    00450 {
    00451   flashcdw_issue_command((lock) ? AVR32_FLASHCDW_FCMD_CMD_LP : AVR32_FLASHCDW_FCMD_CMD_UP, page_number);
    00452 }
    00453
    00454
    00455 void flashcdw_lock_region(unsigned int region, Bool lock)
    00456 {
    00457   flashcdw_lock_page_region(flashcdw_get_region_first_page_number(region), lock);
    00458 }
    00459
    00460
    00461 void flashcdw_lock_all_regions(Bool lock)
    00462 {
    00463   unsigned int error_status = 0;
    00464   unsigned int region = AVR32_FLASHCDW_REGIONS;
    00465   while (region)
    00466   {
    00467     flashcdw_lock_region(--region, lock);
    00468     error_status |= flashcdw_error_status;
    00469   }
    00470   flashcdw_error_status = error_status;
    00471 }
    00472
    00473
    00475
    00476
    00479
    00480
    00481
    00482 Bool flashcdw_read_gp_fuse_bit(unsigned int gp_fuse_bit)
    00483 {
    00484   return ((flashcdw_read_all_gp_fuses() & 1ULL << (gp_fuse_bit & 0x3F)) != 0);
    00485 }
    00486
    00487
    00488 U64 flashcdw_read_gp_fuse_bitfield(unsigned int pos, unsigned int width)
    00489 {
    00490   return flashcdw_read_all_gp_fuses() >> (pos & 0x3F) & ((1ULL << min(width, 64)) - 1);
    00491 }
    00492
    00493
    00494 U8 flashcdw_read_gp_fuse_byte(unsigned int gp_fuse_byte)
    00495 {
    00496   return flashcdw_read_all_gp_fuses() >> ((gp_fuse_byte & 0x07) << 3);
    00497 }
    00498
    00499
    00500 U64 flashcdw_read_all_gp_fuses(void)
    00501 {
    00502   return AVR32_FLASHCDW.fgpfrlo | (U64)AVR32_FLASHCDW.fgpfrhi << 32;
    00503 }
    00504
    00505
    00506 Bool flashcdw_erase_gp_fuse_bit(unsigned int gp_fuse_bit, Bool check)
    00507 {
    00508   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_EGPB, gp_fuse_bit & 0x3F);
    00509   return (check) ? flashcdw_read_gp_fuse_bit(gp_fuse_bit) : TRUE;
    00510 }
    00511
    00512
    00513 Bool flashcdw_erase_gp_fuse_bitfield(unsigned int pos, unsigned int width, Bool check)
    00514 {
    00515   unsigned int error_status = 0;
    00516   unsigned int gp_fuse_bit;
    00517   pos &= 0x3F;
    00518   width = min(width, 64);
    00519   for (gp_fuse_bit = pos; gp_fuse_bit < pos + width; gp_fuse_bit++)
    00520   {
    00521     flashcdw_erase_gp_fuse_bit(gp_fuse_bit, FALSE);
    00522     error_status |= flashcdw_error_status;
    00523   }
    00524   flashcdw_error_status = error_status;
    00525   return (check) ? (flashcdw_read_gp_fuse_bitfield(pos, width) == (1ULL << width) - 1) : TRUE;
    00526 }
    00527
    00528
    00529 Bool flashcdw_erase_gp_fuse_byte(unsigned int gp_fuse_byte, Bool check)
    00530 {
    00531   unsigned int error_status;
    00532   unsigned int current_gp_fuse_byte;
    00533   U64 value = flashcdw_read_all_gp_fuses();
    00534   flashcdw_erase_all_gp_fuses(FALSE);
    00535   error_status = flashcdw_error_status;
    00536   for (current_gp_fuse_byte = 0; current_gp_fuse_byte < 8; current_gp_fuse_byte++, value >>= 8)
    00537   {
    00538     if (current_gp_fuse_byte != gp_fuse_byte)
    00539     {
    00540       flashcdw_write_gp_fuse_byte(current_gp_fuse_byte, value);
    00541       error_status |= flashcdw_error_status;
    00542     }
    00543   }
    00544   flashcdw_error_status = error_status;
    00545   return (check) ? (flashcdw_read_gp_fuse_byte(gp_fuse_byte) == 0xFF) : TRUE;
    00546 }
    00547
    00548
    00549 Bool flashcdw_erase_all_gp_fuses(Bool check)
    00550 {
    00551   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_EAGPF, -1);
    00552   return (check) ? (flashcdw_read_all_gp_fuses() == 0xFFFFFFFFFFFFFFFFULL) : TRUE;
    00553 }
    00554
    00555
    00556 void flashcdw_write_gp_fuse_bit(unsigned int gp_fuse_bit, Bool value)
    00557 {
    00558   if (!value)
    00559     flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_WGPB, gp_fuse_bit & 0x3F);
    00560 }
    00561
    00562
    00563 void flashcdw_write_gp_fuse_bitfield(unsigned int pos, unsigned int width, U64 value)
    00564 {
    00565   unsigned int error_status = 0;
    00566   unsigned int gp_fuse_bit;
    00567   pos &= 0x3F;
    00568   width = min(width, 64);
    00569   for (gp_fuse_bit = pos; gp_fuse_bit < pos + width; gp_fuse_bit++, value >>= 1)
    00570   {
    00571     flashcdw_write_gp_fuse_bit(gp_fuse_bit, value & 0x01);
    00572     error_status |= flashcdw_error_status;
    00573   }
    00574   flashcdw_error_status = error_status;
    00575 }
    00576
    00577
    00578 void flashcdw_write_gp_fuse_byte(unsigned int gp_fuse_byte, U8 value)
    00579 {
    00580   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_PGPFB, (gp_fuse_byte & 0x07) | value << 3);
    00581 }
    00582
    00583
    00584 void flashcdw_write_all_gp_fuses(U64 value)
    00585 {
    00586   unsigned int error_status = 0;
    00587   unsigned int gp_fuse_byte;
    00588   for (gp_fuse_byte = 0; gp_fuse_byte < 8; gp_fuse_byte++, value >>= 8)
    00589   {
    00590     flashcdw_write_gp_fuse_byte(gp_fuse_byte, value);
    00591     error_status |= flashcdw_error_status;
    00592   }
    00593   flashcdw_error_status = error_status;
    00594 }
    00595
    00596
    00597 void flashcdw_set_gp_fuse_bit(unsigned int gp_fuse_bit, Bool value)
    00598 {
    00599   if (value)
    00600     flashcdw_erase_gp_fuse_bit(gp_fuse_bit, FALSE);
    00601   else
    00602     flashcdw_write_gp_fuse_bit(gp_fuse_bit, FALSE);
    00603 }
    00604
    00605
    00606 void flashcdw_set_gp_fuse_bitfield(unsigned int pos, unsigned int width, U64 value)
    00607 {
    00608   unsigned int error_status = 0;
    00609   unsigned int gp_fuse_bit;
    00610   pos &= 0x3F;
    00611   width = min(width, 64);
    00612   for (gp_fuse_bit = pos; gp_fuse_bit < pos + width; gp_fuse_bit++, value >>= 1)
    00613   {
    00614     flashcdw_set_gp_fuse_bit(gp_fuse_bit, value & 0x01);
    00615     error_status |= flashcdw_error_status;
    00616   }
    00617   flashcdw_error_status = error_status;
    00618 }
    00619
    00620
    00621 void flashcdw_set_gp_fuse_byte(unsigned int gp_fuse_byte, U8 value)
    00622 {
    00623   unsigned int error_status;
    00624   switch (value)
    00625   {
    00626   case 0xFF:
    00627     flashcdw_erase_gp_fuse_byte(gp_fuse_byte, FALSE);
    00628     break;
    00629   case 0x00:
    00630     flashcdw_write_gp_fuse_byte(gp_fuse_byte, 0x00);
    00631     break;
    00632   default:
    00633     flashcdw_erase_gp_fuse_byte(gp_fuse_byte, FALSE);
    00634     error_status = flashcdw_error_status;
    00635     flashcdw_write_gp_fuse_byte(gp_fuse_byte, value);
    00636     flashcdw_error_status |= error_status;
    00637   }
    00638 }
    00639
    00640
    00641 void flashcdw_set_all_gp_fuses(U64 value)
    00642 {
    00643   unsigned int error_status;
    00644   switch (value)
    00645   {
    00646   case 0xFFFFFFFFFFFFFFFFULL:
    00647     flashcdw_erase_all_gp_fuses(FALSE);
    00648     break;
    00649   case 0x0000000000000000ULL:
    00650     flashcdw_write_all_gp_fuses(0x0000000000000000ULL);
    00651     break;
    00652   default:
    00653     flashcdw_erase_all_gp_fuses(FALSE);
    00654     error_status = flashcdw_error_status;
    00655     flashcdw_write_all_gp_fuses(value);
    00656     flashcdw_error_status |= error_status;
    00657   }
    00658 }
    00659
    00660
    00662
    00663
    00666
    00667
    00668
    00669 void flashcdw_clear_page_buffer(void)
    00670 {
    00671   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_CPB, -1);
    00672 }
    00673
    00674
    00675 Bool flashcdw_is_page_erased(void)
    00676 {
    00677   return ((AVR32_FLASHCDW.fsr & AVR32_FLASHCDW_FSR_QPRR_MASK) != 0);
    00678 }
    00679
    00680
    00681 Bool flashcdw_quick_page_read(int page_number)
    00682 {
    00683   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_QPR, page_number);
    00684   return flashcdw_is_page_erased();
    00685 }
    00686
    00687
    00688 Bool flashcdw_erase_page(int page_number, Bool check)
    00689 {
    00690   Bool page_erased = TRUE;
    00691   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_EP, page_number);
    00692   if (check)
    00693   {
    00694     unsigned int error_status = flashcdw_error_status;
    00695     page_erased = flashcdw_quick_page_read(-1);
    00696     flashcdw_error_status |= error_status;
    00697   }
    00698   return page_erased;
    00699 }
    00700
    00701
    00702 Bool flashcdw_erase_all_pages(Bool check)
    00703 {
    00704   Bool all_pages_erased = TRUE;
    00705   unsigned int error_status = 0;
    00706   unsigned int page_number = flashcdw_get_page_count();
    00707   while (page_number)
    00708   {
    00709     all_pages_erased &= flashcdw_erase_page(--page_number, check);
    00710     error_status |= flashcdw_error_status;
    00711   }
    00712   flashcdw_error_status = error_status;
    00713   return all_pages_erased;
    00714 }
    00715
    00716
    00717 void flashcdw_write_page(int page_number)
    00718 {
    00719   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_WP, page_number);
    00720 }
    00721
    00722
    00723 Bool flashcdw_quick_user_page_read(void)
    00724 {
    00725   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_QPRUP, -1);
    00726   return flashcdw_is_page_erased();
    00727 }
    00728
    00729
    00730 Bool flashcdw_erase_user_page(Bool check)
    00731 {
    00732   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_EUP, -1);
    00733   return (check) ? flashcdw_quick_user_page_read() : TRUE;
    00734 }
    00735
    00736
    00737 void flashcdw_write_user_page(void)
    00738 {
    00739   flashcdw_issue_command(AVR32_FLASHCDW_FCMD_CMD_WUP, -1);
    00740 }
    00741
    00742
    00743 volatile void *flashcdw_memset8(volatile void *dst, U8 src, size_t nbytes, Bool erase)
    00744 {
    00745   return flashcdw_memset16(dst, src | (U16)src << 8, nbytes, erase);
    00746 }
    00747
    00748
    00749 volatile void *flashcdw_memset16(volatile void *dst, U16 src, size_t nbytes, Bool erase)
    00750 {
    00751   return flashcdw_memset32(dst, src | (U32)src << 16, nbytes, erase);
    00752 }
    00753
    00754
    00755 volatile void *flashcdw_memset32(volatile void *dst, U32 src, size_t nbytes, Bool erase)
    00756 {
    00757   return flashcdw_memset64(dst, src | (U64)src << 32, nbytes, erase);
    00758 }
    00759
    00760
    00761 volatile void *flashcdw_memset64(volatile void *dst, U64 src, size_t nbytes, Bool erase)
    00762 {
    00763   // Use aggregated pointers to have several alignments available for a same address.
    00764   UnionCVPtr flash_array_end;
    00765   UnionVPtr dest;
    00766   Union64 source = {0};
    00767   StructCVPtr dest_end;
    00768   UnionCVPtr flash_page_source_end;
    00769   Bool incomplete_flash_page_end;
    00770   Union64 flash_dword;
    00771   UnionVPtr tmp;
    00772   unsigned int error_status = 0;
    00773   unsigned int i;
    00774
    00775   // Reformat arguments.
    00776   flash_array_end.u8ptr = AVR32_FLASH + flashcdw_get_flash_size();
    00777   dest.u8ptr = dst;
    00778   for (i = (Get_align((U32)dest.u8ptr, sizeof(U64)) - 1) & (sizeof(U64) - 1);
    00779        src; i = (i - 1) & (sizeof(U64) - 1))
    00780   {
    00781     source.u8[i] = src;
    00782     src >>= 8;
    00783   }
    00784   dest_end.u8ptr = dest.u8ptr + nbytes;
    00785
    00786   // If destination is outside flash, go to next flash page if any.
    00787   if (dest.u8ptr < AVR32_FLASH)
    00788   {
    00789     dest.u8ptr = AVR32_FLASH;
    00790   }
    00791   else if (flash_array_end.u8ptr <= dest.u8ptr && dest.u8ptr < AVR32_FLASHCDW_USER_PAGE)
    00792   {
    00793     dest.u8ptr = AVR32_FLASHCDW_USER_PAGE;
    00794   }
    00795
    00796   // If end of destination is outside flash, move it to the end of the previous flash page if any.
    00797   if (dest_end.u8ptr > AVR32_FLASHCDW_USER_PAGE + AVR32_FLASHCDW_USER_PAGE_SIZE)
    00798   {
    00799     dest_end.u8ptr = AVR32_FLASHCDW_USER_PAGE + AVR32_FLASHCDW_USER_PAGE_SIZE;
    00800   }
    00801   else if (AVR32_FLASHCDW_USER_PAGE >= dest_end.u8ptr && dest_end.u8ptr > flash_array_end.u8ptr)
    00802   {
    00803     dest_end.u8ptr = flash_array_end.u8ptr;
    00804   }
    00805
    00806   // Align each end of destination pointer with its natural boundary.
    00807   dest_end.u16ptr = (U16 *)Align_down((U32)dest_end.u8ptr, sizeof(U16));
    00808   dest_end.u32ptr = (U32 *)Align_down((U32)dest_end.u16ptr, sizeof(U32));
    00809   dest_end.u64ptr = (U64 *)Align_down((U32)dest_end.u32ptr, sizeof(U64));
    00810
    00811   // While end of destination is not reached...
    00812   while (dest.u8ptr < dest_end.u8ptr)
    00813   {
    00814     // Clear the page buffer in order to prepare data for a flash page write.
    00815     flashcdw_clear_page_buffer();
    00816     error_status |= flashcdw_error_status;
    00817
    00818     // Determine where the source data will end in the current flash page.
    00819     flash_page_source_end.u64ptr =
    00820       (U64 *)min((U32)dest_end.u64ptr,
    00821                  Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE) + AVR32_FLASHCDW_PAGE_SIZE);
    00822
    00823     // Determine if the current destination page has an incomplete end.
    00824     incomplete_flash_page_end = (Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE) >=
    00825                                  Align_down((U32)dest_end.u8ptr, AVR32_FLASHCDW_PAGE_SIZE));
    00826
    00827     // Use a flash double-word buffer to manage unaligned accesses.
    00828     flash_dword.u64 = source.u64;
    00829
    00830     // If destination does not point to the beginning of the current flash page...
    00831     if (!Test_align((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE))
    00832     {
    00833       // Fill the beginning of the page buffer with the current flash page data.
    00834       // This is required by the hardware, even if page erase is not requested,
    00835       // in order to be able to write successfully to erased parts of flash
    00836       // pages that have already been written to.
    00837       for (tmp.u8ptr = (U8 *)Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE);
    00838            tmp.u64ptr < (U64 *)Align_down((U32)dest.u8ptr, sizeof(U64));
    00839            tmp.u64ptr++)
    00840         *tmp.u64ptr = *tmp.u64ptr;
    00841
    00842       // If destination is not 64-bit aligned...
    00843       if (!Test_align((U32)dest.u8ptr, sizeof(U64)))
    00844       {
    00845         // Fill the beginning of the flash double-word buffer with the current
    00846         // flash page data.
    00847         // This is required by the hardware, even if page erase is not
    00848         // requested, in order to be able to write successfully to erased parts
    00849         // of flash pages that have already been written to.
    00850         for (i = 0; i < Get_align((U32)dest.u8ptr, sizeof(U64)); i++)
    00851           flash_dword.u8[i] = *tmp.u8ptr++;
    00852
    00853         // Align the destination pointer with its 64-bit boundary.
    00854         dest.u64ptr = (U64 *)Align_down((U32)dest.u8ptr, sizeof(U64));
    00855
    00856         // If the current destination double-word is not the last one...
    00857         if (dest.u64ptr < dest_end.u64ptr)
    00858         {
    00859           // Write the flash double-word buffer to the page buffer and reinitialize it.
    00860           *dest.u64ptr++ = flash_dword.u64;
    00861           flash_dword.u64 = source.u64;
    00862         }
    00863       }
    00864     }
    00865
    00866     // Write the source data to the page buffer with 64-bit alignment.
    00867     for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
    00868       *dest.u64ptr++ = source.u64;
    00869
    00870     // If the current destination page has an incomplete end...
    00871     if (incomplete_flash_page_end)
    00872     {
    00873       // This is required by the hardware, even if page erase is not requested,
    00874       // in order to be able to write successfully to erased parts of flash
    00875       // pages that have already been written to.
    00876       {
    00877         tmp.u8ptr = (volatile U8 *)dest_end.u8ptr;
    00878
    00879         // If end of destination is not 64-bit aligned...
    00880         if (!Test_align((U32)dest_end.u8ptr, sizeof(U64)))
    00881         {
    00882           // Fill the end of the flash double-word buffer with the current flash page data.
    00883           for (i = Get_align((U32)dest_end.u8ptr, sizeof(U64)); i < sizeof(U64); i++)
    00884             flash_dword.u8[i] = *tmp.u8ptr++;
    00885
    00886           // Write the flash double-word buffer to the page buffer.
    00887           *dest.u64ptr++ = flash_dword.u64;
    00888         }
    00889
    00890         // Fill the end of the page buffer with the current flash page data.
    00891         for (; !Test_align((U32)tmp.u64ptr, AVR32_FLASHCDW_PAGE_SIZE); tmp.u64ptr++)
    00892           *tmp.u64ptr = *tmp.u64ptr;
    00893       }
    00894     }
    00895
    00896     // If the current flash page is in the flash array...
    00897     if (dest.u8ptr <= AVR32_FLASHCDW_USER_PAGE)
    00898     {
    00899       // Erase the current page if requested and write it from the page buffer.
    00900       if (erase)
    00901       {
    00902         flashcdw_erase_page(-1, FALSE);
    00903         error_status |= flashcdw_error_status;
    00904       }
    00905       flashcdw_write_page(-1);
    00906       error_status |= flashcdw_error_status;
    00907
    00908       // If the end of the flash array is reached, go to the User page.
    00909       if (dest.u8ptr >= flash_array_end.u8ptr)
    00910         dest.u8ptr = AVR32_FLASHCDW_USER_PAGE;
    00911     }
    00912     // If the current flash page is the User page...
    00913     else
    00914     {
    00915       // Erase the User page if requested and write it from the page buffer.
    00916       if (erase)
    00917       {
    00918         flashcdw_erase_user_page(FALSE);
    00919         error_status |= flashcdw_error_status;
    00920       }
    00921       flashcdw_write_user_page();
    00922       error_status |= flashcdw_error_status;
    00923     }
    00924   }
    00925
    00926   // Update the FLASHC error status.
    00927   flashcdw_error_status = error_status;
    00928
    00929   // Return the initial destination pointer as the standard memset function does.
    00930   return dst;
    00931 }
    00932
    00933
    00934 volatile void *flashcdw_memcpy(volatile void *dst, const void *src, size_t nbytes, Bool erase)
    00935 {
    00936   // Use aggregated pointers to have several alignments available for a same address.
    00937   UnionCVPtr flash_array_end;
    00938   UnionVPtr dest;
    00939   UnionCPtr source;
    00940   StructCVPtr dest_end;
    00941   UnionCVPtr flash_page_source_end;
    00942   Bool incomplete_flash_page_end;
    00943   Union64 flash_dword;
    00944   Bool flash_dword_pending = FALSE;
    00945   UnionVPtr tmp;
    00946   unsigned int error_status = 0;
    00947   unsigned int i, j;
    00948
    00949   // Reformat arguments.
    00950   flash_array_end.u8ptr = AVR32_FLASH + flashcdw_get_flash_size();
    00951   dest.u8ptr = dst;
    00952   source.u8ptr = src;
    00953   dest_end.u8ptr = dest.u8ptr + nbytes;
    00954
    00955   // If destination is outside flash, go to next flash page if any.
    00956   if (dest.u8ptr < AVR32_FLASH)
    00957   {
    00958     source.u8ptr += AVR32_FLASH - dest.u8ptr;
    00959     dest.u8ptr = AVR32_FLASH;
    00960   }
    00961   else if (flash_array_end.u8ptr <= dest.u8ptr && dest.u8ptr < AVR32_FLASHCDW_USER_PAGE)
    00962   {
    00963     source.u8ptr += AVR32_FLASHCDW_USER_PAGE - dest.u8ptr;
    00964     dest.u8ptr = AVR32_FLASHCDW_USER_PAGE;
    00965   }
    00966
    00967   // If end of destination is outside flash, move it to the end of the previous flash page if any.
    00968   if (dest_end.u8ptr > AVR32_FLASHCDW_USER_PAGE + AVR32_FLASHCDW_USER_PAGE_SIZE)
    00969   {
    00970     dest_end.u8ptr = AVR32_FLASHCDW_USER_PAGE + AVR32_FLASHCDW_USER_PAGE_SIZE;
    00971   }
    00972   else if (AVR32_FLASHCDW_USER_PAGE >= dest_end.u8ptr && dest_end.u8ptr > flash_array_end.u8ptr)
    00973   {
    00974     dest_end.u8ptr = flash_array_end.u8ptr;
    00975   }
    00976
    00977   // Align each end of destination pointer with its natural boundary.
    00978   dest_end.u16ptr = (U16 *)Align_down((U32)dest_end.u8ptr, sizeof(U16));
    00979   dest_end.u32ptr = (U32 *)Align_down((U32)dest_end.u16ptr, sizeof(U32));
    00980   dest_end.u64ptr = (U64 *)Align_down((U32)dest_end.u32ptr, sizeof(U64));
    00981
    00982   // While end of destination is not reached...
    00983   while (dest.u8ptr < dest_end.u8ptr)
    00984   {
    00985     // Clear the page buffer in order to prepare data for a flash page write.
    00986     flashcdw_clear_page_buffer();
    00987     error_status |= flashcdw_error_status;
    00988
    00989     // Determine where the source data will end in the current flash page.
    00990     flash_page_source_end.u64ptr =
    00991       (U64 *)min((U32)dest_end.u64ptr,
    00992                  Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE) + AVR32_FLASHCDW_PAGE_SIZE);
    00993
    00994     // Determine if the current destination page has an incomplete end.
    00995     incomplete_flash_page_end = (Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE) >=
    00996                                  Align_down((U32)dest_end.u8ptr, AVR32_FLASHCDW_PAGE_SIZE));
    00997
    00998     // If destination does not point to the beginning of the current flash page...
    00999     if (!Test_align((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE))
    01000     {
    01001       // Fill the beginning of the page buffer with the current flash page data.
    01002       // This is required by the hardware, even if page erase is not requested,
    01003       // in order to be able to write successfully to erased parts of flash
    01004       // pages that have already been written to.
    01005       for (tmp.u8ptr = (U8 *)Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE);
    01006            tmp.u64ptr < (U64 *)Align_down((U32)dest.u8ptr, sizeof(U64));
    01007            tmp.u64ptr++)
    01008         *tmp.u64ptr = *tmp.u64ptr;
    01009
    01010       // If destination is not 64-bit aligned...
    01011       if (!Test_align((U32)dest.u8ptr, sizeof(U64)))
    01012       {
    01013         // Fill the beginning of the flash double-word buffer with the current
    01014         // flash page data.
    01015         // This is required by the hardware, even if page erase is not
    01016         // requested, in order to be able to write successfully to erased parts
    01017         // of flash pages that have already been written to.
    01018         for (i = 0; i < Get_align((U32)dest.u8ptr, sizeof(U64)); i++)
    01019           flash_dword.u8[i] = *tmp.u8ptr++;
    01020
    01021         // Fill the end of the flash double-word buffer with the source data.
    01022         for (; i < sizeof(U64); i++)
    01023           flash_dword.u8[i] = *source.u8ptr++;
    01024
    01025         // Align the destination pointer with its 64-bit boundary.
    01026         dest.u64ptr = (U64 *)Align_down((U32)dest.u8ptr, sizeof(U64));
    01027
    01028         // If the current destination double-word is not the last one...
    01029         if (dest.u64ptr < dest_end.u64ptr)
    01030         {
    01031           // Write the flash double-word buffer to the page buffer.
    01032           *dest.u64ptr++ = flash_dword.u64;
    01033         }
    01034         // If the current destination double-word is the last one, the flash
    01035         // double-word buffer must be kept for later.
    01036         else flash_dword_pending = TRUE;
    01037       }
    01038     }
    01039
    01040     // Read the source data with the maximal possible alignment and write it to
    01041     // the page buffer with 64-bit alignment.
    01042     switch (Get_align((U32)source.u8ptr, sizeof(U32)))
    01043     {
    01044     case 0:
    01045       for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
    01046         *dest.u64ptr++ = *source.u64ptr++;
    01047       break;
    01048
    01049     case sizeof(U16):
    01050       for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
    01051       {
    01052         for (j = 0; j < sizeof(U64) / sizeof(U16); j++) flash_dword.u16[j] = *source.u16ptr++;
    01053         *dest.u64ptr++ = flash_dword.u64;
    01054       }
    01055       break;
    01056
    01057     default:
    01058       for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
    01059       {
    01060         for (j = 0; j < sizeof(U64); j++) flash_dword.u8[j] = *source.u8ptr++;
    01061         *dest.u64ptr++ = flash_dword.u64;
    01062       }
    01063     }
    01064
    01065     // If the current destination page has an incomplete end...
    01066     if (incomplete_flash_page_end)
    01067     {
    01068       // If the flash double-word buffer is in use, do not initialize it.
    01069       if (flash_dword_pending) i = Get_align((U32)dest_end.u8ptr, sizeof(U64));
    01070       // If the flash double-word buffer is free...
    01071       else
    01072       {
    01073         // Fill the beginning of the flash double-word buffer with the source data.
    01074         for (i = 0; i < Get_align((U32)dest_end.u8ptr, sizeof(U64)); i++)
    01075           flash_dword.u8[i] = *source.u8ptr++;
    01076       }
    01077
    01078       // This is required by the hardware, even if page erase is not requested,
    01079       // in order to be able to write successfully to erased parts of flash
    01080       // pages that have already been written to.
    01081       {
    01082         tmp.u8ptr = (volatile U8 *)dest_end.u8ptr;
    01083
    01084         // If end of destination is not 64-bit aligned...
    01085         if (!Test_align((U32)dest_end.u8ptr, sizeof(U64)))
    01086         {
    01087           // Fill the end of the flash double-word buffer with the current flash page data.
    01088           for (; i < sizeof(U64); i++)
    01089             flash_dword.u8[i] = *tmp.u8ptr++;
    01090
    01091           // Write the flash double-word buffer to the page buffer.
    01092           *dest.u64ptr++ = flash_dword.u64;
    01093         }
    01094
    01095         // Fill the end of the page buffer with the current flash page data.
    01096         for (; !Test_align((U32)tmp.u64ptr, AVR32_FLASHCDW_PAGE_SIZE); tmp.u64ptr++)
    01097           *tmp.u64ptr = *tmp.u64ptr;
    01098       }
    01099     }
    01100
    01101     // If the current flash page is in the flash array...
    01102     if (dest.u8ptr <= AVR32_FLASHCDW_USER_PAGE)
    01103     {
    01104       // Erase the current page if requested and write it from the page buffer.
    01105       if (erase)
    01106       {
    01107         flashcdw_erase_page(-1, FALSE);
    01108         error_status |= flashcdw_error_status;
    01109       }
    01110       flashcdw_write_page(-1);
    01111       error_status |= flashcdw_error_status;
    01112
    01113       // If the end of the flash array is reached, go to the User page.
    01114       if (dest.u8ptr >= flash_array_end.u8ptr)
    01115       {
    01116         source.u8ptr += AVR32_FLASHCDW_USER_PAGE - dest.u8ptr;
    01117         dest.u8ptr = AVR32_FLASHCDW_USER_PAGE;
    01118       }
    01119     }
    01120     // If the current flash page is the User page...
    01121     else
    01122     {
    01123       // Erase the User page if requested and write it from the page buffer.
    01124       if (erase)
    01125       {
    01126         flashcdw_erase_user_page(FALSE);
    01127         error_status |= flashcdw_error_status;
    01128       }
    01129       flashcdw_write_user_page();
    01130       error_status |= flashcdw_error_status;
    01131     }
    01132   }
    01133
    01134   // Update the FLASHC error status.
    01135   flashcdw_error_status = error_status;
    01136
    01137   // Return the initial destination pointer as the standard memcpy function does.
    01138   return dst;
    01139 }
    01140