1 /* ----------------------------------------------------------------------------
\r
2 * ATMEL Microcontroller Software Support
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2008, 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
31 #define trace_LEVEL trace_INFO
\r
34 //------------------------------------------------------------------------------
\r
36 //------------------------------------------------------------------------------
\r
40 #ifdef BOARD_FLASH_EFC
\r
42 #include <utility/assert.h>
\r
43 #include <utility/trace.h>
\r
45 //------------------------------------------------------------------------------
\r
46 // Local definitions
\r
47 //------------------------------------------------------------------------------
\r
49 // Round a number to the nearest integral value (number must have been
\r
50 // multiplied by 10, e.g. to round 10.3 enter 103).
\r
51 #define ROUND(n) ((((n) % 10) >= 5) ? (((n) / 10) + 1) : ((n) / 10))
\r
53 // Returns the FMCN field value when manipulating lock bits, given MCK.
\r
54 #if defined(at91sam7a3)
\r
55 #define FMCN_BITS(mck) (ROUND((mck) / 100000) << 16) // <- Not correct according to the datasheet but it works
\r
57 #define FMCN_BITS(mck) (ROUND((mck) / 100000) << 16)
\r
60 // Returns the FMCN field value when manipulating the rest of the flash.
\r
61 #define FMCN_FLASH(mck) ((((mck) / 2000000) * 3) << 16)
\r
63 //------------------------------------------------------------------------------
\r
65 //------------------------------------------------------------------------------
\r
68 /// Master clock frequency, used to infer the value of the FMCN field.
\r
69 static unsigned int lMck;
\r
70 /// Calculated value of the FMCN field base on Master clock frequency.
\r
71 static unsigned int lMckFMCN;
\r
73 //------------------------------------------------------------------------------
\r
75 //------------------------------------------------------------------------------
\r
77 //------------------------------------------------------------------------------
\r
78 /// Sets the system master clock so the FMCN field of the EFC(s) can be
\r
79 /// programmed properly.
\r
80 /// \param mck Master clock frequency in Hz.
\r
81 //------------------------------------------------------------------------------
\r
82 void EFC_SetMasterClock(unsigned int mck)
\r
85 lMckFMCN = FMCN_BITS(lMck);
\r
88 //------------------------------------------------------------------------------
\r
89 /// Enables the given interrupt sources on an EFC peripheral.
\r
90 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
91 /// \param sources Interrupt sources to enable.
\r
92 //------------------------------------------------------------------------------
\r
93 void EFC_EnableIt(AT91S_EFC *pEfc, unsigned int sources)
\r
96 SANITY_CHECK((sources & ~0x0000000D) == 0);
\r
98 pEfc->EFC_FMR |= sources;
\r
101 //------------------------------------------------------------------------------
\r
102 /// Disables the given interrupt sources on an EFC peripheral.
\r
103 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
104 /// \param sources Interrupt sources to disable.
\r
105 //------------------------------------------------------------------------------
\r
106 void EFC_DisableIt(AT91S_EFC *pEfc, unsigned int sources)
\r
108 SANITY_CHECK(pEfc);
\r
109 SANITY_CHECK((sources & ~(AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE)) == 0);
\r
111 pEfc->EFC_FMR &= ~sources;
\r
114 //------------------------------------------------------------------------------
\r
115 /// Enables or disable the "Erase before programming" feature of an EFC.
\r
116 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
117 /// \param enable If 1, the feature is enabled; otherwise it is disabled.
\r
118 //------------------------------------------------------------------------------
\r
119 void EFC_SetEraseBeforeProgramming(AT91S_EFC *pEfc, unsigned char enable)
\r
121 SANITY_CHECK(pEfc);
\r
125 pEfc->EFC_FMR &= ~AT91C_MC_NEBP;
\r
129 pEfc->EFC_FMR |= AT91C_MC_NEBP;
\r
133 //------------------------------------------------------------------------------
\r
134 /// Translates the given address into EFC, page and offset values. The resulting
\r
135 /// values are stored in the provided variables if they are not null.
\r
136 /// \param address Address to translate.
\r
137 /// \param ppEfc Pointer to target EFC peripheral.
\r
138 /// \param pPage First page accessed.
\r
139 /// \param pOffset Byte offset in first page.
\r
140 //------------------------------------------------------------------------------
\r
141 void EFC_TranslateAddress(
\r
142 unsigned int address,
\r
144 unsigned short *pPage,
\r
145 unsigned short *pOffset)
\r
148 unsigned short page;
\r
149 unsigned short offset;
\r
151 SANITY_CHECK(address >= AT91C_IFLASH);
\r
152 SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
\r
154 #if defined(AT91C_BASE_EFC0)
\r
155 if (address >= (AT91C_IFLASH + AT91C_IFLASH_SIZE / 2)) {
\r
157 pEfc = AT91C_BASE_EFC1;
\r
158 page = (address - AT91C_IFLASH - AT91C_IFLASH_SIZE / 2) / AT91C_IFLASH_PAGE_SIZE;
\r
159 offset = (address - AT91C_IFLASH - AT91C_IFLASH_SIZE / 2) % AT91C_IFLASH_PAGE_SIZE;
\r
163 pEfc = AT91C_BASE_EFC0;
\r
164 page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
\r
165 offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
\r
168 pEfc = AT91C_BASE_EFC;
\r
169 page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
\r
170 offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
\r
172 trace_LOG(trace_DEBUG,
\r
173 "-D- Translated 0x%08X to EFC=0x%08X, page=%d and offset=%d\n\r",
\r
174 address, (unsigned int) pEfc, page, offset);
\r
191 //------------------------------------------------------------------------------
\r
192 /// Computes the address of a flash access given the EFC, page and offset.
\r
193 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
194 /// \param page Page number.
\r
195 /// \param offset Byte offset inside page.
\r
196 /// \param pAddress Computed address (optional).
\r
197 //------------------------------------------------------------------------------
\r
198 void EFC_ComputeAddress(
\r
200 unsigned short page,
\r
201 unsigned short offset,
\r
202 unsigned int *pAddress)
\r
204 unsigned int address;
\r
206 SANITY_CHECK(pEfc);
\r
207 #if defined(AT91C_BASE_EFC1)
\r
208 SANITY_CHECK(page <= (AT91C_IFLASH_NB_OF_PAGES / 2));
\r
210 SANITY_CHECK(page <= AT91C_IFLASH_NB_OF_PAGES);
\r
212 SANITY_CHECK(offset < AT91C_IFLASH_PAGE_SIZE);
\r
215 address = AT91C_IFLASH + page * AT91C_IFLASH_PAGE_SIZE + offset;
\r
216 #if defined(AT91C_BASE_EFC1)
\r
217 if (pEfc == AT91C_BASE_EFC1) {
\r
219 address += AT91C_IFLASH_SIZE / 2;
\r
226 *pAddress = address;
\r
230 //------------------------------------------------------------------------------
\r
231 /// Starts the executing the given command on an EFC. This function returns
\r
232 /// as soon as the command is started. It does NOT set the FMCN field automatically.
\r
233 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
234 /// \param command Command to execute.
\r
235 /// \param argument Command argument (should be 0 if not used).
\r
236 //------------------------------------------------------------------------------
\r
237 void EFC_StartCommand(
\r
239 unsigned char command,
\r
240 unsigned short argument)
\r
242 SANITY_CHECK(pEfc);
\r
243 ASSERT(lMck != 0, "-F- Master clock not set.\n\r");
\r
245 // Check command & argument
\r
248 case AT91C_MC_FCMD_PROG_AND_LOCK:
\r
249 ASSERT(0, "-F- Write and lock command cannot be carried out.\n\r");
\r
252 case AT91C_MC_FCMD_START_PROG:
\r
253 case AT91C_MC_FCMD_LOCK:
\r
254 case AT91C_MC_FCMD_UNLOCK:
\r
255 ASSERT(argument < AT91C_IFLASH_NB_OF_PAGES,
\r
256 "-F- Maximum number of pages is %d (argument was %d)\n\r",
\r
257 AT91C_IFLASH_NB_OF_PAGES,
\r
261 #if (EFC_NUM_GPNVMS > 0)
\r
262 case AT91C_MC_FCMD_SET_GP_NVM:
\r
263 case AT91C_MC_FCMD_CLR_GP_NVM:
\r
264 ASSERT(argument < EFC_NUM_GPNVMS, "-F- A maximum of %d GPNVMs are available on the chip.\n\r", EFC_NUM_GPNVMS);
\r
268 case AT91C_MC_FCMD_ERASE_ALL:
\r
270 #if !defined(EFC_NO_SECURITY_BIT)
\r
271 case AT91C_MC_FCMD_SET_SECURITY:
\r
273 ASSERT(argument == 0, "-F- Argument is meaningless for the given command\n\r");
\r
276 default: ASSERT(0, "-F- Unknown command %d\n\r", command);
\r
282 case AT91C_MC_FCMD_LOCK:
\r
283 case AT91C_MC_FCMD_UNLOCK:
\r
284 #if (EFC_NUM_GPNVMS > 0)
\r
285 case AT91C_MC_FCMD_SET_GP_NVM:
\r
286 case AT91C_MC_FCMD_CLR_GP_NVM:
\r
288 #if !defined(EFC_NO_SECURITY_BIT)
\r
289 case AT91C_MC_FCMD_SET_SECURITY:
\r
291 pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
\r
294 case AT91C_MC_FCMD_START_PROG:
\r
295 case AT91C_MC_FCMD_ERASE_ALL:
\r
296 pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
\r
301 ASSERT((pEfc->EFC_FSR & AT91C_MC_FRDY) != 0, "-F- Efc is not ready\n\r");
\r
302 pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
\r
305 //------------------------------------------------------------------------------
\r
306 /// Performs the given command and wait until its completion (or an error).
\r
307 /// Returns 0 if successful; otherwise returns an error code.
\r
308 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
309 /// \param command Command to perform.
\r
310 /// \param argument Optional command argument.
\r
311 //------------------------------------------------------------------------------
\r
315 __attribute__ ((section (".ramfunc")))
\r
317 unsigned char EFC_PerformCommand(
\r
319 unsigned char command,
\r
320 unsigned short argument)
\r
322 unsigned int status;
\r
327 case AT91C_MC_FCMD_LOCK:
\r
328 case AT91C_MC_FCMD_UNLOCK:
\r
329 #if (EFC_NUM_GPNVMS > 0)
\r
330 case AT91C_MC_FCMD_SET_GP_NVM:
\r
331 case AT91C_MC_FCMD_CLR_GP_NVM:
\r
333 #if !defined(EFC_NO_SECURITY_BIT)
\r
334 case AT91C_MC_FCMD_SET_SECURITY:
\r
336 pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
\r
339 case AT91C_MC_FCMD_START_PROG:
\r
340 case AT91C_MC_FCMD_ERASE_ALL:
\r
341 pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
\r
345 #ifdef BOARD_FLASH_IAP_ADDRESS
\r
346 // Pointer on IAP function in ROM
\r
347 static void (*IAP_PerformCommand)(unsigned int, unsigned int);
\r
348 unsigned int index = 0;
\r
349 #ifdef AT91C_BASE_EFC1
\r
350 if (pEfc == AT91C_BASE_EFC1) {
\r
355 IAP_PerformCommand = (void (*)(unsigned int, unsigned int)) *((unsigned int *) BOARD_FLASH_IAP_ADDRESS);
\r
357 // Check if IAP function is implemented (opcode in SWI != 'b' or 'ldr') */
\r
358 if ((((((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xEA) &&
\r
359 (((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xE5)) {
\r
361 IAP_PerformCommand(index, (0x5A << 24) | (argument << 8) | command);
\r
362 return (pEfc->EFC_FSR & (AT91C_MC_LOCKE | AT91C_MC_PROGE));
\r
366 pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
\r
369 status = pEfc->EFC_FSR;
\r
371 while ((status & AT91C_MC_FRDY) == 0);
\r
373 return (status & (AT91C_MC_PROGE | AT91C_MC_LOCKE));
\r
376 //------------------------------------------------------------------------------
\r
377 /// Returns the current status of an EFC. Keep in mind that this function clears
\r
378 /// the value of some status bits (LOCKE, PROGE).
\r
379 /// \param pEfc Pointer to an AT91S_EFC structure.
\r
380 //------------------------------------------------------------------------------
\r
381 unsigned int EFC_GetStatus(AT91S_EFC *pEfc)
\r
383 return pEfc->EFC_FSR;
\r
386 #endif //#ifdef BOARD_FLASH_EFC
\r