]> git.sur5r.net Git - u-boot/blob - board/amirix/ap1000/flash.c
f07edf0e163bd2a12a541701b6ab019599bf278c
[u-boot] / board / amirix / ap1000 / flash.c
1 /**
2  * @file flash.c
3  */
4
5 /*
6  * (C) Copyright 2003
7  * AMIRIX Systems Inc.
8  *
9  * Originated from ppcboot-2.0.0/board/esd/cpci440/strataflash.c
10  *
11  * (C) Copyright 2002
12  * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
13  *
14  * See file CREDITS for list of people who contributed to this
15  * project.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of
20  * the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30  * MA 02111-1307 USA
31  */
32
33 #include <common.h>
34 #include <asm/processor.h>
35
36 #undef  DEBUG_FLASH
37 /*
38  * This file implements a Common Flash Interface (CFI) driver for ppcboot.
39  * The width of the port and the width of the chips are determined at initialization.
40  * These widths are used to calculate the address for access CFI data structures.
41  * It has been tested on an Intel Strataflash implementation.
42  *
43  * References
44  * JEDEC Standard JESD68 - Common Flash Interface (CFI)
45  * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
46  * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
47  * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
48  *
49  * TODO
50  * Use Primary Extended Query table (PRI) and Alternate Algorithm Query Table (ALT) to determine if protection is available
51  * Add support for other command sets Use the PRI and ALT to determine command set
52  * Verify erase and program timeouts.
53  */
54
55 #define FLASH_CMD_CFI           0x98
56 #define FLASH_CMD_READ_ID       0x90
57 #define FLASH_CMD_RESET         0xff
58 #define FLASH_CMD_BLOCK_ERASE       0x20
59 #define FLASH_CMD_ERASE_CONFIRM     0xD0
60 #define FLASH_CMD_WRITE         0x40
61 #define FLASH_CMD_PROTECT       0x60
62 #define FLASH_CMD_PROTECT_SET       0x01
63 #define FLASH_CMD_PROTECT_CLEAR     0xD0
64 #define FLASH_CMD_CLEAR_STATUS      0x50
65 #define FLASH_CMD_WRITE_TO_BUFFER       0xE8
66 #define FLASH_CMD_WRITE_BUFFER_CONFIRM  0xD0
67
68 #define FLASH_STATUS_DONE       0x80
69 #define FLASH_STATUS_ESS        0x40
70 #define FLASH_STATUS_ECLBS      0x20
71 #define FLASH_STATUS_PSLBS      0x10
72 #define FLASH_STATUS_VPENS      0x08
73 #define FLASH_STATUS_PSS        0x04
74 #define FLASH_STATUS_DPS        0x02
75 #define FLASH_STATUS_R          0x01
76 #define FLASH_STATUS_PROTECT        0x01
77
78 #define FLASH_OFFSET_CFI        0x55
79 #define FLASH_OFFSET_CFI_RESP       0x10
80 #define FLASH_OFFSET_WTOUT      0x1F
81 #define FLASH_OFFSET_WBTOUT             0x20
82 #define FLASH_OFFSET_ETOUT      0x21
83 #define FLASH_OFFSET_CETOUT             0x22
84 #define FLASH_OFFSET_WMAX_TOUT      0x23
85 #define FLASH_OFFSET_WBMAX_TOUT         0x24
86 #define FLASH_OFFSET_EMAX_TOUT      0x25
87 #define FLASH_OFFSET_CEMAX_TOUT         0x26
88 #define FLASH_OFFSET_SIZE       0x27
89 #define FLASH_OFFSET_INTERFACE          0x28
90 #define FLASH_OFFSET_BUFFER_SIZE        0x2A
91 #define FLASH_OFFSET_NUM_ERASE_REGIONS  0x2C
92 #define FLASH_OFFSET_ERASE_REGIONS  0x2D
93 #define FLASH_OFFSET_PROTECT        0x02
94 #define FLASH_OFFSET_USER_PROTECTION    0x85
95 #define FLASH_OFFSET_INTEL_PROTECTION   0x81
96
97
98 #define FLASH_MAN_CFI           0x01000000
99
100
101
102
103 typedef union {
104     unsigned char c;
105     unsigned short w;
106     unsigned long l;
107 } cfiword_t;
108
109 typedef union {
110     unsigned char * cp;
111     unsigned short *wp;
112     unsigned long *lp;
113 } cfiptr_t;
114
115 #define NUM_ERASE_REGIONS 4
116
117 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips    */
118
119
120 /*-----------------------------------------------------------------------
121  * Functions
122  */
123
124
125
126 static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c);
127 static void flash_make_cmd(flash_info_t * info, uchar cmd, void * cmdbuf);
128 static void flash_write_cmd(flash_info_t * info, int sect, uchar offset, uchar cmd);
129 static int flash_isequal(flash_info_t * info, int sect, uchar offset, uchar cmd);
130 static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd);
131 static int flash_detect_cfi(flash_info_t * info);
132 static ulong flash_get_size (ulong base, int banknum);
133 static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword);
134 static int flash_full_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt);
135 #ifdef CFG_FLASH_USE_BUFFER_WRITE
136 static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len);
137 #endif
138 /*-----------------------------------------------------------------------
139  * create an address based on the offset and the port width
140  */
141 uchar * flash_make_addr(flash_info_t * info, int sect, int offset)
142 {
143     return ((uchar *)(info->start[sect] + (offset * info->chipwidth)));
144 }
145 /*-----------------------------------------------------------------------
146  * read a character at a port width address
147  */
148 uchar flash_read_uchar(flash_info_t * info, uchar offset)
149 {
150     if (info->portwidth == FLASH_CFI_8BIT) {
151         volatile uchar *cp;
152         uchar c;
153         cp = flash_make_addr(info, 0, offset);
154         c = *cp;
155 #ifdef DEBUG_FLASH
156         printf("flash_read_uchar offset=%04x ptr=%08x c=%02x\n",
157                         offset, (unsigned int)cp, c);
158 #endif
159         return (c);
160
161     } else if (info->portwidth == FLASH_CFI_16BIT) {
162         volatile ushort *sp;
163         ushort s;
164         uchar c;
165         sp = (ushort*)flash_make_addr(info, 0, offset);
166         s = *sp;
167         c = (uchar)s;
168 #ifdef DEBUG_FLASH
169         printf("flash_read_uchar offset=%04x ptr=%08x s=%04x c=%02x\n",
170                        offset, (unsigned int)sp, s, c);
171 #endif
172         return (c);
173
174     }
175
176     return 0;
177 }
178
179 /*-----------------------------------------------------------------------
180  * read a short word by swapping for ppc format.
181  */
182 ushort flash_read_ushort(flash_info_t * info, int sect,  uchar offset)
183 {
184     if (info->portwidth == FLASH_CFI_8BIT) {
185         volatile uchar *cp;
186         uchar c0, c1;
187         ushort s;
188         cp = flash_make_addr(info, 0, offset);
189         c1 = cp[2];
190         c0 = cp[0];
191         s = c1<<8 | c0;
192 #ifdef DEBUG_FLASH
193         printf("flash_read_ushort offset=%04x ptr=%08x c1=%02x c0=%02x s=%04x\n",
194                         offset, (unsigned int)cp, c1, c0, s);
195 #endif
196         return (s);
197
198     } else if (info->portwidth == FLASH_CFI_16BIT) {
199         volatile ushort *sp;
200         ushort s;
201         uchar c0, c1;
202         sp = (ushort*)flash_make_addr(info, 0, offset);
203         s = *sp;
204         c1 = (uchar)sp[1];
205         c0 = (uchar)sp[0];
206         s = c1<<8 | c0;
207 #ifdef DEBUG_FLASH
208         printf("flash_read_ushort offset=%04x ptr=%08x c1=%02x c0=%02x s=%04x\n",
209                         offset, (unsigned int)sp, c1, c0, s);
210 #endif
211         return (s);
212
213     }
214
215     return 0;
216 }
217
218 /*-----------------------------------------------------------------------
219  * read a long word by picking the least significant byte of each maiximum
220  * port size word. Swap for ppc format.
221  */
222 ulong flash_read_long(flash_info_t * info, int sect,  uchar offset)
223 {
224     if (info->portwidth == FLASH_CFI_8BIT) {
225         volatile uchar *cp;
226         uchar c0, c1, c2, c3;
227         ulong l;
228         cp = flash_make_addr(info, 0, offset);
229         c3 = cp[6];
230         c2 = cp[4];
231         c1 = cp[2];
232         c0 = cp[0];
233         l = c3<<24 | c2<<16 | c1<<8 | c0;
234 #ifdef DEBUG_FLASH
235         printf("flash_read_long offset=%04x ptr=%08x c3=%02x c2=%02x c1=%02x c0=%02x l=%08x\n",
236                         offset, (unsigned int)cp, c3, c2, c1, c0, l);
237 #endif
238         return (l);
239
240     } else if (info->portwidth == FLASH_CFI_16BIT) {
241         volatile ushort *sp;
242         uchar c0, c1, c2, c3;
243         ulong l;
244         sp = (ushort*)flash_make_addr(info, 0, offset);
245         c3 = (uchar)sp[3];
246         c2 = (uchar)sp[2];
247         c1 = (uchar)sp[1];
248         c0 = (uchar)sp[0];
249         l = c3<<24 | c2<<16 | c1<<8 | c0;
250 #ifdef DEBUG_FLASH
251         printf("flash_read_long offset=%04x ptr=%08x c3=%02x c2=%02x c1=%02x c0=%02x l=%08x\n",
252                         offset, (unsigned int)sp, c3, c2, c1, c0, l);
253 #endif
254         return (l);
255
256     }
257
258     return 0;
259 }
260
261 /*-----------------------------------------------------------------------
262  */
263 unsigned long flash_init (void)
264 {
265     unsigned long size;
266
267     size = 0;
268
269     flash_info[0].flash_id = FLASH_UNKNOWN;
270     flash_info[0].portwidth = FLASH_CFI_16BIT;
271     flash_info[0].chipwidth = FLASH_CFI_16BIT;
272     size += flash_info[0].size = flash_get_size(CFG_PROGFLASH_BASE, 0);
273     if (flash_info[0].flash_id == FLASH_UNKNOWN) {
274         printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", 1,
275         flash_info[0].size, flash_info[0].size<<20);
276         };
277
278     flash_info[1].flash_id = FLASH_UNKNOWN;
279     flash_info[1].portwidth = FLASH_CFI_8BIT;
280     flash_info[1].chipwidth = FLASH_CFI_16BIT;
281     size += flash_info[1].size = flash_get_size(CFG_CONFFLASH_BASE, 1);
282     if (flash_info[1].flash_id == FLASH_UNKNOWN) {
283         printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", 2,
284         flash_info[1].size, flash_info[1].size<<20);
285     };
286
287     return (size);
288 }
289
290 /*-----------------------------------------------------------------------
291  */
292 int flash_erase (flash_info_t *info, int s_first, int s_last)
293 {
294     int rcode = 0;
295     int prot;
296     int sect;
297
298     if( info->flash_id != FLASH_MAN_CFI) {
299         printf ("Can't erase unknown flash type - aborted\n");
300         return 1;
301     }
302     if ((s_first < 0) || (s_first > s_last)) {
303         printf ("- no sectors to erase\n");
304         return 1;
305     }
306
307     prot = 0;
308     for (sect=s_first; sect<=s_last; ++sect) {
309         if (info->protect[sect]) {
310             prot++;
311         }
312     }
313     if (prot) {
314         printf ("- Warning: %d protected sectors will not be erased!\n",
315             prot);
316     } else {
317         printf ("\n");
318     }
319
320
321     for (sect = s_first; sect<=s_last; sect++) {
322         if (info->protect[sect] == 0) { /* not protected */
323             flash_write_cmd(info, sect, 0, FLASH_CMD_CLEAR_STATUS);
324             flash_write_cmd(info, sect, 0, FLASH_CMD_BLOCK_ERASE);
325             flash_write_cmd(info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
326
327             if(flash_full_status_check(info, sect, info->erase_blk_tout, "erase")) {
328                 rcode = 1;
329             } else
330                 printf(".");
331         }
332     }
333     printf (" done\n");
334     return rcode;
335 }
336
337 /*-----------------------------------------------------------------------
338  */
339 void flash_print_info  (flash_info_t *info)
340 {
341     int i;
342
343     if (info->flash_id != FLASH_MAN_CFI) {
344         printf ("missing or unknown FLASH type\n");
345         return;
346     }
347
348     printf("CFI conformant FLASH (x%d device in x%d mode)",
349            (info->chipwidth  << 3 ), (info->portwidth  << 3 ));
350     printf ("  Size: %ld MB in %d Sectors\n",
351         info->size >> 20, info->sector_count);
352     printf(" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n",
353            info->erase_blk_tout, info->write_tout, info->buffer_write_tout, info->buffer_size);
354
355     printf ("  Sector Start Addresses:");
356     for (i=0; i<info->sector_count; ++i) {
357         if ((i % 5) == 0)
358             printf ("\n");
359         printf (" %08lX%5s",
360             info->start[i],
361             info->protect[i] ? " (RO)" : " "
362             );
363     }
364     printf ("\n");
365     return;
366 }
367
368 /*-----------------------------------------------------------------------
369  * Copy memory to flash, returns:
370  * 0 - OK
371  * 1 - write timeout
372  * 2 - Flash not erased
373  */
374 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
375 {
376     ulong wp;
377     ulong cp;
378     int aln;
379     cfiword_t cword;
380     int i, rc;
381
382     /* get lower aligned address */
383     wp = (addr & ~(info->portwidth - 1));
384
385     /* handle unaligned start */
386     if((aln = addr - wp) != 0) {
387         cword.l = 0;
388         cp = wp;
389         for(i=0;i<aln; ++i, ++cp)
390             flash_add_byte(info, &cword, (*(uchar *)cp));
391
392         for(; (i< info->portwidth) && (cnt > 0) ; i++) {
393             flash_add_byte(info, &cword, *src++);
394             cnt--;
395             cp++;
396         }
397         for(; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
398             flash_add_byte(info, &cword, (*(uchar *)cp));
399         if((rc = flash_write_cfiword(info, wp, cword)) != 0)
400             return rc;
401         wp = cp;
402     }
403
404 #ifdef CFG_FLASH_USE_BUFFER_WRITE
405     while(cnt >= info->portwidth) {
406         i = info->buffer_size > cnt? cnt: info->buffer_size;
407         if((rc = flash_write_cfibuffer(info, wp, src,i)) != ERR_OK)
408             return rc;
409         wp += i;
410         src += i;
411         cnt -=i;
412     }
413 #else
414     /* handle the aligned part */
415     while(cnt >= info->portwidth) {
416         cword.l = 0;
417         for(i = 0; i < info->portwidth; i++) {
418             flash_add_byte(info, &cword, *src++);
419         }
420         if((rc = flash_write_cfiword(info, wp, cword)) != 0)
421             return rc;
422         wp += info->portwidth;
423         cnt -= info->portwidth;
424     }
425 #endif /* CFG_FLASH_USE_BUFFER_WRITE */
426     if (cnt == 0) {
427         return (0);
428     }
429
430     /*
431      * handle unaligned tail bytes
432      */
433     cword.l = 0;
434     for (i=0, cp=wp; (i<info->portwidth) && (cnt>0); ++i, ++cp) {
435         flash_add_byte(info, &cword, *src++);
436         --cnt;
437     }
438     for (; i<info->portwidth; ++i, ++cp) {
439         flash_add_byte(info, & cword, (*(uchar *)cp));
440     }
441
442     return flash_write_cfiword(info, wp, cword);
443 }
444
445 /*-----------------------------------------------------------------------
446  */
447 int flash_real_protect(flash_info_t *info, long sector, int prot)
448 {
449     int retcode = 0;
450
451     flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
452     flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT);
453     if(prot)
454         flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_SET);
455     else
456         flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
457
458     if((retcode = flash_full_status_check(info, sector, info->erase_blk_tout,
459                      prot?"protect":"unprotect")) == 0) {
460
461         info->protect[sector] = prot;
462         /* Intel's unprotect unprotects all locking */
463         if(prot == 0) {
464             int i;
465             for(i = 0 ; i<info->sector_count; i++) {
466                 if(info->protect[i])
467                     flash_real_protect(info, i, 1);
468             }
469         }
470     }
471
472     return retcode;
473 }
474 /*-----------------------------------------------------------------------
475  *  wait for XSR.7 to be set. Time out with an error if it does not.
476  *  This routine does not set the flash to read-array mode.
477  */
478 static int flash_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt)
479 {
480     ulong start;
481
482     /* Wait for command completion */
483     start = get_timer (0);
484     while(!flash_isset(info, sector, 0, FLASH_STATUS_DONE)) {
485         if (get_timer(start) > info->erase_blk_tout) {
486             printf("Flash %s timeout at address %lx\n", prompt, info->start[sector]);
487             flash_write_cmd(info, sector, 0, FLASH_CMD_RESET);
488             return ERR_TIMOUT;
489         }
490     }
491     return ERR_OK;
492 }
493 /*-----------------------------------------------------------------------
494  * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
495  * This routine sets the flash to read-array mode.
496  */
497 static int flash_full_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt)
498 {
499     int retcode;
500     retcode = flash_status_check(info, sector, tout, prompt);
501     if((retcode == ERR_OK) && !flash_isequal(info,sector, 0, FLASH_STATUS_DONE)) {
502         retcode = ERR_INVAL;
503         printf("Flash %s error at address %lx\n", prompt,info->start[sector]);
504         if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)){
505             printf("Command Sequence Error.\n");
506         } else if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS)){
507             printf("Block Erase Error.\n");
508                 retcode = ERR_NOT_ERASED;
509         } else if (flash_isset(info, sector, 0, FLASH_STATUS_PSLBS)) {
510             printf("Locking Error\n");
511         }
512         if(flash_isset(info, sector, 0, FLASH_STATUS_DPS)){
513             printf("Block locked.\n");
514             retcode = ERR_PROTECTED;
515         }
516         if(flash_isset(info, sector, 0, FLASH_STATUS_VPENS))
517             printf("Vpp Low Error.\n");
518     }
519     flash_write_cmd(info, sector, 0, FLASH_CMD_RESET);
520     return retcode;
521 }
522 /*-----------------------------------------------------------------------
523  */
524 static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c)
525 {
526     switch(info->portwidth) {
527     case FLASH_CFI_8BIT:
528         cword->c = c;
529         break;
530     case FLASH_CFI_16BIT:
531         cword->w = (cword->w << 8) | c;
532         break;
533     case FLASH_CFI_32BIT:
534         cword->l = (cword->l << 8) | c;
535     }
536 }
537
538
539 /*-----------------------------------------------------------------------
540  * make a proper sized command based on the port and chip widths
541  */
542 static void flash_make_cmd(flash_info_t * info, uchar cmd, void * cmdbuf)
543 {
544     //int i;
545     uchar *cp = (uchar *)cmdbuf;
546     // for(i=0; i< info->portwidth; i++)
547     //  *cp++ = ((i+1) % info->chipwidth) ? '\0':cmd;
548         if (info->portwidth == FLASH_CFI_8BIT && info->chipwidth == FLASH_CFI_16BIT) {
549         cp[0] = cmd;
550         } else if (info->portwidth == FLASH_CFI_16BIT && info->chipwidth == FLASH_CFI_16BIT) {
551         cp[0] = '\0';
552         cp[1] = cmd;
553     };
554 }
555
556 /*
557  * Write a proper sized command to the correct address
558  */
559 static void flash_write_cmd(flash_info_t * info, int sect, uchar offset, uchar cmd)
560 {
561
562     volatile cfiptr_t addr;
563     cfiword_t cword;
564     addr.cp = flash_make_addr(info, sect, offset);
565     flash_make_cmd(info, cmd, &cword);
566     switch(info->portwidth) {
567     case FLASH_CFI_8BIT:
568         *addr.cp = cword.c;
569         break;
570     case FLASH_CFI_16BIT:
571         *addr.wp = cword.w;
572         break;
573     case FLASH_CFI_32BIT:
574         *addr.lp = cword.l;
575         break;
576     }
577 }
578
579 /*-----------------------------------------------------------------------
580  */
581 static int flash_isequal(flash_info_t * info, int sect, uchar offset, uchar cmd)
582 {
583     cfiptr_t cptr;
584     cfiword_t cword;
585     int retval;
586     cptr.cp = flash_make_addr(info, sect, offset);
587     flash_make_cmd(info, cmd, &cword);
588     switch(info->portwidth) {
589     case FLASH_CFI_8BIT:
590         retval = (cptr.cp[0] == cword.c);
591         break;
592     case FLASH_CFI_16BIT:
593         retval = (cptr.wp[0] == cword.w);
594         break;
595     case FLASH_CFI_32BIT:
596         retval = (cptr.lp[0] == cword.l);
597         break;
598     default:
599         retval = 0;
600         break;
601     }
602     return retval;
603 }
604 /*-----------------------------------------------------------------------
605  */
606 static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd)
607 {
608     cfiptr_t cptr;
609     cfiword_t cword;
610     int retval;
611     cptr.cp = flash_make_addr(info, sect, offset);
612     flash_make_cmd(info, cmd, &cword);
613     switch(info->portwidth) {
614     case FLASH_CFI_8BIT:
615         retval = ((cptr.cp[0] & cword.c) == cword.c);
616         break;
617     case FLASH_CFI_16BIT:
618         retval = ((cptr.wp[0] & cword.w) == cword.w);
619         break;
620     case FLASH_CFI_32BIT:
621         retval = ((cptr.lp[0] & cword.l) == cword.l);
622         break;
623     default:
624         retval = 0;
625         break;
626     }
627     return retval;
628 }
629
630 /*-----------------------------------------------------------------------
631  * detect if flash is compatible with the Common Flash Interface (CFI)
632  * http://www.jedec.org/download/search/jesd68.pdf
633  *
634 */
635 static int flash_detect_cfi(flash_info_t * info)
636 {
637
638 #if 0
639     for(info->portwidth=FLASH_CFI_8BIT; info->portwidth <= FLASH_CFI_32BIT;
640         info->portwidth <<= 1) {
641         for(info->chipwidth =FLASH_CFI_BY8;
642             info->chipwidth <= info->portwidth;
643             info->chipwidth <<= 1) {
644             flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
645             flash_write_cmd(info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
646             if(flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP,'Q') &&
647                flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') &&
648                flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y'))
649                 return 1;
650         }
651     }
652 #endif
653     flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
654     flash_write_cmd(info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
655     if(flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP,'Q') &&
656        flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') &&
657        flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
658         return 1;
659     } else {
660         return 0;
661     };
662 }
663 /*
664  * The following code cannot be run from FLASH!
665  *
666  */
667 static ulong flash_get_size (ulong base, int banknum)
668 {
669     flash_info_t * info = &flash_info[banknum];
670     int i, j;
671     int sect_cnt;
672     unsigned long sector;
673     unsigned long tmp;
674     int size_ratio;
675     uchar num_erase_regions;
676     int  erase_region_size;
677     int  erase_region_count;
678
679     info->start[0] = base;
680
681     if(flash_detect_cfi(info)){
682 #ifdef DEBUG_FLASH
683         printf("portwidth=%d chipwidth=%d\n", info->portwidth, info->chipwidth); /* test-only */
684 #endif
685         size_ratio = 1; // info->portwidth / info->chipwidth;
686         num_erase_regions = flash_read_uchar(info, FLASH_OFFSET_NUM_ERASE_REGIONS);
687 #ifdef DEBUG_FLASH
688         printf("found %d erase regions\n", num_erase_regions);
689 #endif
690         sect_cnt = 0;
691         sector = base;
692         for(i = 0 ; i < num_erase_regions; i++) {
693             if(i > NUM_ERASE_REGIONS) {
694                 printf("%d erase regions found, only %d used\n",
695                        num_erase_regions, NUM_ERASE_REGIONS);
696                 break;
697             }
698             tmp = flash_read_long(info, 0, FLASH_OFFSET_ERASE_REGIONS);
699             erase_region_count = (tmp & 0xffff) +1;
700             tmp >>= 16;
701             erase_region_size = (tmp & 0xffff)? ((tmp & 0xffff) * 256): 128;
702             for(j = 0; j< erase_region_count; j++) {
703                 info->start[sect_cnt] = sector;
704                 sector += (erase_region_size * size_ratio);
705                 info->protect[sect_cnt] = flash_isset(info, sect_cnt, FLASH_OFFSET_PROTECT, FLASH_STATUS_PROTECT);
706                 sect_cnt++;
707             }
708         }
709
710         info->sector_count = sect_cnt;
711         /* multiply the size by the number of chips */
712         info->size = (1 << flash_read_uchar(info, FLASH_OFFSET_SIZE)) * size_ratio;
713         info->buffer_size = (1 << flash_read_ushort(info, 0, FLASH_OFFSET_BUFFER_SIZE));
714         tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_ETOUT);
715         info->erase_blk_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_EMAX_TOUT)));
716         tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WBTOUT);
717         info->buffer_write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WBMAX_TOUT)));
718         tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WTOUT);
719         info->write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WMAX_TOUT)))/ 1000;
720         info->flash_id = FLASH_MAN_CFI;
721     }
722
723     flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
724     return(info->size);
725 }
726
727
728 /*-----------------------------------------------------------------------
729  */
730 static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword)
731 {
732
733     cfiptr_t ctladdr;
734     cfiptr_t cptr;
735     int flag;
736
737     ctladdr.cp = flash_make_addr(info, 0, 0);
738     cptr.cp = (uchar *)dest;
739
740
741     /* Check if Flash is (sufficiently) erased */
742     switch(info->portwidth) {
743     case FLASH_CFI_8BIT:
744         flag = ((cptr.cp[0] & cword.c) == cword.c);
745         break;
746     case FLASH_CFI_16BIT:
747         flag = ((cptr.wp[0] & cword.w) == cword.w);
748         break;
749     case FLASH_CFI_32BIT:
750         flag = ((cptr.lp[0] & cword.l)  == cword.l);
751         break;
752     default:
753         return 2;
754     }
755     if(!flag)
756         return 2;
757
758     /* Disable interrupts which might cause a timeout here */
759     flag = disable_interrupts();
760
761     flash_write_cmd(info, 0, 0, FLASH_CMD_CLEAR_STATUS);
762     flash_write_cmd(info, 0, 0, FLASH_CMD_WRITE);
763
764     switch(info->portwidth) {
765     case FLASH_CFI_8BIT:
766         cptr.cp[0] = cword.c;
767         break;
768     case FLASH_CFI_16BIT:
769         cptr.wp[0] = cword.w;
770         break;
771     case FLASH_CFI_32BIT:
772         cptr.lp[0] = cword.l;
773         break;
774     }
775
776     /* re-enable interrupts if necessary */
777     if(flag)
778         enable_interrupts();
779
780     return flash_full_status_check(info, 0, info->write_tout, "write");
781 }
782
783 #ifdef CFG_FLASH_USE_BUFFER_WRITE
784
785 /* loop through the sectors from the highest address
786  * when the passed address is greater or equal to the sector address
787  * we have a match
788  */
789 static int find_sector(flash_info_t *info, ulong addr)
790 {
791     int sector;
792     for(sector = info->sector_count - 1; sector >= 0; sector--) {
793         if(addr >= info->start[sector])
794             break;
795     }
796     return sector;
797 }
798
799 static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len)
800 {
801
802     int sector;
803     int cnt;
804     int retcode;
805     volatile cfiptr_t src;
806     volatile cfiptr_t dst;
807
808     src.cp = cp;
809     dst.cp = (uchar *)dest;
810     sector = find_sector(info, dest);
811     flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
812     flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
813     if((retcode = flash_status_check(info, sector, info->buffer_write_tout,
814                      "write to buffer")) == ERR_OK) {
815         switch(info->portwidth) {
816         case FLASH_CFI_8BIT:
817             cnt = len;
818             break;
819         case FLASH_CFI_16BIT:
820             cnt = len >> 1;
821             break;
822         case FLASH_CFI_32BIT:
823             cnt = len >> 2;
824             break;
825         default:
826             return ERR_INVAL;
827             break;
828         }
829         flash_write_cmd(info, sector, 0, (uchar)cnt-1);
830         while(cnt-- > 0) {
831             switch(info->portwidth) {
832             case FLASH_CFI_8BIT:
833                 *dst.cp++ = *src.cp++;
834                 break;
835             case FLASH_CFI_16BIT:
836                 *dst.wp++ = *src.wp++;
837                 break;
838             case FLASH_CFI_32BIT:
839                 *dst.lp++ = *src.lp++;
840                 break;
841             default:
842                 return ERR_INVAL;
843                 break;
844             }
845         }
846         flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM);
847         retcode = flash_full_status_check(info, sector, info->buffer_write_tout,
848                          "buffer write");
849     }
850     flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
851     return retcode;
852 }
853 #endif /* CFG_USE_FLASH_BUFFER_WRITE */