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