]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/flash/v2_0/src/flash.c
59725c5083fc252919b6c8ed9b85412ced7b5d5c
[karo-tx-redboot.git] / packages / io / flash / v2_0 / src / flash.c
1 //==========================================================================
2 //
3 //      flash.c
4 //
5 //      Flash programming
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-26
47 // Purpose:      
48 // Description:  
49 //              
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54 #include <pkgconf/system.h>
55 #include <pkgconf/io_flash.h>
56
57 #include <cyg/hal/hal_arch.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/hal/hal_cache.h>
60 #include <string.h>
61
62 #define  _FLASH_PRIVATE_
63 #include <cyg/io/flash.h>
64
65 // When this flag is set, do not actually jump to the relocated code.
66 // This can be used for running the function in place (RAM startup only),
67 // allowing calls to diag_printf() and similar.
68 #undef RAM_FLASH_DEV_DEBUG
69 #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
70 # warning "Can only enable the flash debugging when configured for RAM startup"
71 #endif
72
73 struct flash_info flash_info;
74
75 // These are the functions in the HW specific driver we need to call.
76 typedef void code_fun(void *);
77
78 externC code_fun flash_query;
79 externC code_fun flash_erase_block;
80 externC code_fun flash_program_buf;
81 externC code_fun flash_read_buf;
82 externC code_fun flash_lock_block;
83 externC code_fun flash_unlock_block;
84
85 int
86 flash_init(_printf *pf)
87 {
88     int err;
89
90     flash_info.pf = pf; // Do this before calling into the driver
91     if (flash_info.init) return FLASH_ERR_OK;
92
93     if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
94         return err;
95     }
96     flash_info.block_mask = ~(flash_info.block_size-1);
97     flash_info.init = 1;
98     return FLASH_ERR_OK;
99 }
100
101 // Use this function to make function pointers anonymous - forcing the
102 // compiler to use jumps instead of branches when calling driver
103 // services.
104 static void *__anonymizer(void *p)
105 {
106   return p;
107 }
108
109 // FIXME: Want to change all drivers to use this function. But it may
110 // make sense to wait till device structure pointer arguments get
111 // added as well.
112 void
113 flash_dev_query(void *data)
114 {
115     typedef void code_fun(void *);
116     code_fun *_flash_query;
117     int d_cache, i_cache;
118
119     _flash_query = (code_fun*)__anonymizer(&flash_query);
120
121     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
122     (*_flash_query)(data);
123     HAL_FLASH_CACHES_ON(d_cache, i_cache);
124 }
125
126 int
127 flash_verify_addr(void *target)
128 {
129     if (!flash_info.init) {
130         return FLASH_ERR_NOT_INIT;
131     }
132     if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
133         ((CYG_ADDRESS)target <= ((CYG_ADDRESS)flash_info.end - 1))) {
134         return FLASH_ERR_OK;
135     } else {
136         return FLASH_ERR_INVALID;
137     }
138 }
139
140 int
141 flash_get_limits(void *target, void **start, void **end)
142 {
143     if (!flash_info.init) {
144         return FLASH_ERR_NOT_INIT;
145     }
146     *start = flash_info.start;
147     *end = flash_info.end;
148     return FLASH_ERR_OK;
149 }
150
151 int
152 flash_get_block_info(int *block_size, int *blocks)
153 {
154     if (!flash_info.init) {
155         return FLASH_ERR_NOT_INIT;
156     }
157     *block_size = flash_info.block_size;
158     *blocks = flash_info.blocks;
159     return FLASH_ERR_OK;
160 }
161
162 int
163 flash_erase(void *addr, int len, void **err_addr)
164 {
165     unsigned short *block, *end_addr;
166     int stat = 0;
167     typedef int code_fun(unsigned short *, unsigned int);
168     code_fun *_flash_erase_block;
169     int d_cache, i_cache;
170
171     if (!flash_info.init) {
172         return FLASH_ERR_NOT_INIT;
173     }
174
175 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
176     if (plf_flash_query_soft_wp(addr,len))
177         return FLASH_ERR_PROTECT;
178 #endif
179
180      _flash_erase_block = (code_fun*)__anonymizer(&flash_erase_block);
181
182     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
183     end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
184
185     /* Check to see if end_addr overflowed */
186     if ((end_addr < block) && (len > 0)) {
187         end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
188     }
189
190 #ifdef CYGSEM_IO_FLASH_CHATTER
191     flash_info.pf("... Erase from %p-%p: ", block, end_addr);
192 #endif
193
194     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
195     FLASH_Enable(block, end_addr);
196     while (block < end_addr) {
197         // Supply the blocksize for a gross check for erase success
198         unsigned short *tmp_block;
199 #if !defined(CYGSEM_IO_FLASH_READ_INDIRECT)
200         int i;
201         unsigned char *dp;
202         bool erased = true;
203
204         dp = (unsigned char *)block;
205         for (i = 0;  i < flash_info.block_size;  i++) {
206             if (*dp++ != 0xFF) {
207                 erased = false;
208                 break;
209             }
210         }
211 #else
212         bool erased = false;
213 #endif
214
215         if (!erased) {
216             stat = (*_flash_erase_block)(block, flash_info.block_size);
217             stat = flash_hwr_map_error(stat);
218         }
219         if (stat) {
220             *err_addr = block;
221             break;
222         }
223
224         // Check to see if block will overflow
225         tmp_block = block + flash_info.block_size / sizeof(*block);
226         if (tmp_block < block) {
227             // If block address overflows, set block value to end on this loop
228             block = end_addr;
229         } else {
230             block = tmp_block;
231         }
232 #ifdef CYGSEM_IO_FLASH_CHATTER
233         flash_info.pf(".");
234 #endif
235     }
236     FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
237                                   end_addr);
238     HAL_FLASH_CACHES_ON(d_cache, i_cache);
239 #ifdef CYGSEM_IO_FLASH_CHATTER
240     flash_info.pf("\n");
241 #endif
242     return stat;
243 }
244
245 int
246 flash_program(void *_addr, void *_data, int len, void **err_addr)
247 {
248     int stat = 0;
249     int size;
250     typedef int code_fun(void *, void *, int, unsigned long, int);
251     code_fun *_flash_program_buf;
252     unsigned char *addr = _addr;
253     unsigned char *data = _data;
254     CYG_ADDRESS tmp;
255     int d_cache, i_cache;
256
257     if (!flash_info.init) {
258         return FLASH_ERR_NOT_INIT;
259     }
260
261 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
262     if (plf_flash_query_soft_wp(addr,len))
263         return FLASH_ERR_PROTECT;
264 #endif
265
266     _flash_program_buf = (code_fun*)__anonymizer(&flash_program_buf);
267
268 #ifdef CYGSEM_IO_FLASH_CHATTER
269     flash_info.pf("... Program from %p-%p at %p: ", data, 
270                      (void *)((CYG_ADDRESS)data + len), addr);
271 #endif
272
273     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
274     FLASH_Enable(addr, addr + len);
275     while (len > 0) {
276         size = len;
277 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
278         if (flash_info.start != 0)
279 #endif
280         if (size > flash_info.block_size) size = flash_info.block_size;
281
282         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
283         if (tmp) {
284                 tmp = flash_info.block_size - tmp;
285                 if (size > tmp) size = tmp;
286         }
287
288         stat = (*_flash_program_buf)(addr, data, size, 
289                                      flash_info.block_mask, flash_info.buffer_size);
290         stat = flash_hwr_map_error(stat);
291 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
292         if (0 == stat) // Claims to be OK
293             if (memcmp(addr, data, size) != 0) {                
294                 stat = 0x0BAD;
295 #ifdef CYGSEM_IO_FLASH_CHATTER
296                 flash_info.pf("V");
297 #endif
298             }
299 #endif
300         if (stat) {
301             *err_addr = addr;
302             break;
303         }
304 #ifdef CYGSEM_IO_FLASH_CHATTER
305         flash_info.pf(".");
306 #endif
307         len -= size;
308         addr += size / sizeof(*addr);
309         data += size / sizeof(*data);
310     }
311     FLASH_Disable(_addr, addr + len);
312     HAL_FLASH_CACHES_ON(d_cache, i_cache);
313 #ifdef CYGSEM_IO_FLASH_CHATTER
314     flash_info.pf("\n");
315 #endif
316     return stat;
317 }
318
319 int
320 flash_read(void *_addr, void *_data, int len, void **err_addr)
321 {
322 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
323     int stat = 0;
324     int size;
325     typedef int code_fun(void *, void *, int, unsigned long, int);
326     code_fun *_flash_read_buf;
327     unsigned char *addr = _addr;
328     unsigned char *data = _data;
329     CYG_ADDRESS tmp;
330     int d_cache, i_cache;
331
332     if (!flash_info.init) {
333         return FLASH_ERR_NOT_INIT;
334     }
335
336     _flash_read_buf = (code_fun*)__anonymizer(&flash_read_buf);
337
338 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
339     flash_info.pf("... Read from %p-%p at %p: ", data, 
340                      (void *)((CYG_ADDRESS)data + len), addr);
341 #endif
342
343     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
344     FLASH_Enable(addr, addr + len);
345     while (len > 0) {
346         size = len;
347 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
348         if (flash_info.start !=0)
349 #endif
350         if (size > flash_info.block_size) size = flash_info.block_size;
351
352         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
353         if (tmp) {
354                 tmp = flash_info.block_size - tmp;
355                 if (size>tmp) size = tmp;
356
357         }
358
359         stat = (*_flash_read_buf)(addr, data, size, 
360                                      flash_info.block_mask, flash_info.buffer_size);
361         stat = flash_hwr_map_error(stat);
362 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
363         if (0 == stat) // Claims to be OK
364             if (memcmp(addr, data, size) != 0) {                
365                 stat = 0x0BAD;
366 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
367                 flash_info.pf("V");
368 #endif
369             }
370 #endif
371         if (stat) {
372             *err_addr = addr;
373             break;
374         }
375 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
376         flash_info.pf(".");
377 #endif
378         len -= size;
379         addr += size / sizeof(*addr);
380         data += size / sizeof(*data);
381     }
382     FLASH_Disable(_addr, addr + len);
383     HAL_FLASH_CACHES_ON(d_cache, i_cache);
384 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
385     flash_info.pf("\n");
386 #endif
387     return stat;
388 #else // CYGSEM_IO_FLASH_READ_INDIRECT
389     // Direct access to FLASH memory is possible - just move the requested bytes
390     if (!flash_info.init) {
391         return FLASH_ERR_NOT_INIT;
392     }
393     memcpy(_data, _addr, len);
394     return FLASH_ERR_OK;
395 #endif
396 }
397
398 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
399
400 int
401 flash_lock(void *addr, int len, void **err_addr)
402 {
403     unsigned short *block, *end_addr;
404     int stat = 0;
405     typedef int code_fun(unsigned short *);
406     code_fun *_flash_lock_block;
407     int d_cache, i_cache;
408
409     if (!flash_info.init) {
410         return FLASH_ERR_NOT_INIT;
411     }
412
413 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
414     if (plf_flash_query_soft_wp(addr,len))
415         return FLASH_ERR_PROTECT;
416 #endif
417
418     _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
419
420     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
421     end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
422
423     /* Check to see if end_addr overflowed */
424     if ((end_addr < block) && (len > 0)) {
425         end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
426     }
427
428 #ifdef CYGSEM_IO_FLASH_CHATTER
429     flash_info.pf("... Lock from %p-%p: ", block, end_addr);
430 #endif
431
432     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
433     FLASH_Enable(block, end_addr);
434     while (block < end_addr) {
435         unsigned short *tmp_block;
436         stat = (*_flash_lock_block)(block);
437         stat = flash_hwr_map_error(stat);
438         if (stat) {
439             *err_addr = block;
440             break;
441         }
442
443         // Check to see if block will overflow
444         tmp_block = block + flash_info.block_size / sizeof(*block);
445         if (tmp_block < block) {
446             // If block address overflows, set block value to end on this loop
447             block = end_addr;
448         } else {
449             block = tmp_block;
450         }
451 #ifdef CYGSEM_IO_FLASH_CHATTER
452         flash_info.pf(".");
453 #endif
454     }
455     FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
456                                   end_addr);
457     HAL_FLASH_CACHES_ON(d_cache, i_cache);
458 #ifdef CYGSEM_IO_FLASH_CHATTER
459     flash_info.pf("\n");
460 #endif
461     return stat;
462 }
463
464 int
465 flash_unlock(void *addr, int len, void **err_addr)
466 {
467         unsigned short *block, *end_addr;
468         int stat = 0;
469         typedef int code_fun(unsigned short *, int, int);
470         code_fun *_flash_unlock_block;
471         int d_cache, i_cache;
472
473         if (!flash_info.init) {
474                 return FLASH_ERR_NOT_INIT;
475         }
476
477 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
478         if (plf_flash_query_soft_wp(addr,len))
479                 return FLASH_ERR_PROTECT;
480 #endif
481
482         _flash_unlock_block = (code_fun*)__anonymizer(&flash_unlock_block);
483
484         block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
485         end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
486
487         /* Check to see if end_addr overflowed */
488         if ((end_addr < block) && (len > 0)) {
489                 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
490         }
491
492 #ifdef CYGSEM_IO_FLASH_CHATTER
493         flash_info.pf("... Unlock from %p-%p: ", block, end_addr);
494 #endif
495
496         HAL_FLASH_CACHES_OFF(d_cache, i_cache);
497         FLASH_Enable(block, end_addr);
498         while (block < end_addr) {
499                 unsigned short *tmp_block;
500                 stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
501                 stat = flash_hwr_map_error(stat);
502                 if (stat) {
503                         *err_addr = block;
504                         break;
505                 }
506
507                 tmp_block = block + flash_info.block_size / sizeof(*block);
508                 if (tmp_block < block) {
509                         // If block address overflows, set block value to end on this loop
510                         block = end_addr;
511                 } else {
512                         block = tmp_block;
513                 }
514 #ifdef CYGSEM_IO_FLASH_CHATTER
515                 flash_info.pf(".");
516 #endif
517         }
518         FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
519                                   end_addr);
520         HAL_FLASH_CACHES_ON(d_cache, i_cache);
521 #ifdef CYGSEM_IO_FLASH_CHATTER
522         flash_info.pf("\n");
523 #endif
524         return stat;
525 }
526 #endif
527
528 char *
529 flash_errmsg(int err)
530 {
531     switch (err) {
532     case FLASH_ERR_OK:
533         return "No error - operation complete";
534     case FLASH_ERR_ERASE_SUSPEND:
535         return "Device is in erase suspend state";
536     case FLASH_ERR_PROGRAM_SUSPEND:
537         return "Device is in program suspend state";
538     case FLASH_ERR_INVALID:
539         return "Invalid FLASH address";
540     case FLASH_ERR_ERASE:
541         return "Error trying to erase";
542     case FLASH_ERR_LOCK:
543         return "Error trying to lock/unlock";
544     case FLASH_ERR_PROGRAM:
545         return "Error trying to program";
546     case FLASH_ERR_PROTOCOL:
547         return "Generic error";
548     case FLASH_ERR_PROTECT:
549         return "Device/region is write-protected";
550     case FLASH_ERR_NOT_INIT:
551         return "FLASH sub-system not initialized";
552     case FLASH_ERR_DRV_VERIFY:
553         return "Data verify failed after operation";
554     case FLASH_ERR_DRV_TIMEOUT:
555         return "Driver timed out waiting for device";
556     case FLASH_ERR_DRV_WRONG_PART:
557         return "Driver does not support device";
558     case FLASH_ERR_LOW_VOLTAGE:
559         return "Device reports low voltage";
560     default:
561         return "Unknown error";
562     }
563 }
564
565 // EOF io/flash/..../flash.c