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