flash_efc.cpp
Go to the documentation of this file.
00001 
00044 #include <string.h>
00045 #include <assert.h>
00046 #include "flash_efc.h"
00047 
00049 
00050 #ifdef __cplusplus
00051 extern "C" {
00052 #endif
00053 
00054 
00055 
00064 #if SAM4E
00065 /* User signature size */
00066 # define FLASH_USER_SIG_SIZE   (512)
00067 #endif
00068 
00069 #if SAM4S
00070 /* Internal Flash Controller 0. */
00071 # define EFC     EFC0
00072 /* User signature size */
00073 # define FLASH_USER_SIG_SIZE   (512)
00074 /* Internal Flash 0 base address. */
00075 # define IFLASH_ADDR     IFLASH0_ADDR
00076 /* Internal flash page size. */
00077 # define IFLASH_PAGE_SIZE     IFLASH0_PAGE_SIZE
00078 /* Internal flash lock region size. */
00079 # define IFLASH_LOCK_REGION_SIZE     IFLASH0_LOCK_REGION_SIZE
00080 #endif
00081 
00082 /* Internal Flash Controller 0. */
00083 # define EFC     EFC0
00084 /* The max GPNVM number. */
00085 # define GPNVM_NUM_MAX        3
00086 /* Internal Flash 0 base address. */
00087 # define IFLASH_ADDR     IFLASH0_ADDR
00088 /* Internal flash page size. */
00089 # define IFLASH_PAGE_SIZE     IFLASH0_PAGE_SIZE
00090 /* Internal flash lock region size. */
00091 # define IFLASH_LOCK_REGION_SIZE     IFLASH0_LOCK_REGION_SIZE
00092 
00093 /* Flash page buffer for alignment */
00094 static uint32_t gs_ul_page_buffer[IFLASH_PAGE_SIZE / sizeof(uint32_t)];
00095 
00106 static void translate_address(Efc **pp_efc, uint32_t ul_addr,
00107                 uint16_t *pus_page, uint16_t *pus_offset)
00108 {
00109         Efc *p_efc;
00110         uint16_t us_page;
00111         uint16_t us_offset;
00112 
00113         if (ul_addr >= IFLASH1_ADDR) {
00114                 p_efc = EFC1;
00115                 us_page = (ul_addr - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
00116                 us_offset = (ul_addr - IFLASH1_ADDR) % IFLASH1_PAGE_SIZE;
00117         } else {
00118                 p_efc = EFC0;
00119                 us_page = (ul_addr - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
00120                 us_offset = (ul_addr - IFLASH0_ADDR) % IFLASH0_PAGE_SIZE;
00121         }
00122 
00123         /* Store values */
00124         if (pp_efc) {
00125                 *pp_efc = p_efc;
00126         }
00127 
00128         if (pus_page) {
00129                 *pus_page = us_page;
00130         }
00131 
00132         if (pus_offset) {
00133                 *pus_offset = us_offset;
00134         }
00135 }
00136 
00145 static void compute_address(Efc *p_efc, uint16_t us_page, uint16_t us_offset,
00146                 uint32_t *pul_addr)
00147 {
00148         uint32_t ul_addr;
00149 
00150 /* Dual bank flash */
00151 #ifdef EFC1
00152         /* Compute address */
00153         ul_addr = (p_efc == EFC0) ?
00154                         IFLASH0_ADDR + us_page * IFLASH_PAGE_SIZE + us_offset :
00155                         IFLASH1_ADDR + us_page * IFLASH_PAGE_SIZE + us_offset;
00156 
00157 /* One bank flash */
00158 #else
00159         /* avoid Cppcheck Warning */
00160         UNUSED(p_efc);
00161         /* Compute address */
00162         ul_addr = IFLASH_ADDR + us_page * IFLASH_PAGE_SIZE + us_offset;
00163 #endif
00164 
00165         /* Store result */
00166         if (pul_addr != NULL) {
00167                 *pul_addr = ul_addr;
00168         }
00169 }
00170 
00179 static void compute_lock_range(uint32_t ul_start, uint32_t ul_end,
00180                 uint32_t *pul_actual_start, uint32_t *pul_actual_end)
00181 {
00182         uint32_t ul_actual_start, ul_actual_end;
00183 
00184         ul_actual_start = ul_start - (ul_start % IFLASH_LOCK_REGION_SIZE);
00185         ul_actual_end = ul_end - (ul_end % IFLASH_LOCK_REGION_SIZE) +
00186                         IFLASH_LOCK_REGION_SIZE - 1;
00187 
00188         if (pul_actual_start) {
00189                 *pul_actual_start = ul_actual_start;
00190         }
00191 
00192         if (pul_actual_end) {
00193                 *pul_actual_end = ul_actual_end;
00194         }
00195 }
00196 
00205 uint32_t flash_init(uint32_t ul_mode, uint32_t ul_fws)
00206 {
00207         efc_init(EFC, ul_mode, ul_fws);
00208 
00209 #ifdef EFC1
00210         efc_init(EFC1, ul_mode, ul_fws);
00211 #endif
00212 
00213         return FLASH_RC_OK;
00214 }
00215 
00224 uint32_t flash_set_wait_state(uint32_t ul_address, uint32_t ul_fws)
00225 {
00226         Efc *p_efc;
00227 
00228         translate_address(&p_efc, ul_address, NULL, NULL);
00229         efc_set_wait_state(p_efc, ul_fws);
00230 
00231         return FLASH_RC_OK;
00232 }
00233 
00242 uint32_t flash_set_wait_state_adaptively(uint32_t ul_address)
00243 {
00244         Efc *p_efc;
00245         uint32_t clock = SystemCoreClock;
00246 
00247         translate_address(&p_efc, ul_address, NULL, NULL);
00248 
00249         /* Set FWS for embedded Flash access according to operating frequency */
00250         if (clock < CHIP_FREQ_FWS_0) {
00251                 efc_set_wait_state(p_efc, 0);
00252         } else if (clock < CHIP_FREQ_FWS_1) {
00253                 efc_set_wait_state(p_efc, 1);
00254         } else if (clock < CHIP_FREQ_FWS_2) {
00255                 efc_set_wait_state(p_efc, 2);
00256         } else if (clock < CHIP_FREQ_FWS_3) {
00257                 efc_set_wait_state(p_efc, 3);
00258         } else {
00259                 efc_set_wait_state(p_efc, 4);
00260         }
00261         return FLASH_RC_OK;
00262 }
00263 
00271 uint32_t flash_get_wait_state(uint32_t ul_address)
00272 {
00273         Efc *p_efc;
00274 
00275         translate_address(&p_efc, ul_address, NULL, NULL);
00276         return efc_get_wait_state(p_efc);
00277 }
00278 
00288 uint32_t flash_get_descriptor(uint32_t ul_address,
00289                 uint32_t *pul_flash_descriptor, uint32_t ul_size)
00290 {
00291         Efc *p_efc;
00292         uint32_t ul_tmp;
00293         uint32_t ul_cnt;
00294 
00295         translate_address(&p_efc, ul_address, NULL, NULL);
00296 
00297         /* Command fails */
00298         if (FLASH_RC_OK != efc_perform_command(p_efc, EFC_FCMD_GETD, 0)) {
00299                 return 0;
00300         } else {
00301                 /* Read until no result */
00302                 for (ul_cnt = 0;; ul_cnt++) {
00303                         ul_tmp = efc_get_result(p_efc);
00304                         if ((ul_size > ul_cnt) && (ul_tmp != 0)) {
00305                                 *pul_flash_descriptor++ = ul_tmp;
00306                         } else {
00307                                 break;
00308                         }
00309                 }
00310         }
00311 
00312         return ul_cnt;
00313 }
00314 
00325 uint32_t flash_get_page_count(const uint32_t *pul_flash_descriptor)
00326 {
00327         return (pul_flash_descriptor[1] / pul_flash_descriptor[2]);
00328 }
00329 
00340 uint32_t flash_get_page_count_per_region(const uint32_t *pul_flash_descriptor)
00341 {
00342         return (pul_flash_descriptor[4] / pul_flash_descriptor[2]);
00343 }
00344 
00355 uint32_t flash_get_region_count(const uint32_t *pul_flash_descriptor)
00356 {
00357         return (pul_flash_descriptor[3]);
00358 }
00359 
00371 uint32_t flash_erase_all(uint32_t ul_address)
00372 {
00373         Efc *p_efc;
00374 
00375         translate_address(&p_efc, ul_address, NULL, NULL);
00376 
00377         if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EA, 0)) {
00378                 return FLASH_RC_ERROR;
00379         }
00380 
00381         return FLASH_RC_OK;
00382 }
00383 
00384 #if SAM3SD8
00385 
00395 uint32_t flash_erase_plane(uint32_t ul_address)
00396 {
00397         Efc *p_efc;
00398         uint16_t us_page;
00399 
00400         translate_address(&p_efc, ul_address, &us_page, NULL);
00401 
00402         if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EPL, us_page)) {
00403                 return FLASH_RC_ERROR;
00404         }
00405 
00406         return FLASH_RC_OK;
00407 }
00408 #endif
00409 
00410 #if (SAM4S || SAM4E)
00411 
00418 uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num)
00419 {
00420         Efc *p_efc;
00421         uint16_t us_page;
00422 
00423         if (uc_page_num >= IFLASH_ERASE_PAGES_INVALID) {
00424                 return FLASH_RC_INVALID;
00425         }
00426 
00427         if (ul_address & (IFLASH_PAGE_SIZE - 1)) {
00428                 return FLASH_RC_INVALID;
00429         }
00430 
00431         translate_address(&p_efc, ul_address, &us_page, NULL);
00432 
00433         if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EPA,
00434                                         (us_page | uc_page_num))) {
00435                 return FLASH_RC_ERROR;
00436         }
00437 
00438         return FLASH_RC_OK;
00439 }
00440 
00451 uint32_t flash_erase_sector(uint32_t ul_address)
00452 {
00453         Efc *p_efc;
00454         uint16_t us_page;
00455 
00456         translate_address(&p_efc, ul_address, &us_page, NULL);
00457 
00458         if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_ES, us_page)) {
00459                 return FLASH_RC_ERROR;
00460         }
00461 
00462         return FLASH_RC_OK;
00463 }
00464 #endif
00465 
00482 uint32_t flash_write(uint32_t ul_address, const void *p_buffer,
00483                 uint32_t ul_size, uint32_t ul_erase_flag)
00484 {
00485         Efc *p_efc;
00486         uint32_t ul_fws_temp;
00487         uint16_t us_page;
00488         uint16_t us_offset;
00489         uint32_t writeSize;
00490         uint32_t ul_page_addr;
00491         uint16_t us_padding;
00492         uint32_t ul_error;
00493         uint32_t ul_idx;
00494         uint32_t *p_aligned_dest;
00495         uint8_t *puc_page_buffer = (uint8_t *) gs_ul_page_buffer;
00496 
00497         translate_address(&p_efc, ul_address, &us_page, &us_offset);
00498 
00499         /* According to the errata, set the wait state value to 6. */
00500         ul_fws_temp = efc_get_wait_state(p_efc);
00501         efc_set_wait_state(p_efc, 6);
00502 
00503         /* Write all pages */
00504         while (ul_size > 0) {
00505                 /* Copy data in temporary buffer to avoid alignment problems. */
00506                 writeSize = Min((uint32_t) IFLASH_PAGE_SIZE - us_offset,
00507                                 ul_size);
00508                 compute_address(p_efc, us_page, 0, &ul_page_addr);
00509                 us_padding = IFLASH_PAGE_SIZE - us_offset - writeSize;
00510 
00511                 /* Pre-buffer data */
00512                 memcpy(puc_page_buffer, (void *)ul_page_addr, us_offset);
00513 
00514                 /* Buffer data */
00515                 memcpy(puc_page_buffer + us_offset, p_buffer, writeSize);
00516 
00517                 /* Post-buffer data */
00518                 memcpy(puc_page_buffer + us_offset + writeSize,
00519                                 (void *)(ul_page_addr + us_offset + writeSize),
00520                                 us_padding);
00521 
00522                 /* Write page.
00523                  * Writing 8-bit and 16-bit data is not allowed and may lead to
00524                  * unpredictable data corruption.
00525                  */
00526                 p_aligned_dest = (uint32_t *) ul_page_addr;
00527                 for (ul_idx = 0; ul_idx < (IFLASH_PAGE_SIZE / sizeof(uint32_t));
00528                                 ++ul_idx) {
00529                         *p_aligned_dest++ = gs_ul_page_buffer[ul_idx];
00530                 }
00531 
00532                 if (ul_erase_flag) {
00533                         ul_error = efc_perform_command(p_efc, EFC_FCMD_EWP,
00534                                         us_page);
00535                 } else {
00536                         ul_error = efc_perform_command(p_efc, EFC_FCMD_WP,
00537                                         us_page);
00538                 }
00539 
00540                 if (ul_error) {
00541                         return ul_error;
00542                 }
00543 
00544                 /* Progression */
00545                 p_buffer = (void *)((uint32_t) p_buffer + writeSize);
00546                 ul_size -= writeSize;
00547                 us_page++;
00548                 us_offset = 0;
00549         }
00550 
00551         /* According to the errata, restore the wait state value. */
00552         efc_set_wait_state(p_efc, ul_fws_temp);
00553 
00554         return FLASH_RC_OK;
00555 }
00556 
00557 
00569 uint32_t flash_lock(uint32_t ul_start, uint32_t ul_end,
00570                 uint32_t *pul_actual_start, uint32_t *pul_actual_end)
00571 {
00572         Efc *p_efc;
00573         uint32_t ul_actual_start, ul_actual_end;
00574         uint16_t us_start_page, us_end_page;
00575         uint32_t ul_error;
00576         uint16_t us_num_pages_in_region =
00577                         IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
00578 
00579         /* Compute actual lock range and store it */
00580         compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end);
00581 
00582         if (pul_actual_start != NULL) {
00583                 *pul_actual_start = ul_actual_start;
00584         }
00585 
00586         if (pul_actual_end != NULL) {
00587                 *pul_actual_end = ul_actual_end;
00588         }
00589 
00590         /* Compute page numbers */
00591         translate_address(&p_efc, ul_actual_start, &us_start_page, 0);
00592         translate_address(0, ul_actual_end, &us_end_page, 0);
00593 
00594         /* Lock all pages */
00595         while (us_start_page < us_end_page) {
00596                 ul_error = efc_perform_command(p_efc, EFC_FCMD_SLB, us_start_page);
00597 
00598                 if (ul_error) {
00599                         return ul_error;
00600                 }
00601                 us_start_page += us_num_pages_in_region;
00602         }
00603 
00604         return FLASH_RC_OK;
00605 }
00606 
00618 uint32_t flash_unlock(uint32_t ul_start, uint32_t ul_end,
00619                 uint32_t *pul_actual_start, uint32_t *pul_actual_end)
00620 {
00621         Efc *p_efc;
00622         uint32_t ul_actual_start, ul_actual_end;
00623         uint16_t us_start_page, us_end_page;
00624         uint32_t ul_error;
00625         uint16_t us_num_pages_in_region =
00626                         IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
00627 
00628         /* Compute actual unlock range and store it */
00629         compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end);
00630         if (pul_actual_start != NULL) {
00631                 *pul_actual_start = ul_actual_start;
00632         }
00633         if (pul_actual_end != NULL) {
00634                 *pul_actual_end = ul_actual_end;
00635         }
00636 
00637         /* Compute page numbers */
00638         translate_address(&p_efc, ul_actual_start, &us_start_page, 0);
00639         translate_address(0, ul_actual_end, &us_end_page, 0);
00640 
00641         /* Unlock all pages */
00642         while (us_start_page < us_end_page) {
00643                 ul_error = efc_perform_command(p_efc, EFC_FCMD_CLB,
00644                                 us_start_page);
00645                 if (ul_error) {
00646                         return ul_error;
00647                 }
00648                 us_start_page += us_num_pages_in_region;
00649         }
00650 
00651         return FLASH_RC_OK;
00652 }
00653 
00662 uint32_t flash_is_locked(uint32_t ul_start, uint32_t ul_end)
00663 {
00664         Efc *p_efc;
00665         uint16_t us_start_page, us_end_page;
00666         uint8_t uc_start_region, uc_end_region;
00667         uint16_t us_num_pages_in_region;
00668         uint32_t ul_status;
00669         uint32_t ul_error;
00670         uint32_t ul_num_locked_regions = 0;
00671         uint32_t ul_count = 0;
00672         uint32_t ul_bit = 0;
00673 
00674         /* Compute page numbers */
00675         translate_address(&p_efc, ul_start, &us_start_page, 0);
00676         translate_address(0, ul_end, &us_end_page, 0);
00677 
00678         /* Compute region numbers */
00679         us_num_pages_in_region = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
00680         uc_start_region = us_start_page / us_num_pages_in_region;
00681         uc_end_region = us_end_page / us_num_pages_in_region;
00682 
00683         /* Retrieve lock status */
00684         ul_error = efc_perform_command(p_efc, EFC_FCMD_GLB, 0);
00685 
00686         /* Skip unrequested regions (if necessary) */
00687         ul_status = efc_get_result(p_efc);
00688         while (!(ul_count <= uc_start_region &&
00689                         uc_start_region < (ul_count + 32))) {
00690                 ul_status = efc_get_result(p_efc);
00691                 ul_count += 32;
00692         }
00693 
00694         /* Check status of each involved region */
00695         ul_bit = uc_start_region - ul_count;
00696 
00697         /* Number of region to check (must be > 0) */
00698         ul_count = uc_end_region - uc_start_region + 1;
00699 
00700         while (ul_count > 0) {
00701                 if (ul_status & (1 << (ul_bit))) {
00702                         ul_num_locked_regions++;
00703                 }
00704 
00705                 ul_count -= 1;
00706                 ul_bit += 1;
00707                 if (ul_bit == 32) {
00708                         ul_status = efc_get_result(p_efc);
00709                         ul_bit = 0;
00710                 }
00711         }
00712 
00713         return ul_num_locked_regions;
00714 }
00715 
00723 uint32_t flash_set_gpnvm(uint32_t ul_gpnvm)
00724 {
00725         if (ul_gpnvm >= GPNVM_NUM_MAX) {
00726                 return FLASH_RC_INVALID;
00727         }
00728 
00729         if (FLASH_RC_YES == flash_is_gpnvm_set(ul_gpnvm)) {
00730                 return FLASH_RC_OK;
00731         }
00732 
00733         if (EFC_RC_OK == efc_perform_command(EFC, EFC_FCMD_SGPB, ul_gpnvm)) {
00734                 return FLASH_RC_OK;
00735         }
00736 
00737         return FLASH_RC_ERROR;
00738 }
00739 
00747 uint32_t flash_clear_gpnvm(uint32_t ul_gpnvm)
00748 {
00749         if (ul_gpnvm >= GPNVM_NUM_MAX) {
00750                 return FLASH_RC_INVALID;
00751         }
00752 
00753         if (FLASH_RC_NO == flash_is_gpnvm_set(ul_gpnvm)) {
00754                 return FLASH_RC_OK;
00755         }
00756 
00757         if (EFC_RC_OK == efc_perform_command(EFC, EFC_FCMD_CGPB, ul_gpnvm)) {
00758                 return FLASH_RC_OK;
00759         }
00760 
00761         return FLASH_RC_ERROR;
00762 }
00763 
00772 uint32_t flash_is_gpnvm_set(uint32_t ul_gpnvm)
00773 {
00774         uint32_t ul_gpnvm_bits;
00775 
00776         if (ul_gpnvm >= GPNVM_NUM_MAX) {
00777                 return FLASH_RC_INVALID;
00778         }
00779 
00780         if (EFC_RC_OK != efc_perform_command(EFC, EFC_FCMD_GGPB, 0)) {
00781                 return FLASH_RC_ERROR;
00782         }
00783 
00784         ul_gpnvm_bits = efc_get_result(EFC);
00785         if (ul_gpnvm_bits & (1 << ul_gpnvm)) {
00786                 return FLASH_RC_YES;
00787         }
00788 
00789         return FLASH_RC_NO;
00790 }
00791 
00797 uint32_t flash_enable_security_bit(void)
00798 {
00799         return flash_set_gpnvm(0);
00800 }
00801 
00808 uint32_t flash_is_security_bit_enabled(void)
00809 {
00810         return flash_is_gpnvm_set(0);
00811 }
00812 
00821 uint32_t flash_read_unique_id(uint32_t *pul_data, uint32_t ul_size)
00822 {
00823         uint32_t uid_buf[4];
00824         uint32_t ul_idx;
00825 
00826         if (FLASH_RC_OK != efc_perform_read_sequence(EFC, EFC_FCMD_STUI,
00827                         EFC_FCMD_SPUI, uid_buf, 4)) {
00828                 return FLASH_RC_ERROR;
00829         }
00830 
00831         if (ul_size > 4) {
00832                 /* Only 4 dword to store unique ID */
00833                 ul_size = 4;
00834         }
00835 
00836         for (ul_idx = 0; ul_idx < ul_size; ul_idx++) {
00837                 pul_data[ul_idx] = uid_buf[ul_idx];
00838         }
00839 
00840         return FLASH_RC_OK;
00841 }
00842 
00843 #if (SAM4S || SAM4E)
00844 
00852 uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size)
00853 {
00854         if (ul_size > FLASH_USER_SIG_SIZE) {
00855                 /* Only 512 byte to store unique ID */
00856                 ul_size = FLASH_USER_SIG_SIZE;
00857         }
00858 
00859         /* Send the read user signature commands */
00860         if (FLASH_RC_OK != efc_perform_read_sequence(EFC, EFC_FCMD_STUS,
00861                         EFC_FCMD_SPUS, p_data, ul_size)) {
00862                 return FLASH_RC_ERROR;
00863         }
00864 
00865         return FLASH_RC_OK;
00866 }
00867 
00877 uint32_t flash_write_user_signature(uint32_t ul_address, const void *p_buffer,
00878                 uint32_t ul_size)
00879 {
00880         /* The user signature should be no longer than 512 bytes */
00881         if (ul_size > FLASH_USER_SIG_SIZE) {
00882                 return FLASH_RC_INVALID;
00883         }
00884 
00885         /* Write the full page */
00886         flash_write(ul_address,  p_buffer, ul_size, 0);
00887 
00888         /* Send the write signature command */
00889         if (FLASH_RC_OK != efc_perform_command(EFC, EFC_FCMD_WUS, 0)) {
00890                 return FLASH_RC_ERROR;
00891         }
00892 
00893         return FLASH_RC_OK;
00894 }
00895 
00901 uint32_t flash_erase_user_signature(void)
00902 {
00903         /* Perform the erase user signature command */
00904         return efc_perform_command(EFC, EFC_FCMD_EUS, 0);
00905 }
00906 #endif
00907 
00909 
00911 
00912 #ifdef __cplusplus
00913 }
00914 #endif
00915 
00916 


lizi_arduino
Author(s): RoboTiCan
autogenerated on Wed Aug 26 2015 12:24:22