]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/flash/v2_0/src/flash.c
TX51/TX53 Release 2011-08-19
[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 #include <pkgconf/system.h>
54 #include <pkgconf/io_flash.h>
55
56 #include <cyg/hal/hal_arch.h>
57 #include <cyg/hal/hal_intr.h>
58 #include <cyg/hal/hal_cache.h>
59 #include <string.h>
60
61 #define  _FLASH_PRIVATE_
62 #include <cyg/io/flash.h>
63
64 // When this flag is set, do not actually jump to the relocated code.
65 // This can be used for running the function in place (RAM startup only),
66 // allowing calls to diag_printf() and similar.
67 #undef RAM_FLASH_DEV_DEBUG
68 #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
69 # warning "Can only enable the flash debugging when configured for RAM startup"
70 #endif
71
72 struct flash_info flash_info;
73
74 // These are the functions in the HW specific driver we need to call.
75 typedef void code_fun(void *);
76
77 externC code_fun flash_query;
78 externC code_fun flash_erase_block;
79 externC code_fun flash_program_buf;
80 externC code_fun flash_read_buf;
81 externC code_fun flash_lock_block;
82 externC code_fun flash_unlock_block;
83
84 int
85 flash_init(_printf *pf)
86 {
87         int err;
88
89         flash_info.pf = pf; // Do this before calling into the driver
90         if (flash_info.init) return FLASH_ERR_OK;
91
92         if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
93                 return err;
94         }
95         flash_info.block_mask = ~(flash_info.block_size - 1);
96         flash_info.init = 1;
97         return FLASH_ERR_OK;
98 }
99
100 // Use this function to make function pointers anonymous - forcing the
101 // compiler to use jumps instead of branches when calling driver
102 // services.
103 static void *__anonymizer(void *p)
104 {
105   return p;
106 }
107
108 // FIXME: Want to change all drivers to use this function. But it may
109 // make sense to wait till device structure pointer arguments get
110 // added as well.
111 void
112 flash_dev_query(void *data)
113 {
114         typedef void code_fun(void *);
115         code_fun *_flash_query;
116         int d_cache, i_cache;
117
118         _flash_query = (code_fun*)__anonymizer(&flash_query);
119
120         HAL_FLASH_CACHES_OFF(d_cache, i_cache);
121         (*_flash_query)(data);
122         HAL_FLASH_CACHES_ON(d_cache, i_cache);
123 }
124
125 int
126 flash_verify_addr(void *target)
127 {
128         if (!flash_info.init) {
129                 return FLASH_ERR_NOT_INIT;
130         }
131         if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
132                 ((CYG_ADDRESS)target <= ((CYG_ADDRESS)flash_info.end - 1))) {
133                 return FLASH_ERR_OK;
134         } else {
135                 return FLASH_ERR_INVALID;
136         }
137 }
138
139 int
140 flash_get_limits(void *target, void **start, void **end)
141 {
142         if (!flash_info.init) {
143                 return FLASH_ERR_NOT_INIT;
144         }
145         *start = flash_info.start;
146         *end = flash_info.end;
147         return FLASH_ERR_OK;
148 }
149
150 int
151 flash_get_block_info(int *block_size, int *blocks)
152 {
153         if (!flash_info.init) {
154                 return FLASH_ERR_NOT_INIT;
155         }
156         *block_size = flash_info.block_size;
157         *blocks = flash_info.blocks;
158         return FLASH_ERR_OK;
159 }
160
161 int
162 flash_erase(void *addr, int len, void **err_addr)
163 {
164         unsigned short *block, *end_addr;
165         int stat = 0;
166         typedef int code_fun(unsigned short *, unsigned int);
167         code_fun *_flash_erase_block;
168         int d_cache, i_cache;
169
170         if (!flash_info.init) {
171                 return FLASH_ERR_NOT_INIT;
172         }
173
174 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
175         if (plf_flash_query_soft_wp(addr,len))
176                 return FLASH_ERR_PROTECT;
177 #endif
178
179         _flash_erase_block = (code_fun*)__anonymizer(&flash_erase_block);
180
181         block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
182         end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
183
184         /* Check to see if end_addr overflowed */
185         if ((end_addr < block) && (len > 0)) {
186                 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end);
187         }
188
189 #ifdef CYGSEM_IO_FLASH_CHATTER
190         flash_info.pf("... Erase from %p-%p: ", block, end_addr);
191 #endif
192
193         HAL_FLASH_CACHES_OFF(d_cache, i_cache);
194         FLASH_Enable(block, end_addr);
195         while (block < end_addr) {
196                 // Supply the blocksize for a gross check for erase success
197                 unsigned short *tmp_block;
198 #if !defined(CYGSEM_IO_FLASH_READ_INDIRECT)
199                 int i;
200                 unsigned char *dp;
201                 bool erased = true;
202
203                 dp = (unsigned char *)block;
204                 for (i = 0; i < flash_info.block_size; i++) {
205                         if (*dp++ != 0xFF) {
206                                 erased = false;
207                                 break;
208                         }
209                 }
210 #else
211                 bool erased = false;
212 #endif
213
214                 if (!erased) {
215                         stat = (*_flash_erase_block)(block, flash_info.block_size);
216                         stat = flash_hwr_map_error(stat);
217                 }
218                 if (stat) {
219                         *err_addr = block;
220                         break;
221                 }
222
223                 // Check to see if block will overflow
224                 tmp_block = block + flash_info.block_size / sizeof(*block);
225                 if (tmp_block < block) {
226                         // If block address overflows, set block value to end on this loop
227                         block = end_addr;
228                 } else {
229                         block = tmp_block;
230                 }
231 #ifdef CYGSEM_IO_FLASH_CHATTER
232                 flash_info.pf(".");
233 #endif
234         }
235         FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
236                                 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 + len);
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                 stat = (*_flash_read_buf)(addr, data, size,
358                                                                 flash_info.block_mask, flash_info.buffer_size);
359                 stat = flash_hwr_map_error(stat);
360 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
361                 if (0 == stat) // Claims to be OK
362                         if (memcmp(addr, data, size) != 0) {
363                                 stat = 0x0BAD;
364 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
365                                 flash_info.pf("V");
366 #endif
367                         }
368 #endif
369                 if (stat) {
370                         *err_addr = addr;
371                         break;
372                 }
373 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
374                 flash_info.pf(".");
375 #endif
376                 len -= size;
377                 addr += size / sizeof(*addr);
378                 data += size / sizeof(*data);
379         }
380         FLASH_Disable(_addr, addr + len);
381         HAL_FLASH_CACHES_ON(d_cache, i_cache);
382 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
383         flash_info.pf("\n");
384 #endif
385         return stat;
386 #else // CYGSEM_IO_FLASH_READ_INDIRECT
387         // Direct access to FLASH memory is possible - just move the requested bytes
388         if (!flash_info.init) {
389                 return FLASH_ERR_NOT_INIT;
390         }
391         memcpy(_data, _addr, len);
392         return FLASH_ERR_OK;
393 #endif
394 }
395
396 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
397
398 int
399 flash_lock(void *addr, int len, void **err_addr)
400 {
401         unsigned short *block, *end_addr;
402         int stat = 0;
403         typedef int code_fun(unsigned short *);
404         code_fun *_flash_lock_block;
405         int d_cache, i_cache;
406
407         if (!flash_info.init) {
408                 return FLASH_ERR_NOT_INIT;
409         }
410
411 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
412         if (plf_flash_query_soft_wp(addr,len))
413                 return FLASH_ERR_PROTECT;
414 #endif
415
416         _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
417
418         block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
419         end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
420
421         /* Check to see if end_addr overflowed */
422         if ((end_addr < block) && (len > 0)) {
423                 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
424         }
425
426 #ifdef CYGSEM_IO_FLASH_CHATTER
427         flash_info.pf("... Lock from %p-%p: ", block, end_addr);
428 #endif
429
430         HAL_FLASH_CACHES_OFF(d_cache, i_cache);
431         FLASH_Enable(block, end_addr);
432         while (block < end_addr) {
433                 unsigned short *tmp_block;
434                 stat = (*_flash_lock_block)(block);
435                 stat = flash_hwr_map_error(stat);
436                 if (stat) {
437                         *err_addr = block;
438                         break;
439                 }
440
441                 // Check to see if block will overflow
442                 tmp_block = block + flash_info.block_size / sizeof(*block);
443                 if (tmp_block < block) {
444                         // If block address overflows, set block value to end on this loop
445                         block = end_addr;
446                 } else {
447                         block = tmp_block;
448                 }
449 #ifdef CYGSEM_IO_FLASH_CHATTER
450                 flash_info.pf(".");
451 #endif
452         }
453         FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
454                                 end_addr);
455         HAL_FLASH_CACHES_ON(d_cache, i_cache);
456 #ifdef CYGSEM_IO_FLASH_CHATTER
457         flash_info.pf("\n");
458 #endif
459         return stat;
460 }
461
462 int
463 flash_unlock(void *addr, int len, void **err_addr)
464 {
465         unsigned short *block, *end_addr;
466         int stat = 0;
467         typedef int code_fun(unsigned short *, int, int);
468         code_fun *_flash_unlock_block;
469         int d_cache, i_cache;
470
471         if (!flash_info.init) {
472                 return FLASH_ERR_NOT_INIT;
473         }
474
475 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
476         if (plf_flash_query_soft_wp(addr,len))
477                 return FLASH_ERR_PROTECT;
478 #endif
479
480         _flash_unlock_block = (code_fun*)__anonymizer(&flash_unlock_block);
481
482         block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
483         end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
484
485         /* Check to see if end_addr overflowed */
486         if ((end_addr < block) && (len > 0)) {
487                 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
488         }
489
490 #ifdef CYGSEM_IO_FLASH_CHATTER
491         flash_info.pf("... Unlock from %p-%p: ", block, end_addr);
492 #endif
493
494         HAL_FLASH_CACHES_OFF(d_cache, i_cache);
495         FLASH_Enable(block, end_addr);
496         while (block < end_addr) {
497                 unsigned short *tmp_block;
498                 stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
499                 stat = flash_hwr_map_error(stat);
500                 if (stat) {
501                         *err_addr = block;
502                         break;
503                 }
504
505                 tmp_block = block + flash_info.block_size / sizeof(*block);
506                 if (tmp_block < block) {
507                         // If block address overflows, set block value to end on this loop
508                         block = end_addr;
509                 } else {
510                         block = tmp_block;
511                 }
512 #ifdef CYGSEM_IO_FLASH_CHATTER
513                 flash_info.pf(".");
514 #endif
515         }
516         FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
517                                   end_addr);
518         HAL_FLASH_CACHES_ON(d_cache, i_cache);
519 #ifdef CYGSEM_IO_FLASH_CHATTER
520         flash_info.pf("\n");
521 #endif
522         return stat;
523 }
524 #endif
525
526 char *
527 flash_errmsg(int err)
528 {
529         switch (err) {
530         case FLASH_ERR_OK:
531                 return "No error - operation complete";
532         case FLASH_ERR_ERASE_SUSPEND:
533                 return "Device is in erase suspend state";
534         case FLASH_ERR_PROGRAM_SUSPEND:
535                 return "Device is in program suspend state";
536         case FLASH_ERR_INVALID:
537                 return "Invalid FLASH address";
538         case FLASH_ERR_ERASE:
539                 return "Error trying to erase";
540         case FLASH_ERR_LOCK:
541                 return "Error trying to lock/unlock";
542         case FLASH_ERR_PROGRAM:
543                 return "Error trying to program";
544         case FLASH_ERR_PROTOCOL:
545                 return "Generic error";
546         case FLASH_ERR_PROTECT:
547                 return "Device/region is write-protected";
548         case FLASH_ERR_NOT_INIT:
549                 return "FLASH sub-system not initialized";
550         case FLASH_ERR_DRV_VERIFY:
551                 return "Data verify failed after operation";
552         case FLASH_ERR_DRV_TIMEOUT:
553                 return "Driver timed out waiting for device";
554         case FLASH_ERR_DRV_WRONG_PART:
555                 return "Driver does not support device";
556         case FLASH_ERR_LOW_VOLTAGE:
557                 return "Device reports low voltage";
558         default:
559                 return "Unknown error";
560         }
561 }
562
563 // EOF io/flash/..../flash.c