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