1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2012, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
30 /** \addtogroup flashd_module Flash Memory Interface
\r
31 * The flash driver manages the programming, erasing, locking and unlocking sequences
\r
32 * with dedicated commands.
\r
34 * To implement flash programing operation, the user has to follow these few steps :
\r
36 * <li>Configue flash wait states to initializes the flash. </li>
\r
37 * <li>Checks whether a region to be programmed is locked. </li>
\r
38 * <li>Unlocks the user region to be programmed if the region have locked before.</li>
\r
39 * <li>Erases the user page before program (optional).</li>
\r
40 * <li>Writes the user page from the page buffer.</li>
\r
41 * <li>Locks the region of programmed area if any.</li>
\r
44 * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
\r
45 * A check of this validity and padding for 32-bit alignment should be done in write algorithm.
\r
47 * Lock/unlock range associated with the user address range is automatically translated.
\r
49 * This security bit can be enabled through the command "Set General Purpose NVM Bit 0".
\r
51 * A 128-bit factory programmed unique ID could be read to serve several purposes.
\r
53 * The driver accesses the flash memory by calling the lowlevel module provided in \ref efc_module.
\r
54 * For more accurate information, please look at the EEFC section of the Datasheet.
\r
69 * The flash driver provides the unified interface for flash program operations.
\r
73 /*----------------------------------------------------------------------------
\r
75 *----------------------------------------------------------------------------*/
\r
81 /*----------------------------------------------------------------------------
\r
83 *----------------------------------------------------------------------------*/
\r
85 #define GPNVM_NUM_MAX 8
\r
87 /*----------------------------------------------------------------------------
\r
89 *----------------------------------------------------------------------------*/
\r
91 static uint32_t _pdwPageBuffer[IFLASH_PAGE_SIZE/sizeof(uint32_t)] ;
\r
92 static uint32_t _dwUseIAP = 1; /* Use IAP interface by default. */
\r
94 /*----------------------------------------------------------------------------
\r
96 *----------------------------------------------------------------------------*/
\r
98 #define min( a, b ) (((a) < (b)) ? (a) : (b))
\r
100 /*----------------------------------------------------------------------------
\r
102 *----------------------------------------------------------------------------*/
\r
106 * \brief Computes the lock range associated with the given address range.
\r
108 * \param dwStart Start address of lock range.
\r
109 * \param dwEnd End address of lock range.
\r
110 * \param pdwActualStart Actual start address of lock range.
\r
111 * \param pdwActualEnd Actual end address of lock range.
\r
113 static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd )
\r
117 uint16_t wStartPage ;
\r
118 uint16_t wEndPage ;
\r
119 uint16_t wNumPagesInRegion ;
\r
120 uint16_t wActualStartPage ;
\r
121 uint16_t wActualEndPage ;
\r
123 /* Convert start and end address in page numbers */
\r
124 EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ;
\r
125 EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ;
\r
127 /* Find out the first page of the first region to lock */
\r
128 wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;
\r
129 wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ;
\r
130 wActualEndPage = wEndPage ;
\r
132 if ( (wEndPage % wNumPagesInRegion) != 0 )
\r
134 wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ;
\r
136 /* Store actual page numbers */
\r
137 EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ;
\r
138 EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ;
\r
139 TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r",
\r
140 (unsigned int)*pdwActualStart, (unsigned int)*pdwActualEnd ) ;
\r
144 /*----------------------------------------------------------------------------
\r
145 * Exported functions
\r
146 *----------------------------------------------------------------------------*/
\r
149 * \brief Initializes the flash driver.
\r
151 * \param dwMCk Master clock frequency in Hz.
\r
152 * \param dwUseIAP 0: use EEFC controller interface, 1: use IAP interface.
\r
153 * dwUseIAP should be set to 1 when running out of flash.
\r
156 extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP )
\r
158 dwMCk = dwMCk; /* avoid warnings */
\r
160 EFC_DisableFrdyIt( EFC ) ;
\r
161 _dwUseIAP = dwUseIAP ;
\r
165 * \brief Erases the entire flash.
\r
167 * \param dwAddress Flash start address.
\r
168 * \return 0 if successful; otherwise returns an error code.
\r
170 extern uint32_t FLASHD_Erase( uint32_t dwAddress )
\r
177 assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
\r
179 /* Translate write address */
\r
180 EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
\r
181 dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EA, 0, _dwUseIAP ) ;
\r
187 * \brief Erases flash by sector.
\r
189 * \param dwAddress Start address of be erased sector.
\r
191 * \return 0 if successful; otherwise returns an error code.
\r
193 extern uint32_t FLASHD_EraseSector( uint32_t dwAddress )
\r
200 assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
\r
202 /* Translate write address */
\r
203 EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
\r
204 dwError = EFC_PerformCommand( pEfc, EFC_FCMD_ES, wPage, _dwUseIAP ) ;
\r
210 * \brief Erases flash by pages.
\r
212 * \param dwAddress Start address of be erased pages.
\r
213 * \param dwPageNum Number of pages to be erased with EPA command (4, 8, 16, 32)
\r
215 * \return 0 if successful; otherwise returns an error code.
\r
217 extern uint32_t FLASHD_ErasePages( uint32_t dwAddress, uint32_t dwPageNum )
\r
223 static uint32_t dwFarg ;
\r
225 assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
\r
227 /* Translate write address */
\r
228 EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
\r
230 /* Get FARG field for EPA command:
\r
231 * The first page to be erased is specified in the FARG[15:2] field of
\r
232 * the MC_FCR register. The first page number must be modulo 4, 8,16 or 32
\r
233 * according to the number of pages to erase at the same time.
\r
235 * The 2 lowest bits of the FARG field define the number of pages to
\r
236 * be erased (FARG[1:0]).
\r
238 if (dwPageNum == 32)
\r
240 wPage &= ~(32u - 1u);
\r
241 dwFarg = (wPage << 2) | 3; /* 32 pages */
\r
243 else if (dwPageNum == 16)
\r
245 wPage &= ~(16u - 1u);
\r
246 dwFarg = (wPage << 2) | 2; /* 16 pages */
\r
248 else if (dwPageNum == 8)
\r
250 wPage &= ~(8u - 1u);
\r
251 dwFarg = (wPage << 2) | 1; /* 8 pages */
\r
255 wPage &= ~(4u - 1u);
\r
256 dwFarg = (wPage << 2) | 0; /* 4 pages */
\r
259 dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EPA, dwFarg, _dwUseIAP ) ;
\r
266 * \brief Writes a data buffer in the internal flash
\r
268 * \note This function works in polling mode, and thus only returns when the
\r
269 * data has been effectively written.
\r
270 * \param address Write address.
\r
271 * \param pBuffer Data buffer.
\r
272 * \param size Size of data buffer in bytes.
\r
273 * \return 0 if successful, otherwise returns an error code.
\r
275 extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize )
\r
280 uint32_t writeSize ;
\r
281 uint32_t pageAddress ;
\r
285 uint32_t *pAlignedDestination ;
\r
286 uint8_t *pucPageBuffer = (uint8_t *)_pdwPageBuffer;
\r
288 assert( pvBuffer ) ;
\r
289 assert( dwAddress >=IFLASH_ADDR ) ;
\r
290 assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
\r
292 /* Translate write address */
\r
293 EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ;
\r
295 /* Write all pages */
\r
296 while ( dwSize > 0 )
\r
298 /* Copy data in temporary buffer to avoid alignment problems */
\r
299 writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ;
\r
300 EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ;
\r
301 padding = IFLASH_PAGE_SIZE - offset - writeSize ;
\r
303 /* Pre-buffer data */
\r
304 memcpy( pucPageBuffer, (void *) pageAddress, offset);
\r
307 memcpy( pucPageBuffer + offset, pvBuffer, writeSize);
\r
309 /* Post-buffer data */
\r
310 memcpy( pucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding);
\r
313 * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption
\r
315 pAlignedDestination = (uint32_t*)pageAddress ;
\r
316 for (dwIdx = 0; dwIdx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); ++ dwIdx) {
\r
317 *pAlignedDestination++ = _pdwPageBuffer[dwIdx];
\r
320 /* Note for sam3s16 and sam4s:
\r
321 * It is not possible to use Erase and write Command (EWP) on all Flash (this
\r
322 * command is available on the First 2 Small Sector, 16K Bytes). For the next
\r
323 * block, Erase them first then use Write page command.
\r
325 /* Send writing command */
\r
326 dwError = EFC_PerformCommand( pEfc, EFC_FCMD_WP, page, _dwUseIAP ) ;
\r
333 pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ;
\r
334 dwSize -= writeSize ;
\r
342 * \brief Locks all the regions in the given address range. The actual lock range is
\r
343 * reported through two output parameters.
\r
345 * \param start Start address of lock range.
\r
346 * \param end End address of lock range.
\r
347 * \param pActualStart Start address of the actual lock range (optional).
\r
348 * \param pActualEnd End address of the actual lock range (optional).
\r
349 * \return 0 if successful, otherwise returns an error code.
\r
351 extern uint32_t FLASHD_Lock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd )
\r
354 uint32_t actualStart, actualEnd ;
\r
355 uint16_t startPage, endPage ;
\r
357 uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
\r
359 /* Compute actual lock range and store it */
\r
360 ComputeLockRange( start, end, &actualStart, &actualEnd ) ;
\r
361 if ( pActualStart != NULL )
\r
363 *pActualStart = actualStart ;
\r
365 if ( pActualEnd != NULL )
\r
367 *pActualEnd = actualEnd;
\r
370 /* Compute page numbers */
\r
371 EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;
\r
372 EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;
\r
374 /* Lock all pages */
\r
375 while ( startPage < endPage )
\r
377 dwError = EFC_PerformCommand( pEfc, EFC_FCMD_SLB, startPage, _dwUseIAP ) ;
\r
382 startPage += numPagesInRegion;
\r
389 * \brief Unlocks all the regions in the given address range. The actual unlock range is
\r
390 * reported through two output parameters.
\r
391 * \param start Start address of unlock range.
\r
392 * \param end End address of unlock range.
\r
393 * \param pActualStart Start address of the actual unlock range (optional).
\r
394 * \param pActualEnd End address of the actual unlock range (optional).
\r
395 * \return 0 if successful, otherwise returns an error code.
\r
397 extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd )
\r
400 uint32_t actualStart, actualEnd ;
\r
401 uint16_t startPage, endPage ;
\r
403 uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
\r
405 /* Compute actual unlock range and store it */
\r
406 ComputeLockRange(start, end, &actualStart, &actualEnd);
\r
407 if ( pActualStart != NULL )
\r
409 *pActualStart = actualStart ;
\r
411 if ( pActualEnd != NULL )
\r
413 *pActualEnd = actualEnd ;
\r
416 /* Compute page numbers */
\r
417 EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;
\r
418 EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;
\r
420 /* Unlock all pages */
\r
421 while ( startPage < endPage )
\r
423 dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ;
\r
428 startPage += numPagesInRegion ;
\r
434 * \brief Returns the number of locked regions inside the given address range.
\r
436 * \param start Start address of range
\r
437 * \param end End address of range.
\r
439 extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end )
\r
443 uint16_t startPage, endPage ;
\r
444 uint8_t startRegion, endRegion ;
\r
445 uint32_t numPagesInRegion ;
\r
446 uint32_t status[IFLASH_NB_OF_LOCK_BITS / 32u] ;
\r
447 uint32_t numLockedRegions = 0 ;
\r
449 assert( end >= start ) ;
\r
450 assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ;
\r
452 /* Compute page numbers */
\r
453 EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ;
\r
454 EFC_TranslateAddress( 0, end, &endPage, 0 ) ;
\r
456 /* Compute region numbers */
\r
457 numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;
\r
458 startRegion = startPage / numPagesInRegion ;
\r
459 endRegion = endPage / numPagesInRegion ;
\r
460 if ((endPage % numPagesInRegion) != 0)
\r
465 /* Retrieve lock status */
\r
466 EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ;
\r
467 for (i = 0; i < (IFLASH_NB_OF_LOCK_BITS / 32u); i++)
\r
469 status[i] = EFC_GetResult( pEfc ) ;
\r
472 /* Check status of each involved region */
\r
473 while ( startRegion < endRegion )
\r
475 i = startRegion / 32u;
\r
476 j = startRegion % 32u;
\r
477 if ( (status[i] & (1 << j)) != 0 )
\r
479 numLockedRegions++ ;
\r
484 return numLockedRegions ;
\r
488 * \brief Check if the given GPNVM bit is set or not.
\r
490 * \param gpnvm GPNVM bit index.
\r
491 * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0.
\r
493 extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM )
\r
495 uint32_t dwStatus ;
\r
497 assert( ucGPNVM < GPNVM_NUM_MAX ) ;
\r
499 /* Get GPNVMs status */
\r
500 EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ;
\r
501 dwStatus = EFC_GetResult( EFC ) ;
\r
503 /* Check if GPNVM is set */
\r
504 if ( (dwStatus & (1 << ucGPNVM)) != 0 )
\r
515 * \brief Sets the selected GPNVM bit.
\r
517 * \param gpnvm GPNVM bit index.
\r
518 * \returns 0 if successful; otherwise returns an error code.
\r
520 extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM )
\r
522 assert( ucGPNVM < GPNVM_NUM_MAX ) ;
\r
524 if ( !FLASHD_IsGPNVMSet( ucGPNVM ) )
\r
526 return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ;
\r
535 * \brief Clears the selected GPNVM bit.
\r
537 * \param gpnvm GPNVM bit index.
\r
538 * \returns 0 if successful; otherwise returns an error code.
\r
540 extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM )
\r
542 assert( ucGPNVM < GPNVM_NUM_MAX ) ;
\r
544 if ( FLASHD_IsGPNVMSet( ucGPNVM ) )
\r
546 return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ;
\r
555 * \brief Read the unique ID.
\r
557 * \param pdwUniqueID pointer on a 4bytes char containing the unique ID value.
\r
558 * \returns 0 if successful; otherwise returns an error code.
\r
561 extern __ramfunc uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )
\r
563 __attribute__ ((section (".ramfunc")))
\r
564 uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )
\r
568 if (pdwUniqueID == NULL) {
\r
572 pdwUniqueID[0] = 0 ;
\r
573 pdwUniqueID[1] = 0 ;
\r
574 pdwUniqueID[2] = 0 ;
\r
575 pdwUniqueID[3] = 0 ;
\r
577 /* Send the Start Read unique Identifier command (STUI) by writing the Flash
\r
578 Command Register with the STUI command.*/
\r
579 EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EFC_FCMD_STUI;
\r
581 /* When the Unique Identifier is ready to be read, the FRDY bit in the Flash
\r
582 Programming Status Register (EEFC_FSR) falls. */
\r
585 status = EFC->EEFC_FSR ;
\r
586 } while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY ) ;
\r
588 /* The Unique Identifier is located in the first 128 bits of the Flash
\r
589 memory mapping. So, at the address 0x400000-0x40000F. */
\r
590 pdwUniqueID[0] = *(uint32_t *)IFLASH_ADDR;
\r
591 pdwUniqueID[1] = *(uint32_t *)(IFLASH_ADDR + 4);
\r
592 pdwUniqueID[2] = *(uint32_t *)(IFLASH_ADDR + 8);
\r
593 pdwUniqueID[3] = *(uint32_t *)(IFLASH_ADDR + 12);
\r
595 /* To stop the Unique Identifier mode, the user needs to send the Stop Read
\r
596 unique Identifier command (SPUI) by writing the Flash Command Register
\r
597 with the SPUI command. */
\r
598 EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EFC_FCMD_SPUI ;
\r
600 /* When the Stop read Unique Unique Identifier command (SPUI) has been
\r
601 performed, the FRDY bit in the Flash Programming Status Register (EEFC_FSR)
\r
605 status = EFC->EEFC_FSR ;
\r
606 } while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;
\r