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