]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/flash/toshiba/tc58xxx/v2_0/include/flash_tc58xxx.inl
Initial revision
[karo-tx-redboot.git] / packages / devs / flash / toshiba / tc58xxx / v2_0 / include / flash_tc58xxx.inl
1 #ifndef CYGONCE_DEVS_FLASH_TOSHIBA_TC58XXX_INL
2 #define CYGONCE_DEVS_FLASH_TOSHIBA_TC58XXX_INL
3 //==========================================================================
4 //
5 //      flash_tc58xxx.inl
6 //
7 //      Toshiba Tc58xxx 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, 2004 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):    Gary Thomas <gary@mlbassoc.com>
49 // Contributors: 
50 // Date:         2003-09-02
51 // Purpose:
52 // Description:  FLASH drivers for Toshiba NAND FLASH TC58xxx devices.
53 //               Based on Atmel AT49xxxx drivers by Jani Monoses <jani@iv.ro>
54 //
55 //####DESCRIPTIONEND####
56 //
57 //==========================================================================
58
59 // FIXME!  Someday add support for ECC data & fixups of bad sectors
60
61 #include <pkgconf/hal.h>
62 #include <cyg/hal/hal_arch.h>
63 #include <cyg/hal/hal_cache.h>
64 #include <cyg/infra/diag.h>
65 #include CYGHWR_MEMORY_LAYOUT_H
66
67 #define  _FLASH_PRIVATE_
68 #include <cyg/io/flash.h>
69
70 // Low level debugging
71 //   1 - command level - prints messages about read/write/erase commands
72 //   2 - hardware level - shows all NAND device I/O data
73 #define FLASH_DEBUG  0
74
75 //----------------------------------------------------------------------------
76 // Common device details.
77 #define FLASH_Read_ID                   FLASHWORD(0x90)
78 #define FLASH_Reset                     FLASHWORD(0xFF)
79 #define FLASH_Read_Mode1                FLASHWORD(0x00)
80 #define FLASH_Read_Mode2                FLASHWORD(0x01)
81 #define FLASH_Read_Mode3                FLASHWORD(0x50)
82 #define FLASH_Program                   FLASHWORD(0x10)
83 #define FLASH_Send_Data                 FLASHWORD(0x80)
84 #define FLASH_Status                    FLASHWORD(0x70)
85 #define FLASH_Block_Erase               FLASHWORD(0x60)
86 #define FLASH_Start_Erase               FLASHWORD(0xD0)
87
88 #define CYGNUM_FLASH_ID_MANUFACTURER    FLASHWORD(0x98)
89
90 //----------------------------------------------------------------------------
91 // Now that device properties are defined, include magic for defining
92 // accessor type and constants.
93 #include <cyg/io/flash_dev.h>
94
95 //----------------------------------------------------------------------------
96 // Information about supported devices
97 typedef struct flash_dev_info {
98     flash_data_t device_id;
99     cyg_uint32   block_size;
100     cyg_uint32   page_size;
101     cyg_int32    block_count;
102     cyg_uint32   base_mask;
103     cyg_uint32   device_size;
104 } flash_dev_info_t;
105
106 static const flash_dev_info_t* flash_dev_info;
107 static const flash_dev_info_t supported_devices[] = {
108 #include <cyg/io/flash_tc58xxx_parts.inl>
109 };
110 #define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
111
112 //----------------------------------------------------------------------------
113 // Functions that put the flash device into non-read mode must reside
114 // in RAM.
115 void flash_query(void* data) __attribute__ ((section (".2ram.flash_query")));
116 int  flash_erase_block(void* block, unsigned int size)
117     __attribute__ ((section (".2ram.flash_erase_block")));
118 int  flash_program_buf(void* addr, void* data, int len)
119     __attribute__ ((section (".2ram.flash_program_buf")));
120
121 //----------------------------------------------------------------------------
122 // Initialize driver details
123 int
124 flash_hwr_init(void)
125 {
126     flash_data_t id[4];
127     int i;
128
129 #ifdef CYGHWR_FLASH_TC58XXX_PLF_INIT
130     CYGHWR_FLASH_TC58XXX_PLF_INIT();
131 #endif
132
133     flash_dev_query(id);
134
135     // Check that flash_id data is matching the one the driver was
136     // configured for.
137
138     // Check manufacturer
139     if (id[0] != CYGNUM_FLASH_ID_MANUFACTURER) {
140         diag_printf("Can't identify FLASH - manufacturer is: %x, should be %x\n", 
141                     id[0], CYGNUM_FLASH_ID_MANUFACTURER);
142         return FLASH_ERR_DRV_WRONG_PART;
143     }
144
145     // Look through table for device data
146     flash_dev_info = supported_devices;
147     for (i = 0; i < NUM_DEVICES; i++) {
148         if (flash_dev_info->device_id == id[1])
149             break;
150         flash_dev_info++;
151     }
152
153     // Did we find the device? If not, return error.
154     if (NUM_DEVICES == i) {
155         diag_printf("Can't identify FLASH - device is: %x, supported: ", id[1]);
156         for (i = 0;  i < NUM_DEVICES;  i++) {
157             diag_printf("%x ", supported_devices[i].device_id);
158         }
159         diag_printf("\n");
160         return FLASH_ERR_DRV_WRONG_PART;
161     }
162
163     // Fill in device details
164     flash_info.block_size = flash_dev_info->block_size;
165     flash_info.blocks = flash_dev_info->block_count * CYGNUM_FLASH_SERIES;
166     flash_info.start = (void *)CYGNUM_FLASH_BASE;
167     flash_info.end = (void *)(CYGNUM_FLASH_BASE+ (flash_dev_info->device_size * CYGNUM_FLASH_SERIES));
168     return FLASH_ERR_OK;
169 }
170
171 //----------------------------------------------------------------------------
172 // Map a hardware status to a package error
173 int
174 flash_hwr_map_error(int e)
175 {
176     return e;
177 }
178
179
180 //----------------------------------------------------------------------------
181 // See if a range of FLASH addresses overlaps currently running code
182 bool
183 flash_code_overlaps(void *start, void *end)
184 {
185     extern unsigned char _stext[], _etext[];
186
187     return ((((unsigned long)&_stext >= (unsigned long)start) &&
188              ((unsigned long)&_stext < (unsigned long)end)) ||
189             (((unsigned long)&_etext >= (unsigned long)start) &&
190              ((unsigned long)&_etext < (unsigned long)end)));
191 }
192
193 static void
194 put_NAND(volatile flash_data_t *ROM, flash_data_t val)
195 {
196     *ROM = val;
197 #if FLASH_DEBUG > 1
198     diag_printf("%02x ", val);
199 #endif
200 }
201
202 //----------------------------------------------------------------------------
203 // Flash Query
204 //
205 // Only reads the manufacturer and part number codes for the first
206 // device(s) in series. It is assumed that any devices in series
207 // will be of the same type.
208
209 void
210 flash_query(void* data)
211 {
212     flash_data_t* id = (flash_data_t*) data;
213     volatile flash_data_t *ROM;
214
215     ROM = (volatile flash_data_t*) CYGNUM_FLASH_BASE;
216     // Send initial RESET command
217     CYGHWR_FLASH_TC58XXX_CE(1);
218     CYGHWR_FLASH_TC58XXX_CLE(1);
219     put_NAND(ROM, FLASH_Reset);
220     CYGHWR_FLASH_TC58XXX_CLE(0);
221     CYGHWR_FLASH_TC58XXX_CE(0);
222     // Now, wait for a good while
223     CYGACC_CALL_IF_DELAY_US(10000);  // Actually 10ms
224     // Issue device query
225     CYGHWR_FLASH_TC58XXX_CE(1);
226     CYGHWR_FLASH_TC58XXX_CLE(1);
227     put_NAND(ROM, FLASH_Read_ID);
228     CYGHWR_FLASH_TC58XXX_CLE(0);
229     CYGHWR_FLASH_TC58XXX_ALE(1);
230     put_NAND(ROM, 0x00);  // Dummy address
231     CYGHWR_FLASH_TC58XXX_ALE(0);
232     // Minimum 100ns delay after deasserting ALE
233     CYGACC_CALL_IF_DELAY_US(10);  // Actually 10us
234     id[0] = *ROM;
235     id[1] = *ROM;
236     CYGHWR_FLASH_TC58XXX_CLE(1);
237     put_NAND(ROM, FLASH_Reset);
238     CYGHWR_FLASH_TC58XXX_CLE(0);
239     CYGHWR_FLASH_TC58XXX_CE(0);
240 }
241
242 //----------------------------------------------------------------------------
243 // Erase Block
244 int
245 flash_erase_block(void* block, unsigned int size)
246 {
247     volatile flash_data_t* ROM;
248     volatile flash_data_t* b_p = (volatile flash_data_t*) block;
249     int res = FLASH_ERR_OK;
250     int cnt = 0;
251     flash_data_t stat;
252
253 #if FLASH_DEBUG > 0
254     diag_printf("%s - block: %x, size: %d\n", __FUNCTION__, block, size);
255 #endif
256     ROM = (volatile flash_data_t*) CYGNUM_FLASH_BASE;
257     // Erase the next block
258 #if FLASH_DEBUG > 1
259     diag_printf("<< ");
260 #endif
261     CYGHWR_FLASH_TC58XXX_CE(1);
262     CYGHWR_FLASH_TC58XXX_CLE(1);
263     put_NAND(ROM, FLASH_Block_Erase);
264     CYGHWR_FLASH_TC58XXX_CLE(0);
265     CYGHWR_FLASH_TC58XXX_ALE(1);
266     put_NAND(ROM, ((unsigned long)b_p & 0x0001FE00) >> 9);      // A9..A16
267     put_NAND(ROM, ((unsigned long)b_p & 0x01FE0000) >> 17);     // A17..A24
268     if (flash_dev_info->device_size > 0x02000000) {
269         put_NAND(ROM, ((unsigned long)b_p & 0x06000000) >> 25); // A26..A27
270     }
271     CYGHWR_FLASH_TC58XXX_ALE(0);
272     CYGHWR_FLASH_TC58XXX_CLE(1);
273     put_NAND(ROM, FLASH_Start_Erase);
274     CYGHWR_FLASH_TC58XXX_CLE(0);        
275     CYGACC_CALL_IF_DELAY_US(10);
276     while (!CYGHWR_FLASH_TC58XXX_RDY()) cnt++;  // Wait for operation to complete
277     CYGHWR_FLASH_TC58XXX_CLE(1);
278     put_NAND(ROM, FLASH_Status);
279     CYGHWR_FLASH_TC58XXX_CLE(0);        
280     stat = *ROM;
281     CYGHWR_FLASH_TC58XXX_CE(0);
282 #if FLASH_DEBUG > 1
283     diag_printf(">>\n");
284 #endif
285 #if FLASH_DEBUG > 0
286     diag_printf("block: %x, stat: %x, count = %d\n", b_p, stat, cnt);
287 #endif
288     if (stat != 0xC0) {
289         diag_printf("Status after erase: %x\n", stat);
290         if ((stat & 0x80) == 0x00) {
291             res = FLASH_ERR_PROTECT;
292         } else {
293             res = FLASH_ERR_ERASE;
294         }
295     }
296     return res;
297 }
298
299 //
300 // ECC support - adapted from Linux:
301 //
302 //  drivers/mtd/nand_ecc.c
303 //
304 //  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
305 //                     Toshiba America Electronics Components, Inc.
306 //
307
308 static const unsigned char _nand_ecc_precalc_table[] = {
309     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
310     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
311     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
312     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
313     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
314     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
315     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
316     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
317     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
318     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
319     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
320     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
321     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
322     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
323     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
324     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
325 };
326
327 static void 
328 _nand_trans_result(unsigned char reg2, unsigned char reg3,
329                    unsigned char *ecc0, unsigned char *ecc1)
330 {
331     unsigned char a, b, i, tmp1, tmp2;
332         
333     /* Initialize variables */
334     a = b = 0x80;
335     tmp1 = tmp2 = 0;
336         
337     /* Calculate first ECC byte */
338     for (i = 0; i < 4; i++) {
339         if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
340             tmp1 |= b;
341         b >>= 1;
342         if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
343             tmp1 |= b;
344         b >>= 1;
345         a >>= 1;
346     }
347         
348     /* Calculate second ECC byte */
349     b = 0x80;
350     for (i = 0; i < 4; i++) {
351         if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
352             tmp2 |= b;
353         b >>= 1;
354         if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
355             tmp2 |= b;
356         b >>= 1;
357         a >>= 1;
358     }
359         
360     /* Store two of the ECC bytes */
361     *ecc0 = tmp1;    
362     *ecc1 = tmp2;
363 }
364
365 //
366 // Calculate 3 byte ECC on 256 bytes of data
367 //
368 static void
369 _nand_page_ECC(unsigned char *data, unsigned char *ecc0,
370                unsigned char *ecc1, unsigned char *ecc2)
371 {
372     unsigned char idx, reg1, reg2, reg3;
373     int j;
374         
375     /* Initialize variables */
376     reg1 = reg2 = reg3 = 0;
377     *ecc0 = *ecc1 = *ecc2 = 0;
378         
379     /* Build up column parity */ 
380     for(j = 0; j < 256; j++) {
381         /* Get CP0 - CP5 from table */
382         idx = _nand_ecc_precalc_table[*data++];
383         reg1 ^= (idx & 0x3f);
384         /* All bit XOR = 1 ? */
385         if (idx & 0x40) {
386             reg3 ^= (unsigned char) j;
387             reg2 ^= ~((unsigned char) j);
388         }
389     }
390         
391     /* Create non-inverted ECC code from line parity */
392     _nand_trans_result(reg2, reg3, ecc0, ecc1);
393         
394     /* Calculate final ECC code */
395     *ecc0 = ~*ecc0;
396     *ecc1 = ~*ecc1;
397     *ecc2 = ((~reg1) << 2) | 0x03;
398 }
399
400 //
401 // Correct a buffer via ECC (1 bit, 256 byte block)
402 //  Return: 0 => No error
403 //          1 => Corrected
404 //          2 => Not corrected, ECC updated
405 //         -1 => Not correctable
406 //
407 int 
408 _nand_correct_data(unsigned char *dat, unsigned char *read_ecc, unsigned char *calc_ecc)
409 {
410     unsigned char a, b, c, d1, d2, d3, add, bit, i;
411         
412     /* Do error detection */ 
413     d1 = calc_ecc[0] ^ read_ecc[0];
414     d2 = calc_ecc[1] ^ read_ecc[1];
415     d3 = calc_ecc[2] ^ read_ecc[2];
416         
417     if ((d1 | d2 | d3) == 0) {
418         /* No errors */
419         return 0;
420     } else {
421         a = (d1 ^ (d1 >> 1)) & 0x55;
422         b = (d2 ^ (d2 >> 1)) & 0x55;
423         c = (d3 ^ (d3 >> 1)) & 0x54;
424                 
425         /* Found and will correct single bit error in the data */
426         if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
427             c = 0x80;
428             add = 0;
429             a = 0x80;
430             for (i=0; i<4; i++) {
431                 if (d1 & c)
432                     add |= a;
433                 c >>= 2;
434                 a >>= 1;
435             }
436             c = 0x80;
437             for (i=0; i<4; i++) {
438                 if (d2 & c)
439                     add |= a;
440                 c >>= 2;
441                 a >>= 1;
442             }
443             bit = 0;
444             b = 0x04;
445             c = 0x80;
446             for (i=0; i<3; i++) {
447                 if (d3 & c)
448                     bit |= b;
449                 c >>= 2;
450                 b >>= 1;
451             }
452             b = 0x01;
453             a = dat[add];
454             a ^= (b << bit);
455             dat[add] = a;
456             return 1;
457         } else {
458             i = 0;
459             while (d1) {
460                 if (d1 & 0x01)
461                     ++i;
462                 d1 >>= 1;
463             }
464             while (d2) {
465                 if (d2 & 0x01)
466                     ++i;
467                 d2 >>= 1;
468             }
469             while (d3) {
470                 if (d3 & 0x01)
471                     ++i;
472                 d3 >>= 1;
473             }
474             if (i == 1) {
475                 /* ECC Code Error Correction */
476                 read_ecc[0] = calc_ecc[0];
477                 read_ecc[1] = calc_ecc[1];
478                 read_ecc[2] = calc_ecc[2];
479                 return 2;
480             } else {
481                 /* Uncorrectable Error */
482                 return -1;
483             }
484         }
485     }
486         
487     /* Should never happen */
488     return -1;
489 }
490
491
492 //----------------------------------------------------------------------------
493 // Program Buffer
494 int
495 flash_program_buf(void* addr, void* data, int len)
496 {
497     volatile flash_data_t* ROM;
498     volatile flash_data_t* addr_ptr = (volatile flash_data_t*) addr;
499     volatile flash_data_t* data_ptr = (volatile flash_data_t*) data;
500     int res = FLASH_ERR_OK;
501     int i, cnt;
502     flash_data_t stat;
503     unsigned char oob[16];
504
505     ROM = (volatile flash_data_t*) CYGNUM_FLASH_BASE;
506 #if FLASH_DEBUG > 0
507     diag_printf("%s - addr: %x, data: %x, len: %d, FLASH: %p/%d\n", 
508                 __FUNCTION__, addr, data, len, ROM, sizeof(flash_data_t));
509 #endif
510     while (len > 0) {
511         CYGHWR_FLASH_TC58XXX_CE(1);
512         CYGHWR_FLASH_TC58XXX_CLE(1);
513 #if FLASH_DEBUG > 1
514         diag_printf("<< ");
515 #endif
516         put_NAND(ROM, FLASH_Read_Mode1);
517         put_NAND(ROM, FLASH_Send_Data);
518         CYGHWR_FLASH_TC58XXX_CLE(0);
519         CYGHWR_FLASH_TC58XXX_ALE(1);
520         put_NAND(ROM, ((unsigned long)addr_ptr & 0x000000FF) >> 0);   // A0..A7
521         put_NAND(ROM, ((unsigned long)addr_ptr & 0x0001FE00) >> 9);   // A9..A16
522         put_NAND(ROM, ((unsigned long)addr_ptr & 0x01FE0000) >> 17);  // A17..A24
523         if (flash_dev_info->device_size > 0x02000000) {
524             put_NAND(ROM, ((unsigned long)addr_ptr & 0x06000000) >> 25);  // A26..A27
525         }
526         CYGHWR_FLASH_TC58XXX_ALE(0);
527 #if FLASH_DEBUG > 1
528         diag_printf(">>\n");
529 #endif
530         // Caculate OOB data for page (ECC)
531         for (i = 0;  i < 16;  i++) {
532             oob[i] = 0xFF;
533         }
534         // Calculate ECC for page
535         _nand_page_ECC((unsigned char *)&data_ptr[0], &oob[0], &oob[1], &oob[2]);
536         _nand_page_ECC((unsigned char *)&data_ptr[256], &oob[3], &oob[6], &oob[7]);
537         // Move one page of data to buffer
538         for (i = 0;  i < 512;  i++) {
539             put_NAND(ROM, *data_ptr++);
540 #if FLASH_DEBUG > 1
541             if ((i % 16) == 15) diag_printf("\n");
542 #endif
543         }
544         // OOB data
545         for (i = 0;  i < 16;  i++) {
546             put_NAND(ROM, oob[i]);
547 #if FLASH_DEBUG > 1
548             if ((i % 16) == 15) diag_printf("\n");
549 #endif
550         }
551 #if FLASH_DEBUG > 1
552         diag_printf("<< ");
553 #endif
554         CYGHWR_FLASH_TC58XXX_CLE(1);
555         put_NAND(ROM, FLASH_Program);
556         CYGHWR_FLASH_TC58XXX_CLE(0);
557         CYGACC_CALL_IF_DELAY_US(1);  // Actually 200ns
558         cnt = 0;
559         CYGACC_CALL_IF_DELAY_US(10);
560         while (!CYGHWR_FLASH_TC58XXX_RDY()) cnt++;  // Wait for page data to be ready
561         CYGHWR_FLASH_TC58XXX_CLE(1);
562         put_NAND(ROM, FLASH_Status);
563         CYGHWR_FLASH_TC58XXX_CLE(0);        
564 #if FLASH_DEBUG > 1
565         diag_printf(">>\n");
566 #endif
567         stat = *ROM;
568         CYGHWR_FLASH_TC58XXX_CE(0);        
569 #if FLASH_DEBUG > 0
570         diag_printf("program at %x, stat: %x, count = %d\n", addr_ptr, stat, cnt);
571 #endif
572         addr_ptr += 512;  len -= 512;
573         if (stat != 0xC0) {
574             diag_printf("Status after write: %x\n", stat);
575             if ((stat & 0x80) == 0x00) {
576                 res = FLASH_ERR_PROTECT;
577             } else {
578                 res = FLASH_ERR_PROGRAM;
579             }
580         }
581     }
582     return res;
583 }
584
585 //----------------------------------------------------------------------------
586 // Read data into buffer
587 int
588 flash_read_buf(void* addr, void* data, int len)
589 {
590     volatile flash_data_t* ROM;
591     volatile flash_data_t* addr_ptr = (volatile flash_data_t*) addr;
592     volatile flash_data_t* data_ptr = (volatile flash_data_t*) data;
593     flash_data_t *page;
594     int res = FLASH_ERR_OK;
595     int i, cnt, offset;
596     flash_data_t stat;
597     unsigned char oob[16], dev_oob[16];
598
599     ROM = (volatile flash_data_t*) CYGNUM_FLASH_BASE;
600 #if FLASH_DEBUG > 1
601     diag_printf("<< ");
602 #endif
603     CYGHWR_FLASH_TC58XXX_CE(1);
604     CYGHWR_FLASH_TC58XXX_CLE(1);
605     if (((unsigned long)addr & 0x100) == 0) {
606         // Mode 1 - reads from start of line
607         put_NAND(ROM, FLASH_Read_Mode1);
608     } else {
609         // Mode 2 - reads from second half of line
610         put_NAND(ROM, FLASH_Read_Mode2);
611     }
612     CYGHWR_FLASH_TC58XXX_CLE(0);
613     CYGHWR_FLASH_TC58XXX_ALE(1);
614     put_NAND(ROM, ((unsigned long)addr_ptr & 0x000000FF) >> 0);   // A0..A7
615     put_NAND(ROM, ((unsigned long)addr_ptr & 0x0001FE00) >> 9);   // A9..A16
616     put_NAND(ROM, ((unsigned long)addr_ptr & 0x01FE0000) >> 17);  // A17..A24
617     if (flash_dev_info->device_size > 0x02000000) {
618         put_NAND(ROM, ((unsigned long)addr_ptr & 0x06000000) >> 25);  // A26..A27
619     }
620     CYGHWR_FLASH_TC58XXX_ALE(0);
621 #if FLASH_DEBUG > 1
622     diag_printf(">>\n");
623 #endif
624     cnt = 0;
625     CYGACC_CALL_IF_DELAY_US(10);
626     while (!CYGHWR_FLASH_TC58XXX_RDY()) cnt++;  // Wait for page data to be ready 
627 #if FLASH_DEBUG > 0
628     diag_printf("Read data starting at %p, count = %d\n", data_ptr, cnt);
629 #endif
630     offset = 0;
631     page = (unsigned char *)data_ptr;
632     while (len-- > 0) {
633         *data_ptr++ = *ROM;
634         if (++offset == 0x200) {
635             // Data page has been read, fetch ECC/OOB data
636             for (i = 0;  i < 16;  i++) {
637                 dev_oob[i] = *ROM;
638             }
639             // Calculate actual ECC on page
640             _nand_page_ECC(&page[0], &oob[0], &oob[1], &oob[2]);
641             _nand_page_ECC(&page[256], &oob[3], &oob[6], &oob[7]);
642             // Check & repair if possible
643             if ((oob[0] != dev_oob[0]) || (oob[1] != dev_oob[1]) || (oob[2] != dev_oob[2]) || 
644                 (oob[3] != dev_oob[3]) || (oob[6] != dev_oob[6]) || (oob[7] != dev_oob[7])) {
645                 unsigned char read_ecc[3], calc_ecc[3];
646                 int res;
647
648                 read_ecc[0] = dev_oob[0];  calc_ecc[0] = oob[0];
649                 read_ecc[1] = dev_oob[1];  calc_ecc[1] = oob[1];
650                 read_ecc[2] = dev_oob[2];  calc_ecc[2] = oob[2];
651                 res = _nand_correct_data(&page[0], read_ecc, calc_ecc);
652                 if ((res != 0) && (res != 1)) {
653                     diag_printf("ECC failed\n");
654                     res = FLASH_ERR_HWR;
655                     break;
656                 }
657                 read_ecc[0] = dev_oob[3];  calc_ecc[0] = oob[3];
658                 read_ecc[1] = dev_oob[6];  calc_ecc[1] = oob[6];
659                 read_ecc[2] = dev_oob[7];  calc_ecc[2] = oob[7];
660                 res = _nand_correct_data(&page[256], read_ecc, calc_ecc);
661                 if ((res != 0) && (res != 1)) {
662                     diag_printf("ECC failed\n");
663                     res = FLASH_ERR_HWR;
664                     break;
665                 }
666             }
667             cnt = 0;
668             CYGACC_CALL_IF_DELAY_US(10);
669             while (!CYGHWR_FLASH_TC58XXX_RDY()) cnt++;  // Wait for page data to be ready
670 #if FLASH_DEBUG > 0
671             diag_printf("Read data starting at %p, count = %d\n", data_ptr, cnt);
672 #endif
673             offset = 0;
674             page = (unsigned char *)data_ptr;
675         }
676     }
677     CYGHWR_FLASH_TC58XXX_CLE(1);
678     put_NAND(ROM, FLASH_Status);
679     CYGHWR_FLASH_TC58XXX_CLE(0);        
680     stat = *ROM;
681     CYGHWR_FLASH_TC58XXX_CE(0);
682     if (stat != 0xC0) {
683         diag_printf("Status after read: %x\n", stat);
684         res = FLASH_ERR_HWR;
685     }
686     return res;
687 }
688
689 #endif // CYGONCE_DEVS_FLASH_TOSHIBA_TC58XXX_INL
690
691 // EOF flash_tc58xxx.inl