]> git.sur5r.net Git - u-boot/blob - board/bubinga405ep/flash.c
f93dcd4f9d3673be71d2e5b8bff6759d234237cd
[u-boot] / board / bubinga405ep / flash.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * Modified 4/5/2001
26  * Wait for completion of each sector erase command issued
27  * 4/5/2001
28  * Chris Hallinan - DS4.COM, Inc. - clh@net1plus.com
29  */
30
31 #include <common.h>
32 #include <ppc4xx.h>
33 #include <asm/processor.h>
34
35 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
36
37 /*-----------------------------------------------------------------------
38  * Functions
39  */
40 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
41 static int write_word (flash_info_t *info, ulong dest, ulong data);
42 static void flash_get_offsets (ulong base, flash_info_t *info);
43
44 #ifdef CONFIG_ADCIOP
45 #define ADDR0           0x0aa9
46 #define ADDR1           0x0556
47 #define FLASH_WORD_SIZE unsigned char
48 #endif
49
50 #ifdef CONFIG_CPCI405
51 #define ADDR0           0x5555
52 #define ADDR1           0x2aaa
53 #define FLASH_WORD_SIZE unsigned short
54 #endif
55
56 #ifdef CONFIG_WALNUT405
57 #define ADDR0           0x5555
58 #define ADDR1           0x2aaa
59 #define FLASH_WORD_SIZE unsigned char
60 #endif
61
62 #ifdef CONFIG_BUBINGA405EP
63 #define ADDR0           0x5555
64 #define ADDR1           0x2aaa
65 #define FLASH_WORD_SIZE unsigned char
66 #endif
67
68
69 /*-----------------------------------------------------------------------
70  */
71
72 unsigned long flash_init (void)
73 {
74         unsigned long size_b0, size_b1;
75         int i;
76         uint pbcr;
77         unsigned long base_b0, base_b1;
78
79         /* Init: no FLASHes known */
80         for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
81                 flash_info[i].flash_id = FLASH_UNKNOWN;
82         }
83
84         /* Static FLASH Bank configuration here - FIXME XXX */
85
86         size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
87
88         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
89                 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
90                         size_b0, size_b0<<20);
91         }
92
93         /* Only one bank */
94         if (CFG_MAX_FLASH_BANKS == 1)
95           {
96             /* Setup offsets */
97             flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]);
98
99             /* Monitor protection ON by default */
100             (void)flash_protect(FLAG_PROTECT_SET,
101                                 FLASH_BASE0_PRELIM,
102                                 FLASH_BASE0_PRELIM+CFG_MONITOR_LEN-1,
103                                 &flash_info[0]);
104             size_b1 = 0 ;
105             flash_info[0].size = size_b0;
106           }
107
108         /* 2 banks */
109         else
110           {
111             size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
112
113             /* Re-do sizing to get full correct info */
114
115             if (size_b1)
116               {
117                 mtdcr(ebccfga, pb0cr);
118                 pbcr = mfdcr(ebccfgd);
119                 mtdcr(ebccfga, pb0cr);
120                 base_b1 = -size_b1;
121                 pbcr = (pbcr & 0x0001ffff) | base_b1 | (((size_b1/1024/1024)-1)<<17);
122                 mtdcr(ebccfgd, pbcr);
123                 /*          printf("pb1cr = %x\n", pbcr); */
124               }
125
126             if (size_b0)
127               {
128                 mtdcr(ebccfga, pb1cr);
129                 pbcr = mfdcr(ebccfgd);
130                 mtdcr(ebccfga, pb1cr);
131                 base_b0 = base_b1 - size_b0;
132                 pbcr = (pbcr & 0x0001ffff) | base_b0 | (((size_b0/1024/1024)-1)<<17);
133                 mtdcr(ebccfgd, pbcr);
134                 /*            printf("pb0cr = %x\n", pbcr); */
135               }
136
137             size_b0 = flash_get_size((vu_long *)base_b0, &flash_info[0]);
138
139             flash_get_offsets (base_b0, &flash_info[0]);
140
141             /* monitor protection ON by default */
142             (void)flash_protect(FLAG_PROTECT_SET,
143                                 base_b0+size_b0-CFG_MONITOR_LEN,
144                                 base_b0+size_b0-1,
145                                 &flash_info[0]);
146
147             if (size_b1) {
148               /* Re-do sizing to get full correct info */
149               size_b1 = flash_get_size((vu_long *)base_b1, &flash_info[1]);
150
151               flash_get_offsets (base_b1, &flash_info[1]);
152
153               /* monitor protection ON by default */
154               (void)flash_protect(FLAG_PROTECT_SET,
155                                   base_b1+size_b1-CFG_MONITOR_LEN,
156                                   base_b1+size_b1-1,
157                                   &flash_info[1]);
158               /* monitor protection OFF by default (one is enough) */
159               (void)flash_protect(FLAG_PROTECT_CLEAR,
160                                   base_b0+size_b0-CFG_MONITOR_LEN,
161                                   base_b0+size_b0-1,
162                                   &flash_info[0]);
163             } else {
164               flash_info[1].flash_id = FLASH_UNKNOWN;
165               flash_info[1].sector_count = -1;
166             }
167
168             flash_info[0].size = size_b0;
169             flash_info[1].size = size_b1;
170           }/* else 2 banks */
171         return (size_b0 + size_b1);
172 }
173
174
175
176 /*-----------------------------------------------------------------------
177  */
178 static void flash_get_offsets (ulong base, flash_info_t *info)
179 {
180         int i;
181
182         /* set up sector start address table */
183         if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
184             (info->flash_id  == FLASH_AM040)){
185             for (i = 0; i < info->sector_count; i++)
186                 info->start[i] = base + (i * 0x00010000);
187         } else {
188             if (info->flash_id & FLASH_BTYPE) {
189                 /* set sector offsets for bottom boot block type        */
190                 info->start[0] = base + 0x00000000;
191                 info->start[1] = base + 0x00004000;
192                 info->start[2] = base + 0x00006000;
193                 info->start[3] = base + 0x00008000;
194                 for (i = 4; i < info->sector_count; i++) {
195                         info->start[i] = base + (i * 0x00010000) - 0x00030000;
196                 }
197             } else {
198                 /* set sector offsets for top boot block type           */
199                 i = info->sector_count - 1;
200                 info->start[i--] = base + info->size - 0x00004000;
201                 info->start[i--] = base + info->size - 0x00006000;
202                 info->start[i--] = base + info->size - 0x00008000;
203                 for (; i >= 0; i--) {
204                         info->start[i] = base + i * 0x00010000;
205                 }
206             }
207         }
208 }
209
210 /*-----------------------------------------------------------------------
211  */
212 void flash_print_info  (flash_info_t *info)
213 {
214         int i;
215         int k;
216         int size;
217         int erased;
218         volatile unsigned long *flash;
219
220         if (info->flash_id == FLASH_UNKNOWN) {
221                 printf ("missing or unknown FLASH type\n");
222                 return;
223         }
224
225         switch (info->flash_id & FLASH_VENDMASK) {
226         case FLASH_MAN_AMD:     printf ("AMD ");                break;
227         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
228         case FLASH_MAN_SST:     printf ("SST ");                break;
229         default:                printf ("Unknown Vendor ");     break;
230         }
231
232         switch (info->flash_id & FLASH_TYPEMASK) {
233         case FLASH_AM040:       printf ("AM29F040 (512 Kbit, uniform sector size)\n");
234                                 break;
235         case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
236                                 break;
237         case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
238                                 break;
239         case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
240                                 break;
241         case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
242                                 break;
243         case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
244                                 break;
245         case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
246                                 break;
247         case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
248                                 break;
249         case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
250                                 break;
251         case FLASH_SST800A:     printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
252                                 break;
253         case FLASH_SST160A:     printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
254                                 break;
255         default:                printf ("Unknown Chip Type\n");
256                                 break;
257         }
258
259         printf ("  Size: %ld KB in %d Sectors\n",
260                 info->size >> 10, info->sector_count);
261
262         printf ("  Sector Start Addresses:");
263         for (i=0; i<info->sector_count; ++i) {
264                 /*
265                  * Check if whole sector is erased
266                  */
267                 if (i != (info->sector_count-1))
268                   size = info->start[i+1] - info->start[i];
269                 else
270                   size = info->start[0] + info->size - info->start[i];
271                 erased = 1;
272                 flash = (volatile unsigned long *)info->start[i];
273                 size = size >> 2;        /* divide by 4 for longword access */
274                 for (k=0; k<size; k++)
275                   {
276                     if (*flash++ != 0xffffffff)
277                       {
278                         erased = 0;
279                         break;
280                       }
281                   }
282
283                 if ((i % 5) == 0)
284                         printf ("\n   ");
285 #if 0 /* test-only */
286                 printf (" %08lX%s",
287                         info->start[i],
288                         info->protect[i] ? " (RO)" : "     "
289 #else
290                 printf (" %08lX%s%s",
291                         info->start[i],
292                         erased ? " E" : "  ",
293                         info->protect[i] ? "RO " : "   "
294 #endif
295                 );
296         }
297         printf ("\n");
298         return;
299 }
300
301 /*-----------------------------------------------------------------------
302  */
303
304
305 /*-----------------------------------------------------------------------
306  */
307
308 /*
309  * The following code cannot be run from FLASH!
310  */
311 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
312 {
313         short i;
314         FLASH_WORD_SIZE value;
315         ulong base = (ulong)addr;
316         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
317
318         /* Write auto select command: read Manufacturer ID */
319         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
320         addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
321         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
322
323 #ifdef CONFIG_ADCIOP
324         value = addr2[2];
325 #else
326         value = addr2[0];
327 #endif
328
329         switch (value) {
330         case (FLASH_WORD_SIZE)AMD_MANUFACT:
331                 info->flash_id = FLASH_MAN_AMD;
332                 break;
333         case (FLASH_WORD_SIZE)FUJ_MANUFACT:
334                 info->flash_id = FLASH_MAN_FUJ;
335                 break;
336         case (FLASH_WORD_SIZE)SST_MANUFACT:
337                 info->flash_id = FLASH_MAN_SST;
338                 break;
339         default:
340                 info->flash_id = FLASH_UNKNOWN;
341                 info->sector_count = 0;
342                 info->size = 0;
343                 return (0);                     /* no or unknown flash  */
344         }
345
346 #ifdef CONFIG_ADCIOP
347         value = addr2[0];                       /* device ID            */
348         /*        printf("\ndev_code=%x\n", value); */
349 #else
350         value = addr2[1];                       /* device ID            */
351 #endif
352
353         switch (value) {
354         case (FLASH_WORD_SIZE)AMD_ID_F040B:
355                 info->flash_id += FLASH_AM040;
356                 info->sector_count = 8;
357                 info->size = 0x0080000; /* => 512 ko */
358                 break;
359         case (FLASH_WORD_SIZE)AMD_ID_LV400T:
360                 info->flash_id += FLASH_AM400T;
361                 info->sector_count = 11;
362                 info->size = 0x00080000;
363                 break;                          /* => 0.5 MB            */
364
365         case (FLASH_WORD_SIZE)AMD_ID_LV400B:
366                 info->flash_id += FLASH_AM400B;
367                 info->sector_count = 11;
368                 info->size = 0x00080000;
369                 break;                          /* => 0.5 MB            */
370
371         case (FLASH_WORD_SIZE)AMD_ID_LV800T:
372                 info->flash_id += FLASH_AM800T;
373                 info->sector_count = 19;
374                 info->size = 0x00100000;
375                 break;                          /* => 1 MB              */
376
377         case (FLASH_WORD_SIZE)AMD_ID_LV800B:
378                 info->flash_id += FLASH_AM800B;
379                 info->sector_count = 19;
380                 info->size = 0x00100000;
381                 break;                          /* => 1 MB              */
382
383         case (FLASH_WORD_SIZE)AMD_ID_LV160T:
384                 info->flash_id += FLASH_AM160T;
385                 info->sector_count = 35;
386                 info->size = 0x00200000;
387                 break;                          /* => 2 MB              */
388
389         case (FLASH_WORD_SIZE)AMD_ID_LV160B:
390                 info->flash_id += FLASH_AM160B;
391                 info->sector_count = 35;
392                 info->size = 0x00200000;
393                 break;                          /* => 2 MB              */
394 #if 0   /* enable when device IDs are available */
395         case (FLASH_WORD_SIZE)AMD_ID_LV320T:
396                 info->flash_id += FLASH_AM320T;
397                 info->sector_count = 67;
398                 info->size = 0x00400000;
399                 break;                          /* => 4 MB              */
400
401         case (FLASH_WORD_SIZE)AMD_ID_LV320B:
402                 info->flash_id += FLASH_AM320B;
403                 info->sector_count = 67;
404                 info->size = 0x00400000;
405                 break;                          /* => 4 MB              */
406 #endif
407         case (FLASH_WORD_SIZE)SST_ID_xF800A:
408                 info->flash_id += FLASH_SST800A;
409                 info->sector_count = 16;
410                 info->size = 0x00100000;
411                 break;                          /* => 1 MB              */
412
413         case (FLASH_WORD_SIZE)SST_ID_xF160A:
414                 info->flash_id += FLASH_SST160A;
415                 info->sector_count = 32;
416                 info->size = 0x00200000;
417                 break;                          /* => 2 MB              */
418
419         default:
420                 info->flash_id = FLASH_UNKNOWN;
421                 return (0);                     /* => no or unknown flash */
422
423         }
424
425         /* set up sector start address table */
426         if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
427             (info->flash_id  == FLASH_AM040)){
428             for (i = 0; i < info->sector_count; i++)
429                 info->start[i] = base + (i * 0x00010000);
430         } else {
431             if (info->flash_id & FLASH_BTYPE) {
432                 /* set sector offsets for bottom boot block type        */
433                 info->start[0] = base + 0x00000000;
434                 info->start[1] = base + 0x00004000;
435                 info->start[2] = base + 0x00006000;
436                 info->start[3] = base + 0x00008000;
437                 for (i = 4; i < info->sector_count; i++) {
438                         info->start[i] = base + (i * 0x00010000) - 0x00030000;
439                 }
440             } else {
441                 /* set sector offsets for top boot block type           */
442                 i = info->sector_count - 1;
443                 info->start[i--] = base + info->size - 0x00004000;
444                 info->start[i--] = base + info->size - 0x00006000;
445                 info->start[i--] = base + info->size - 0x00008000;
446                 for (; i >= 0; i--) {
447                         info->start[i] = base + i * 0x00010000;
448                 }
449             }
450         }
451
452         /* check for protected sectors */
453         for (i = 0; i < info->sector_count; i++) {
454                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
455                 /* D0 = 1 if protected */
456 #ifdef CONFIG_ADCIOP
457                 addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
458                 info->protect[i] = addr2[4] & 1;
459 #else
460                 addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
461                 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
462                   info->protect[i] = 0;
463                 else
464                   info->protect[i] = addr2[2] & 1;
465 #endif
466         }
467
468         /*
469          * Prevent writes to uninitialized FLASH.
470          */
471         if (info->flash_id != FLASH_UNKNOWN) {
472 #if 0 /* test-only */
473 #ifdef CONFIG_ADCIOP
474                 addr2 = (volatile unsigned char *)info->start[0];
475                 addr2[ADDR0] = 0xAA;
476                 addr2[ADDR1] = 0x55;
477                 addr2[ADDR0] = 0xF0;  /* reset bank */
478 #else
479                 addr2 = (FLASH_WORD_SIZE *)info->start[0];
480                 *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
481 #endif
482 #else /* test-only */
483                 addr2 = (FLASH_WORD_SIZE *)info->start[0];
484                 *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
485 #endif /* test-only */
486         }
487
488         return (info->size);
489 }
490
491 int wait_for_DQ7(flash_info_t *info, int sect)
492 {
493         ulong start, now, last;
494         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
495
496         start = get_timer (0);
497     last  = start;
498     while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
499         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
500             printf ("Timeout\n");
501             return -1;
502         }
503         /* show that we're waiting */
504         if ((now - last) > 1000) {  /* every second */
505             putc ('.');
506             last = now;
507         }
508     }
509         return 0;
510 }
511
512 /*-----------------------------------------------------------------------
513  */
514
515 int     flash_erase (flash_info_t *info, int s_first, int s_last)
516 {
517         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
518         volatile FLASH_WORD_SIZE *addr2;
519         int flag, prot, sect, l_sect;
520         int i;
521
522         if ((s_first < 0) || (s_first > s_last)) {
523                 if (info->flash_id == FLASH_UNKNOWN) {
524                         printf ("- missing\n");
525                 } else {
526                         printf ("- no sectors to erase\n");
527                 }
528                 return 1;
529         }
530
531         if (info->flash_id == FLASH_UNKNOWN) {
532                 printf ("Can't erase unknown flash type - aborted\n");
533                 return 1;
534         }
535
536         prot = 0;
537         for (sect=s_first; sect<=s_last; ++sect) {
538                 if (info->protect[sect]) {
539                         prot++;
540                 }
541         }
542
543         if (prot) {
544                 printf ("- Warning: %d protected sectors will not be erased!\n",
545                         prot);
546         } else {
547                 printf ("\n");
548         }
549
550         l_sect = -1;
551
552         /* Disable interrupts which might cause a timeout here */
553         flag = disable_interrupts();
554
555         /* Start erase on unprotected sectors */
556         for (sect = s_first; sect<=s_last; sect++) {
557                 if (info->protect[sect] == 0) { /* not protected */
558                     addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
559                     printf("Erasing sector %p\n", addr2);       /* CLH */
560
561                     if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
562                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
563                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
564                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
565                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
566                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
567                         addr2[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
568                         for (i=0; i<50; i++)
569                                 udelay(1000);  /* wait 1 ms */
570                     } else {
571                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
572                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
573                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
574                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
575                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
576                         addr2[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
577                     }
578                     l_sect = sect;
579                     /*
580                      * Wait for each sector to complete, it's more
581                      * reliable.  According to AMD Spec, you must
582                      * issue all erase commands within a specified
583                      * timeout.  This has been seen to fail, especially
584                      * if printf()s are included (for debug)!!
585                      */
586                     wait_for_DQ7(info, sect);
587                 }
588         }
589
590         /* re-enable interrupts if necessary */
591         if (flag)
592                 enable_interrupts();
593
594         /* wait at least 80us - let's wait 1 ms */
595         udelay (1000);
596
597 #if 0
598         /*
599          * We wait for the last triggered sector
600          */
601         if (l_sect < 0)
602                 goto DONE;
603         wait_for_DQ7(info, l_sect);
604
605 DONE:
606 #endif
607         /* reset to read mode */
608         addr = (FLASH_WORD_SIZE *)info->start[0];
609         addr[0] = (FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */
610
611         printf (" done\n");
612         return 0;
613 }
614
615 /*-----------------------------------------------------------------------
616  * Copy memory to flash, returns:
617  * 0 - OK
618  * 1 - write timeout
619  * 2 - Flash not erased
620  */
621
622 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
623 {
624         ulong cp, wp, data;
625         int i, l, rc;
626
627         wp = (addr & ~3);       /* get lower word aligned address */
628
629         /*
630          * handle unaligned start bytes
631          */
632         if ((l = addr - wp) != 0) {
633                 data = 0;
634                 for (i=0, cp=wp; i<l; ++i, ++cp) {
635                         data = (data << 8) | (*(uchar *)cp);
636                 }
637                 for (; i<4 && cnt>0; ++i) {
638                         data = (data << 8) | *src++;
639                         --cnt;
640                         ++cp;
641                 }
642                 for (; cnt==0 && i<4; ++i, ++cp) {
643                         data = (data << 8) | (*(uchar *)cp);
644                 }
645
646                 if ((rc = write_word(info, wp, data)) != 0) {
647                         return (rc);
648                 }
649                 wp += 4;
650         }
651
652         /*
653          * handle word aligned part
654          */
655         while (cnt >= 4) {
656                 data = 0;
657                 for (i=0; i<4; ++i) {
658                         data = (data << 8) | *src++;
659                 }
660                 if ((rc = write_word(info, wp, data)) != 0) {
661                         return (rc);
662                 }
663                 wp  += 4;
664                 cnt -= 4;
665         }
666
667         if (cnt == 0) {
668                 return (0);
669         }
670
671         /*
672          * handle unaligned tail bytes
673          */
674         data = 0;
675         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
676                 data = (data << 8) | *src++;
677                 --cnt;
678         }
679         for (; i<4; ++i, ++cp) {
680                 data = (data << 8) | (*(uchar *)cp);
681         }
682
683         return (write_word(info, wp, data));
684 }
685
686 /*-----------------------------------------------------------------------
687  * Write a word to Flash, returns:
688  * 0 - OK
689  * 1 - write timeout
690  * 2 - Flash not erased
691  */
692 static int write_word (flash_info_t * info, ulong dest, ulong data)
693 {
694         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *) (info->start[0]);
695         volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *) dest;
696         volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *) & data;
697         ulong start;
698         int i;
699
700         /* Check if Flash is (sufficiently) erased */
701         if ((*((volatile FLASH_WORD_SIZE *) dest) &
702             (FLASH_WORD_SIZE) data) != (FLASH_WORD_SIZE) data) {
703                 return (2);
704         }
705
706         for (i = 0; i < 4 / sizeof (FLASH_WORD_SIZE); i++) {
707                 int flag;
708
709                 /* Disable interrupts which might cause a timeout here */
710                 flag = disable_interrupts ();
711
712                 addr2[ADDR0] = (FLASH_WORD_SIZE) 0x00AA00AA;
713                 addr2[ADDR1] = (FLASH_WORD_SIZE) 0x00550055;
714                 addr2[ADDR0] = (FLASH_WORD_SIZE) 0x00A000A0;
715
716                 dest2[i] = data2[i];
717
718                 /* re-enable interrupts if necessary */
719                 if (flag)
720                         enable_interrupts ();
721
722                 /* data polling for D7 */
723                 start = get_timer (0);
724                 while ((dest2[i] & (FLASH_WORD_SIZE) 0x00800080) !=
725                        (data2[i] & (FLASH_WORD_SIZE) 0x00800080)) {
726
727                         if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
728                                 return (1);
729                         }
730                 }
731         }
732
733         return (0);
734 }
735
736 /*-----------------------------------------------------------------------
737  */