]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/flash/atmel/at49xxxx/v2_0/include/flash_at49xxxx.inl
Initial revision
[karo-tx-redboot.git] / packages / devs / flash / atmel / at49xxxx / v2_0 / include / flash_at49xxxx.inl
1 #ifndef CYGONCE_DEVS_FLASH_ATMEL_AT49XXXX_INL
2 #define CYGONCE_DEVS_FLASH_ATMEL_AT49XXXX_INL
3 //==========================================================================
4 //
5 //      at49xxxx.inl
6 //
7 //      Atmel AT49xxxx series flash driver
8 //
9 //==========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 // Copyright (C) 2003 Jonathan Larmour
15 // Copyright (C) 2003 Gary Thomas
16 //
17 // eCos is free software; you can redistribute it and/or modify it under
18 // the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 or (at your option) any later version.
20 //
21 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
22 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24 // for more details.
25 //
26 // You should have received a copy of the GNU General Public License along
27 // with eCos; if not, write to the Free Software Foundation, Inc.,
28 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
29 //
30 // As a special exception, if other files instantiate templates or use macros
31 // or inline functions from this file, or you compile this file and link it
32 // with other works to produce a work based on this file, this file does not
33 // by itself cause the resulting work to be covered by the GNU General Public
34 // License. However the source code for this file must still be made available
35 // in accordance with section (3) of the GNU General Public License.
36 //
37 // This exception does not invalidate any other reasons why a work based on
38 // this file might be covered by the GNU General Public License.
39 //
40 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
41 // at http://sources.redhat.com/ecos/ecos-license/
42 // -------------------------------------------
43 //####ECOSGPLCOPYRIGHTEND####
44
45 //==========================================================================
46 //#####DESCRIPTIONBEGIN####
47 //
48 // Author(s):    Jani Monoses <jani@iv.ro>
49 // Contributors: Cristian Vlasin <cris@iv.ro>, tdrury, jlarmour
50 //               J. Tinembart
51 // Date:         2002-06-24
52 // Purpose:
53 // Description:
54 //
55 //####DESCRIPTIONEND####
56 //
57 //==========================================================================
58
59 #include <pkgconf/hal.h>
60 #include <pkgconf/devs_flash_atmel_at49xxxx.h>
61 #include <cyg/hal/hal_arch.h>
62 #include <cyg/hal/hal_cache.h>
63 #include <cyg/hal/hal_diag.h>
64 #include CYGHWR_MEMORY_LAYOUT_H
65
66 #define  _FLASH_PRIVATE_
67 #include <cyg/io/flash.h>
68
69
70 //----------------------------------------------------------------------------
71 // Common device details.
72 #define FLASH_Read_ID                   FLASHWORD( 0x90 )
73 #define FLASH_Read_ID_Exit              FLASHWORD( 0xF0 )
74 #define FLASH_Program                   FLASHWORD( 0xA0 )
75 #define FLASH_Sector_Erase              FLASHWORD( 0x30 )
76 #define FLASH_Chip_Erase                FLASHWORD( 0x10 )
77
78 #define FLASH_Busy                      FLASHWORD( 0x40 ) // "Toggle" bit, I/O 6
79 #define FLASH_InverseData               FLASHWORD( 0x80 ) // I/O 7, Inverse data
80
81 #ifdef CYGHWR_DEVS_FLASH_ATMEL_AT49LV161
82 #define FLASH_Setup_Addr1               (0x555)
83 #define FLASH_Setup_Addr2               (0xAAA)
84 #else
85 #define FLASH_Setup_Addr1               (0x5555)
86 #define FLASH_Setup_Addr2               (0x2AAA)
87 #endif
88 #define FLASH_Setup_Code1               FLASHWORD( 0xAA )
89 #define FLASH_Setup_Code2               FLASHWORD( 0x55 )
90 #define FLASH_Setup_Erase               FLASHWORD( 0x80 )
91
92 #define CYGNUM_FLASH_BLANK             (1)
93
94 #ifndef CYGNUM_FLASH_ID_MANUFACTURER
95 # define CYGNUM_FLASH_ID_MANUFACTURER  FLASHWORD(0x1F)
96 #endif
97
98 //----------------------------------------------------------------------------
99 // Now that device properties are defined, include magic for defining
100 // accessor type and constants.
101 #include <cyg/io/flash_dev.h>
102
103 //----------------------------------------------------------------------------
104 // Information about supported devices
105 typedef struct flash_dev_info {
106     flash_data_t device_id;
107 #ifdef CYG_FLASH_LONG_DEVICE_NEEDED
108     cyg_bool     long_device_id;
109     flash_data_t device_id2;
110     flash_data_t device_id3;
111 #endif
112     cyg_uint32   block_size;
113     cyg_int32    block_count;
114     cyg_uint32   base_mask;
115     cyg_uint32   device_size;
116     cyg_bool     bootblock;
117     cyg_bool     chip_erase;
118     cyg_uint32   bootblocks[64];         // 0 is bootblock offset, 1-11 sub-sector sizes (or 0)
119 #ifdef NOTYET // FIXME: not supported yet (use am29xxxxx for template)
120     cyg_bool     banked;
121     cyg_uint32   banks[8];               // bank offsets, highest to lowest (lowest should be 0)
122                                          // (only one entry for now, increase to support devices
123                                          // with more banks).
124 #endif
125 } flash_dev_info_t;
126
127 static const flash_dev_info_t* flash_dev_info;
128 static const flash_dev_info_t supported_devices[] = {
129 #include <cyg/io/flash_at49xxxx_parts.inl>
130 };
131 #define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
132
133 //----------------------------------------------------------------------------
134 // Functions that put the flash device into non-read mode must reside
135 // in RAM.
136 void flash_query(void* data) __attribute__ ((section (".2ram.flash_query")));
137 int  flash_erase_block(void* block, unsigned int size)
138     __attribute__ ((section (".2ram.flash_erase_block")));
139 int  flash_program_buf(void* addr, void* data, int len)
140     __attribute__ ((section (".2ram.flash_program_buf")));
141 static int wait_while_busy(int timeout, volatile flash_data_t* addr_ptr, flash_data_t value)
142     __attribute__ ((section (".2ram.text")));
143
144 //----------------------------------------------------------------------------
145 // Initialize driver details
146 int
147 flash_hwr_init(void)
148 {
149     flash_data_t id[4];
150     int i;
151
152 #ifdef CYGHWR_FLASH_AT49XXXX_PLF_INIT
153     CYGHWR_FLASH_AT49XXXX_PLF_INIT();
154 #endif
155
156     flash_dev_query(id);
157
158     // Check that flash_id data is matching the one the driver was
159     // configured for.
160
161     // Check manufacturer
162     if (id[0] != CYGNUM_FLASH_ID_MANUFACTURER)
163         return FLASH_ERR_DRV_WRONG_PART;
164
165     // Look through table for device data
166     flash_dev_info = supported_devices;
167 #ifdef CYG_FLASH_LONG_DEVICE_NEEDED
168     for (i = 0; i < NUM_DEVICES; i++) {
169         if (!flash_dev_info->long_device_id && flash_dev_info->device_id == id[1])
170             break;
171         else if ( flash_dev_info->long_device_id && flash_dev_info->device_id == id[1] 
172                   && flash_dev_info->device_id2 == id[2] 
173                   && flash_dev_info->device_id3 == id[3] )
174             break;
175         flash_dev_info++;
176     }
177 #else
178     for (i = 0; i < NUM_DEVICES; i++) {
179         if (flash_dev_info->device_id == id[1])
180             break;
181         flash_dev_info++;
182     }
183 #endif
184
185     // Did we find the device? If not, return error.
186     if (NUM_DEVICES == i)
187         return FLASH_ERR_DRV_WRONG_PART;
188
189     // Hard wired for now
190     flash_info.block_size = flash_dev_info->block_size;
191     flash_info.blocks = flash_dev_info->block_count * CYGNUM_FLASH_SERIES;
192     flash_info.start = (void *)CYGNUM_FLASH_BASE;
193     flash_info.end = (void *)(CYGNUM_FLASH_BASE+ (flash_dev_info->device_size * CYGNUM_FLASH_SERIES));
194     return FLASH_ERR_OK;
195 }
196
197 //----------------------------------------------------------------------------
198 // Map a hardware status to a package error
199 int
200 flash_hwr_map_error(int e)
201 {
202     return e;
203 }
204
205
206 //----------------------------------------------------------------------------
207 // See if a range of FLASH addresses overlaps currently running code
208 bool
209 flash_code_overlaps(void *start, void *end)
210 {
211     extern unsigned char _stext[], _etext[];
212
213     return ((((unsigned long)&_stext >= (unsigned long)start) &&
214              ((unsigned long)&_stext < (unsigned long)end)) ||
215             (((unsigned long)&_etext >= (unsigned long)start) &&
216              ((unsigned long)&_etext < (unsigned long)end)));
217 }
218
219 //----------------------------------------------------------------------------
220 // Flash Query
221 //
222 // Only reads the manufacturer and part number codes for the first
223 // device(s) in series. It is assumed that any devices in series
224 // will be of the same type.
225
226 void
227 flash_query(void* data)
228 {
229     volatile flash_data_t *ROM;
230     flash_data_t* id = (flash_data_t*) data;
231
232     ROM = (volatile flash_data_t*) CYGNUM_FLASH_BASE;
233
234     ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
235     ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
236     ROM[FLASH_Setup_Addr1] = FLASH_Read_ID;
237
238     // FIXME: 10ms delay?
239
240     // Manufacturers' code
241     id[0] = ROM[0];
242     // Part number
243     id[1] = ROM[1];
244
245     ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
246     ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
247     ROM[FLASH_Setup_Addr1] = FLASH_Read_ID_Exit;
248
249     // FIXME: 10ms delay?
250 }
251
252 // Wait for completion. While programming/erasing check
253 // that i/o 7 is inverse of data as described in Atmels examples.
254
255 static int wait_while_busy(int timeout, volatile flash_data_t* addr_ptr, flash_data_t expected)
256 {
257         int val;
258         flash_data_t state;
259         while (true) {
260             state = *addr_ptr & FLASH_InverseData;
261             if (state==(expected&FLASH_InverseData)) {
262                 val=FLASH_ERR_OK;
263                 break;
264             }
265             if (--timeout == 0) {
266                 val=FLASH_ERR_DRV_TIMEOUT;
267                 break;
268             }
269         }
270         return val;
271 }
272
273 //----------------------------------------------------------------------------
274 // Erase Block
275 int
276 flash_erase_block(void* block, unsigned int size)
277 {
278     volatile flash_data_t* ROM;
279     volatile flash_data_t* b_p = (volatile flash_data_t*) block;
280
281     int res = FLASH_ERR_OK;
282     unsigned int len = 0;
283     cyg_bool bootblock = false;
284     cyg_uint32 *bootblocks = (cyg_uint32 *)0;
285
286     //  diag_printf("\nERASE: Block %p, size: %u\n",block,size);
287
288     // Base address of device(s) being programmed.
289     ROM = (volatile flash_data_t*) ((unsigned long)block & flash_dev_info->base_mask);
290
291
292 #if defined(CYGHWR_DEVS_FLASH_ATMEL_AT49XXXX_ERASE_BUG_WORKAROUND)
293
294     // Before erasing the data, overwrite it with all zeroes. This is a workaround
295     // for a silicon bug that affects erasing of some devices, see
296     // http://www.atmel.com/dyn/resources/prod_documents/doc6076.pdf.
297     for (len = size / sizeof *b_p; (FLASH_ERR_OK == res) && (len > 0); len--, b_p++) {
298         // Program data [byte] - 4 step sequence
299         ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
300         ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
301         ROM[FLASH_Setup_Addr1] = FLASH_Program;
302         *b_p = 0;
303                 
304         res = wait_while_busy(5000000, b_p, 0);
305
306         if (*b_p != 0)
307             // Only update return value if operation was OK
308             if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
309     }
310     
311     if (FLASH_ERR_OK != res)
312         return res;
313     
314     b_p = (volatile flash_data_t*) block;
315
316 #endif // defined(CYGHWR_DEVS_FLASH_ATMEL_AT49XXXX_ERASE_BUG_WORKAROUND)
317
318     // Assume not "boot" sector, full size
319     bootblock = false;
320     len = flash_dev_info->block_size;
321         
322     // Is this in a "boot" sector?
323     if (flash_dev_info->bootblock) {
324         bootblocks = (cyg_uint32 *)&flash_dev_info->bootblocks[0];
325         while (*bootblocks != _LAST_BOOTBLOCK) {
326             if (*bootblocks++ == ((unsigned long)block - (unsigned long)ROM)) {
327                 len = *bootblocks++;  // Size of first sub-block
328                 bootblock = true;
329                 //      diag_printf("\nERASE: Is Boot block - size: %d, ptr %p\n",len,b_p);
330                 break;
331             } else {
332                 int ls = flash_dev_info->block_size;
333                 // Skip over segment
334                 while ((ls -= *bootblocks++) > 0) ;
335             }
336         }
337     }
338
339     while (size > 0) {
340         //Erase sector 6-byte sequence
341         ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
342         ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
343         ROM[FLASH_Setup_Addr1] = FLASH_Setup_Erase;
344         ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
345         ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
346         if (flash_dev_info->chip_erase) {
347             // Can only erase the entire device!
348             if (b_p == ROM) {
349                 ROM[FLASH_Setup_Addr1] = FLASH_Chip_Erase;
350             } else {
351                 res = FLASH_ERR_DRV_VERIFY;
352             }
353         } else {
354             *b_p = FLASH_Sector_Erase;
355         }
356
357         size -= len;  // This much has been erased
358
359         res = wait_while_busy(66000000, b_p, FLASH_BlankValue);
360
361         // Verify erase operation
362         if (FLASH_ERR_OK == res) {
363             while (len > 0) {
364                 if (*b_p != FLASH_BlankValue) {
365                     break;
366                 }
367                 len -= sizeof(*b_p);
368                 b_p++;
369             }                    
370         }
371                     
372         if (FLASH_ERR_OK != res)
373             break;
374
375         if (bootblock) {
376             len = *bootblocks++;
377             //  diag_printf("\nERASE: Is Boot block - size: %d, len %d, ptr %p\n",size,len,b_p);
378         }
379     }
380     return res;
381 }
382
383 //----------------------------------------------------------------------------
384 // Program Buffer
385 int
386 flash_program_buf(void* addr, void* data, int len)
387 {
388     volatile flash_data_t* ROM;
389     volatile flash_data_t* addr_ptr = (volatile flash_data_t*) addr;
390     volatile flash_data_t* data_ptr = (volatile flash_data_t*) data;
391     int res = FLASH_ERR_OK;
392         
393     // check the address is suitably aligned
394     if ((unsigned long)addr & (CYGNUM_FLASH_INTERLEAVE * CYGNUM_FLASH_WIDTH / 8 - 1))
395         return FLASH_ERR_INVALID;
396
397     // Base address of device(s) being programmed. 
398     ROM = (volatile flash_data_t*)((unsigned long)addr_ptr & flash_dev_info->base_mask);
399
400     while ((FLASH_ERR_OK == res) && (len > 0)) {
401         // Program data [byte] - 4 step sequence
402         ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
403         ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
404         ROM[FLASH_Setup_Addr1] = FLASH_Program;
405         addr_ptr[0] = data_ptr[0];
406                 
407         res = wait_while_busy(5000000,addr_ptr, data_ptr[0]);
408
409         if (*addr_ptr++ != *data_ptr++) {
410             // Only update return value if operation was OK
411             if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
412             break;
413         }
414
415         len -= sizeof (*data_ptr);
416     }
417
418     return res;
419 }
420
421 #endif // CYGONCE_DEVS_FLASH_ATMEL_AT49XXXX_INL
422
423 // EOF flash_at49xxxx.inl