]> git.sur5r.net Git - u-boot/blob - board/bubinga405ep/flash.c
* Code cleanup:
[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 static void flash_get_offsets (ulong base, flash_info_t *info)
178 {
179         int i;
180
181         /* set up sector start address table */
182         if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
183             (info->flash_id  == FLASH_AM040)){
184             for (i = 0; i < info->sector_count; i++)
185                 info->start[i] = base + (i * 0x00010000);
186         } else {
187             if (info->flash_id & FLASH_BTYPE) {
188                 /* set sector offsets for bottom boot block type        */
189                 info->start[0] = base + 0x00000000;
190                 info->start[1] = base + 0x00004000;
191                 info->start[2] = base + 0x00006000;
192                 info->start[3] = base + 0x00008000;
193                 for (i = 4; i < info->sector_count; i++) {
194                         info->start[i] = base + (i * 0x00010000) - 0x00030000;
195                 }
196             } else {
197                 /* set sector offsets for top boot block type           */
198                 i = info->sector_count - 1;
199                 info->start[i--] = base + info->size - 0x00004000;
200                 info->start[i--] = base + info->size - 0x00006000;
201                 info->start[i--] = base + info->size - 0x00008000;
202                 for (; i >= 0; i--) {
203                         info->start[i] = base + i * 0x00010000;
204                 }
205             }
206         }
207 }
208
209 /*-----------------------------------------------------------------------
210  */
211 void flash_print_info  (flash_info_t *info)
212 {
213         int i;
214         int k;
215         int size;
216         int erased;
217         volatile unsigned long *flash;
218
219         if (info->flash_id == FLASH_UNKNOWN) {
220                 printf ("missing or unknown FLASH type\n");
221                 return;
222         }
223
224         switch (info->flash_id & FLASH_VENDMASK) {
225         case FLASH_MAN_AMD:     printf ("AMD ");                break;
226         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
227         case FLASH_MAN_SST:     printf ("SST ");                break;
228         default:                printf ("Unknown Vendor ");     break;
229         }
230
231         switch (info->flash_id & FLASH_TYPEMASK) {
232         case FLASH_AM040:       printf ("AM29F040 (512 Kbit, uniform sector size)\n");
233                                 break;
234         case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
235                                 break;
236         case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
237                                 break;
238         case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
239                                 break;
240         case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
241                                 break;
242         case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
243                                 break;
244         case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
245                                 break;
246         case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
247                                 break;
248         case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
249                                 break;
250         case FLASH_SST800A:     printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
251                                 break;
252         case FLASH_SST160A:     printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
253                                 break;
254         default:                printf ("Unknown Chip Type\n");
255                                 break;
256         }
257
258         printf ("  Size: %ld KB in %d Sectors\n",
259                 info->size >> 10, info->sector_count);
260
261         printf ("  Sector Start Addresses:");
262         for (i=0; i<info->sector_count; ++i) {
263                 /*
264                  * Check if whole sector is erased
265                  */
266                 if (i != (info->sector_count-1))
267                   size = info->start[i+1] - info->start[i];
268                 else
269                   size = info->start[0] + info->size - info->start[i];
270                 erased = 1;
271                 flash = (volatile unsigned long *)info->start[i];
272                 size = size >> 2;        /* divide by 4 for longword access */
273                 for (k=0; k<size; k++)
274                   {
275                     if (*flash++ != 0xffffffff)
276                       {
277                         erased = 0;
278                         break;
279                       }
280                   }
281
282                 if ((i % 5) == 0)
283                         printf ("\n   ");
284 #if 0 /* test-only */
285                 printf (" %08lX%s",
286                         info->start[i],
287                         info->protect[i] ? " (RO)" : "     "
288 #else
289                 printf (" %08lX%s%s",
290                         info->start[i],
291                         erased ? " E" : "  ",
292                         info->protect[i] ? "RO " : "   "
293 #endif
294                 );
295         }
296         printf ("\n");
297         return;
298 }
299
300 /*-----------------------------------------------------------------------
301  */
302
303
304 /*-----------------------------------------------------------------------
305  */
306
307 /*
308  * The following code cannot be run from FLASH!
309  */
310 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
311 {
312         short i;
313         FLASH_WORD_SIZE value;
314         ulong base = (ulong)addr;
315         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
316
317         /* Write auto select command: read Manufacturer ID */
318         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
319         addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
320         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
321
322 #ifdef CONFIG_ADCIOP
323         value = addr2[2];
324 #else
325         value = addr2[0];
326 #endif
327
328         switch (value) {
329         case (FLASH_WORD_SIZE)AMD_MANUFACT:
330                 info->flash_id = FLASH_MAN_AMD;
331                 break;
332         case (FLASH_WORD_SIZE)FUJ_MANUFACT:
333                 info->flash_id = FLASH_MAN_FUJ;
334                 break;
335         case (FLASH_WORD_SIZE)SST_MANUFACT:
336                 info->flash_id = FLASH_MAN_SST;
337                 break;
338         default:
339                 info->flash_id = FLASH_UNKNOWN;
340                 info->sector_count = 0;
341                 info->size = 0;
342                 return (0);                     /* no or unknown flash  */
343         }
344
345 #ifdef CONFIG_ADCIOP
346         value = addr2[0];                       /* device ID            */
347         /*        printf("\ndev_code=%x\n", value); */
348 #else
349         value = addr2[1];                       /* device ID            */
350 #endif
351
352         switch (value) {
353         case (FLASH_WORD_SIZE)AMD_ID_F040B:
354                 info->flash_id += FLASH_AM040;
355                 info->sector_count = 8;
356                 info->size = 0x0080000; /* => 512 ko */
357                 break;
358         case (FLASH_WORD_SIZE)AMD_ID_LV400T:
359                 info->flash_id += FLASH_AM400T;
360                 info->sector_count = 11;
361                 info->size = 0x00080000;
362                 break;                          /* => 0.5 MB            */
363
364         case (FLASH_WORD_SIZE)AMD_ID_LV400B:
365                 info->flash_id += FLASH_AM400B;
366                 info->sector_count = 11;
367                 info->size = 0x00080000;
368                 break;                          /* => 0.5 MB            */
369
370         case (FLASH_WORD_SIZE)AMD_ID_LV800T:
371                 info->flash_id += FLASH_AM800T;
372                 info->sector_count = 19;
373                 info->size = 0x00100000;
374                 break;                          /* => 1 MB              */
375
376         case (FLASH_WORD_SIZE)AMD_ID_LV800B:
377                 info->flash_id += FLASH_AM800B;
378                 info->sector_count = 19;
379                 info->size = 0x00100000;
380                 break;                          /* => 1 MB              */
381
382         case (FLASH_WORD_SIZE)AMD_ID_LV160T:
383                 info->flash_id += FLASH_AM160T;
384                 info->sector_count = 35;
385                 info->size = 0x00200000;
386                 break;                          /* => 2 MB              */
387
388         case (FLASH_WORD_SIZE)AMD_ID_LV160B:
389                 info->flash_id += FLASH_AM160B;
390                 info->sector_count = 35;
391                 info->size = 0x00200000;
392                 break;                          /* => 2 MB              */
393 #if 0   /* enable when device IDs are available */
394         case (FLASH_WORD_SIZE)AMD_ID_LV320T:
395                 info->flash_id += FLASH_AM320T;
396                 info->sector_count = 67;
397                 info->size = 0x00400000;
398                 break;                          /* => 4 MB              */
399
400         case (FLASH_WORD_SIZE)AMD_ID_LV320B:
401                 info->flash_id += FLASH_AM320B;
402                 info->sector_count = 67;
403                 info->size = 0x00400000;
404                 break;                          /* => 4 MB              */
405 #endif
406         case (FLASH_WORD_SIZE)SST_ID_xF800A:
407                 info->flash_id += FLASH_SST800A;
408                 info->sector_count = 16;
409                 info->size = 0x00100000;
410                 break;                          /* => 1 MB              */
411
412         case (FLASH_WORD_SIZE)SST_ID_xF160A:
413                 info->flash_id += FLASH_SST160A;
414                 info->sector_count = 32;
415                 info->size = 0x00200000;
416                 break;                          /* => 2 MB              */
417
418         default:
419                 info->flash_id = FLASH_UNKNOWN;
420                 return (0);                     /* => no or unknown flash */
421
422         }
423
424         /* set up sector start address table */
425         if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
426             (info->flash_id  == FLASH_AM040)){
427             for (i = 0; i < info->sector_count; i++)
428                 info->start[i] = base + (i * 0x00010000);
429         } else {
430             if (info->flash_id & FLASH_BTYPE) {
431                 /* set sector offsets for bottom boot block type        */
432                 info->start[0] = base + 0x00000000;
433                 info->start[1] = base + 0x00004000;
434                 info->start[2] = base + 0x00006000;
435                 info->start[3] = base + 0x00008000;
436                 for (i = 4; i < info->sector_count; i++) {
437                         info->start[i] = base + (i * 0x00010000) - 0x00030000;
438                 }
439             } else {
440                 /* set sector offsets for top boot block type           */
441                 i = info->sector_count - 1;
442                 info->start[i--] = base + info->size - 0x00004000;
443                 info->start[i--] = base + info->size - 0x00006000;
444                 info->start[i--] = base + info->size - 0x00008000;
445                 for (; i >= 0; i--) {
446                         info->start[i] = base + i * 0x00010000;
447                 }
448             }
449         }
450
451         /* check for protected sectors */
452         for (i = 0; i < info->sector_count; i++) {
453                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
454                 /* D0 = 1 if protected */
455 #ifdef CONFIG_ADCIOP
456                 addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
457                 info->protect[i] = addr2[4] & 1;
458 #else
459                 addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
460                 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
461                   info->protect[i] = 0;
462                 else
463                   info->protect[i] = addr2[2] & 1;
464 #endif
465         }
466
467         /*
468          * Prevent writes to uninitialized FLASH.
469          */
470         if (info->flash_id != FLASH_UNKNOWN) {
471 #if 0 /* test-only */
472 #ifdef CONFIG_ADCIOP
473                 addr2 = (volatile unsigned char *)info->start[0];
474                 addr2[ADDR0] = 0xAA;
475                 addr2[ADDR1] = 0x55;
476                 addr2[ADDR0] = 0xF0;  /* reset bank */
477 #else
478                 addr2 = (FLASH_WORD_SIZE *)info->start[0];
479                 *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
480 #endif
481 #else /* test-only */
482                 addr2 = (FLASH_WORD_SIZE *)info->start[0];
483                 *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
484 #endif /* test-only */
485         }
486
487         return (info->size);
488 }
489
490 int wait_for_DQ7(flash_info_t *info, int sect)
491 {
492         ulong start, now, last;
493         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
494
495         start = get_timer (0);
496     last  = start;
497     while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
498         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
499             printf ("Timeout\n");
500             return -1;
501         }
502         /* show that we're waiting */
503         if ((now - last) > 1000) {  /* every second */
504             putc ('.');
505             last = now;
506         }
507     }
508         return 0;
509 }
510
511 /*-----------------------------------------------------------------------
512  */
513
514 int     flash_erase (flash_info_t *info, int s_first, int s_last)
515 {
516         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
517         volatile FLASH_WORD_SIZE *addr2;
518         int flag, prot, sect, l_sect;
519         int i;
520
521         if ((s_first < 0) || (s_first > s_last)) {
522                 if (info->flash_id == FLASH_UNKNOWN) {
523                         printf ("- missing\n");
524                 } else {
525                         printf ("- no sectors to erase\n");
526                 }
527                 return 1;
528         }
529
530         if (info->flash_id == FLASH_UNKNOWN) {
531                 printf ("Can't erase unknown flash type - aborted\n");
532                 return 1;
533         }
534
535         prot = 0;
536         for (sect=s_first; sect<=s_last; ++sect) {
537                 if (info->protect[sect]) {
538                         prot++;
539                 }
540         }
541
542         if (prot) {
543                 printf ("- Warning: %d protected sectors will not be erased!\n",
544                         prot);
545         } else {
546                 printf ("\n");
547         }
548
549         l_sect = -1;
550
551         /* Disable interrupts which might cause a timeout here */
552         flag = disable_interrupts();
553
554         /* Start erase on unprotected sectors */
555         for (sect = s_first; sect<=s_last; sect++) {
556                 if (info->protect[sect] == 0) { /* not protected */
557                     addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
558                     printf("Erasing sector %p\n", addr2);       /* CLH */
559
560                     if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
561                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
562                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
563                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
564                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
565                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
566                         addr2[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
567                         for (i=0; i<50; i++)
568                                 udelay(1000);  /* wait 1 ms */
569                     } else {
570                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
571                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
572                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
573                         addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
574                         addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
575                         addr2[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
576                     }
577                     l_sect = sect;
578                     /*
579                      * Wait for each sector to complete, it's more
580                      * reliable.  According to AMD Spec, you must
581                      * issue all erase commands within a specified
582                      * timeout.  This has been seen to fail, especially
583                      * if printf()s are included (for debug)!!
584                      */
585                     wait_for_DQ7(info, sect);
586                 }
587         }
588
589         /* re-enable interrupts if necessary */
590         if (flag)
591                 enable_interrupts();
592
593         /* wait at least 80us - let's wait 1 ms */
594         udelay (1000);
595
596 #if 0
597         /*
598          * We wait for the last triggered sector
599          */
600         if (l_sect < 0)
601                 goto DONE;
602         wait_for_DQ7(info, l_sect);
603
604 DONE:
605 #endif
606         /* reset to read mode */
607         addr = (FLASH_WORD_SIZE *)info->start[0];
608         addr[0] = (FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */
609
610         printf (" done\n");
611         return 0;
612 }
613
614 /*-----------------------------------------------------------------------
615  * Copy memory to flash, returns:
616  * 0 - OK
617  * 1 - write timeout
618  * 2 - Flash not erased
619  */
620
621 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
622 {
623         ulong cp, wp, data;
624         int i, l, rc;
625
626         wp = (addr & ~3);       /* get lower word aligned address */
627
628         /*
629          * handle unaligned start bytes
630          */
631         if ((l = addr - wp) != 0) {
632                 data = 0;
633                 for (i=0, cp=wp; i<l; ++i, ++cp) {
634                         data = (data << 8) | (*(uchar *)cp);
635                 }
636                 for (; i<4 && cnt>0; ++i) {
637                         data = (data << 8) | *src++;
638                         --cnt;
639                         ++cp;
640                 }
641                 for (; cnt==0 && i<4; ++i, ++cp) {
642                         data = (data << 8) | (*(uchar *)cp);
643                 }
644
645                 if ((rc = write_word(info, wp, data)) != 0) {
646                         return (rc);
647                 }
648                 wp += 4;
649         }
650
651         /*
652          * handle word aligned part
653          */
654         while (cnt >= 4) {
655                 data = 0;
656                 for (i=0; i<4; ++i) {
657                         data = (data << 8) | *src++;
658                 }
659                 if ((rc = write_word(info, wp, data)) != 0) {
660                         return (rc);
661                 }
662                 wp  += 4;
663                 cnt -= 4;
664         }
665
666         if (cnt == 0) {
667                 return (0);
668         }
669
670         /*
671          * handle unaligned tail bytes
672          */
673         data = 0;
674         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
675                 data = (data << 8) | *src++;
676                 --cnt;
677         }
678         for (; i<4; ++i, ++cp) {
679                 data = (data << 8) | (*(uchar *)cp);
680         }
681
682         return (write_word(info, wp, data));
683 }
684
685 /*-----------------------------------------------------------------------
686  * Write a word to Flash, returns:
687  * 0 - OK
688  * 1 - write timeout
689  * 2 - Flash not erased
690  */
691 static int write_word (flash_info_t * info, ulong dest, ulong data)
692 {
693         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *) (info->start[0]);
694         volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *) dest;
695         volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *) & data;
696         ulong start;
697         int i;
698
699         /* Check if Flash is (sufficiently) erased */
700         if ((*((volatile FLASH_WORD_SIZE *) dest) &
701             (FLASH_WORD_SIZE) data) != (FLASH_WORD_SIZE) data) {
702                 return (2);
703         }
704
705         for (i = 0; i < 4 / sizeof (FLASH_WORD_SIZE); i++) {
706                 int flag;
707
708                 /* Disable interrupts which might cause a timeout here */
709                 flag = disable_interrupts ();
710
711                 addr2[ADDR0] = (FLASH_WORD_SIZE) 0x00AA00AA;
712                 addr2[ADDR1] = (FLASH_WORD_SIZE) 0x00550055;
713                 addr2[ADDR0] = (FLASH_WORD_SIZE) 0x00A000A0;
714
715                 dest2[i] = data2[i];
716
717                 /* re-enable interrupts if necessary */
718                 if (flag)
719                         enable_interrupts ();
720
721                 /* data polling for D7 */
722                 start = get_timer (0);
723                 while ((dest2[i] & (FLASH_WORD_SIZE) 0x00800080) !=
724                        (data2[i] & (FLASH_WORD_SIZE) 0x00800080)) {
725
726                         if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
727                                 return (1);
728                         }
729                 }
730         }
731
732         return (0);
733 }
734
735 /*-----------------------------------------------------------------------
736  */