]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/flash/v2_0/src/flash.c
unified MX27, MX25, MX37 trees
[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), end_addr);
237     HAL_FLASH_CACHES_ON(d_cache, i_cache);
238 #ifdef CYGSEM_IO_FLASH_CHATTER
239     flash_info.pf("\n");
240 #endif
241     return stat;
242 }
243
244 int
245 flash_program(void *_addr, void *_data, int len, void **err_addr)
246 {
247     int stat = 0;
248     int size;
249     typedef int code_fun(void *, void *, int, unsigned long, int);
250     code_fun *_flash_program_buf;
251     unsigned char *addr = _addr;
252     unsigned char *data = _data;
253     CYG_ADDRESS tmp;
254     int d_cache, i_cache;
255
256     if (!flash_info.init) {
257         return FLASH_ERR_NOT_INIT;
258     }
259
260 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
261     if (plf_flash_query_soft_wp(addr,len))
262         return FLASH_ERR_PROTECT;
263 #endif
264
265     _flash_program_buf = (code_fun*)__anonymizer(&flash_program_buf);
266
267 #ifdef CYGSEM_IO_FLASH_CHATTER
268     flash_info.pf("... Program from %p-%p at %p: ", data, 
269                      (void *)((CYG_ADDRESS)data + len), addr);
270 #endif
271
272     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
273     FLASH_Enable(addr, addr + len);
274     while (len > 0) {
275         size = len;
276 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
277         if (flash_info.start != 0)
278 #endif
279         if (size > flash_info.block_size) size = flash_info.block_size;
280
281         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
282         if (tmp) {
283                 tmp = flash_info.block_size - tmp;
284                 if (size > tmp) size = tmp;
285         }
286
287         stat = (*_flash_program_buf)(addr, data, size, 
288                                      flash_info.block_mask, flash_info.buffer_size);
289         stat = flash_hwr_map_error(stat);
290 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
291         if (0 == stat) // Claims to be OK
292             if (memcmp(addr, data, size) != 0) {                
293                 stat = 0x0BAD;
294 #ifdef CYGSEM_IO_FLASH_CHATTER
295                 flash_info.pf("V");
296 #endif
297             }
298 #endif
299         if (stat) {
300             *err_addr = addr;
301             break;
302         }
303 #ifdef CYGSEM_IO_FLASH_CHATTER
304         flash_info.pf(".");
305 #endif
306         len -= size;
307         addr += size/sizeof(*addr);
308         data += size/sizeof(*data);
309     }
310     FLASH_Disable(_addr, addr);
311     HAL_FLASH_CACHES_ON(d_cache, i_cache);
312 #ifdef CYGSEM_IO_FLASH_CHATTER
313     flash_info.pf("\n");
314 #endif
315     return stat;
316 }
317
318 int
319 flash_read(void *_addr, void *_data, int len, void **err_addr)
320 {
321 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
322     int stat = 0;
323     int size;
324     typedef int code_fun(void *, void *, int, unsigned long, int);
325     code_fun *_flash_read_buf;
326     unsigned char *addr = _addr;
327     unsigned char *data = _data;
328     CYG_ADDRESS tmp;
329     int d_cache, i_cache;
330
331     if (!flash_info.init) {
332         return FLASH_ERR_NOT_INIT;
333     }
334
335     _flash_read_buf = (code_fun*)__anonymizer(&flash_read_buf);
336
337 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
338     flash_info.pf("... Read from %p-%p at %p: ", data, 
339                      (void *)((CYG_ADDRESS)data + len), addr);
340 #endif
341
342     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
343     FLASH_Enable(addr, addr + len);
344     while (len > 0) {
345         size = len;
346 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
347         if (flash_info.start !=0)
348 #endif
349         if (size > flash_info.block_size) size = flash_info.block_size;
350
351         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
352         if (tmp) {
353                 tmp = flash_info.block_size - tmp;
354                 if (size>tmp) size = tmp;
355
356         }
357
358         stat = (*_flash_read_buf)(addr, data, size, 
359                                      flash_info.block_mask, flash_info.buffer_size);
360         stat = flash_hwr_map_error(stat);
361 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
362         if (0 == stat) // Claims to be OK
363             if (memcmp(addr, data, size) != 0) {                
364                 stat = 0x0BAD;
365 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
366                 flash_info.pf("V");
367 #endif
368             }
369 #endif
370         if (stat) {
371             *err_addr = addr;
372             break;
373         }
374 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
375         flash_info.pf(".");
376 #endif
377         len -= size;
378         addr += size / sizeof(*addr);
379         data += size / sizeof(*data);
380     }
381     FLASH_Disable(_addr, addr);
382     HAL_FLASH_CACHES_ON(d_cache, i_cache);
383 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
384     flash_info.pf("\n");
385 #endif
386     return stat;
387 #else // CYGSEM_IO_FLASH_READ_INDIRECT
388     // Direct access to FLASH memory is possible - just move the requested bytes
389     if (!flash_info.init) {
390         return FLASH_ERR_NOT_INIT;
391     }
392     memcpy(_data, _addr, len);
393     return FLASH_ERR_OK;
394 #endif
395 }
396
397 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
398
399 int
400 flash_lock(void *addr, int len, void **err_addr)
401 {
402     unsigned short *block, *end_addr;
403     int stat = 0;
404     typedef int code_fun(unsigned short *);
405     code_fun *_flash_lock_block;
406     int d_cache, i_cache;
407
408     if (!flash_info.init) {
409         return FLASH_ERR_NOT_INIT;
410     }
411
412 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
413     if (plf_flash_query_soft_wp(addr,len))
414         return FLASH_ERR_PROTECT;
415 #endif
416
417     _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
418
419     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
420     end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
421
422     /* Check to see if end_addr overflowed */
423     if ((end_addr < block) && (len > 0)) {
424         end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
425     }
426
427 #ifdef CYGSEM_IO_FLASH_CHATTER
428     flash_info.pf("... Lock from %p-%p: ", block, end_addr);
429 #endif
430
431     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
432     FLASH_Enable(block, end_addr);
433     while (block < end_addr) {
434         unsigned short *tmp_block;
435         stat = (*_flash_lock_block)(block);
436         stat = flash_hwr_map_error(stat);
437         if (stat) {
438             *err_addr = block;
439             break;
440         }
441
442         // Check to see if block will overflow
443         tmp_block = block + flash_info.block_size / sizeof(*block);
444         if (tmp_block < block) {
445             // If block address overflows, set block value to end on this loop
446             block = end_addr;
447         } else {
448             block = tmp_block;
449         }
450 #ifdef CYGSEM_IO_FLASH_CHATTER
451         flash_info.pf(".");
452 #endif
453     }
454     FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
455                                   end_addr);
456     HAL_FLASH_CACHES_ON(d_cache, i_cache);
457 #ifdef CYGSEM_IO_FLASH_CHATTER
458     flash_info.pf("\n");
459 #endif
460     return stat;
461 }
462
463 int
464 flash_unlock(void *addr, int len, void **err_addr)
465 {
466         unsigned short *block, *end_addr;
467         int stat = 0;
468         typedef int code_fun(unsigned short *, int, int);
469         code_fun *_flash_unlock_block;
470         int d_cache, i_cache;
471
472         if (!flash_info.init) {
473                 return FLASH_ERR_NOT_INIT;
474         }
475
476 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
477         if (plf_flash_query_soft_wp(addr,len))
478                 return FLASH_ERR_PROTECT;
479 #endif
480
481         _flash_unlock_block = (code_fun*)__anonymizer(&flash_unlock_block);
482
483         block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
484         end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
485
486         /* Check to see if end_addr overflowed */
487         if ((end_addr < block) && (len > 0)) {
488                 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
489         }
490
491 #ifdef CYGSEM_IO_FLASH_CHATTER
492         flash_info.pf("... Unlock from %p-%p: ", block, end_addr);
493 #endif
494
495         HAL_FLASH_CACHES_OFF(d_cache, i_cache);
496         FLASH_Enable(block, end_addr);
497         while (block < end_addr) {
498                 unsigned short *tmp_block;
499                 stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
500                 stat = flash_hwr_map_error(stat);
501                 if (stat) {
502                         *err_addr = block;
503                         break;
504                 }
505
506                 tmp_block = block + flash_info.block_size / sizeof(*block);
507                 if (tmp_block < block) {
508                         // If block address overflows, set block value to end on this loop
509                         block = end_addr;
510                 } else {
511                         block = tmp_block;
512                 }
513 #ifdef CYGSEM_IO_FLASH_CHATTER
514                 flash_info.pf(".");
515 #endif
516         }
517         FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
518                                   end_addr);
519         HAL_FLASH_CACHES_ON(d_cache, i_cache);
520 #ifdef CYGSEM_IO_FLASH_CHATTER
521         flash_info.pf("\n");
522 #endif
523         return stat;
524 }
525 #endif
526
527 char *
528 flash_errmsg(int err)
529 {
530     switch (err) {
531     case FLASH_ERR_OK:
532         return "No error - operation complete";
533     case FLASH_ERR_ERASE_SUSPEND:
534         return "Device is in erase suspend state";
535     case FLASH_ERR_PROGRAM_SUSPEND:
536         return "Device is in program suspend state";
537     case FLASH_ERR_INVALID:
538         return "Invalid FLASH address";
539     case FLASH_ERR_ERASE:
540         return "Error trying to erase";
541     case FLASH_ERR_LOCK:
542         return "Error trying to lock/unlock";
543     case FLASH_ERR_PROGRAM:
544         return "Error trying to program";
545     case FLASH_ERR_PROTOCOL:
546         return "Generic error";
547     case FLASH_ERR_PROTECT:
548         return "Device/region is write-protected";
549     case FLASH_ERR_NOT_INIT:
550         return "FLASH sub-system not initialized";
551     case FLASH_ERR_DRV_VERIFY:
552         return "Data verify failed after operation";
553     case FLASH_ERR_DRV_TIMEOUT:
554         return "Driver timed out waiting for device";
555     case FLASH_ERR_DRV_WRONG_PART:
556         return "Driver does not support device";
557     case FLASH_ERR_LOW_VOLTAGE:
558         return "Device reports low voltage";
559     default:
560         return "Unknown error";
561     }
562 }
563
564 // EOF io/flash/..../flash.c