* Code cleanup:
[platform/kernel/u-boot.git] / board / evb64260 / flash.c
1 /*
2  * (C) Copyright 2001
3  * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
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  * flash.c - flash support for the 512k, 8bit boot flash on the GEVB
26  *           most of this file was based on the existing U-Boot
27  *           flash drivers.
28  */
29
30 #include <common.h>
31 #include <mpc8xx.h>
32 #include <galileo/gt64260R.h>
33 #include <galileo/memory.h>
34 #include "intel_flash.h"
35
36 #define FLASH_ROM       0xFFFD       /* unknown flash type                   */
37 #define FLASH_RAM       0xFFFE       /* unknown flash type                   */
38 #define FLASH_MAN_UNKNOWN 0xFFFF0000
39
40 /* #define DEBUG */
41 /* #define FLASH_ID_OVERRIDE */ /* Hack to set type to 040B if ROM emulator is installed.
42                                  * Can be used to program a ROM in circuit if a programmer
43                                  * is not available by swapping the rom out. */
44
45 /* Intel flash commands */
46 int flash_erase_intel(flash_info_t *info, int s_first, int s_last);
47 int write_word_intel(bank_addr_t addr, bank_word_t value);
48
49 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
50
51 /*-----------------------------------------------------------------------
52  * Functions
53  */
54 static ulong flash_get_size (int portwidth, vu_long *addr, flash_info_t *info);
55 static int write_word (flash_info_t *info, ulong dest, ulong data);
56 static void flash_get_offsets (ulong base, flash_info_t *info);
57
58 /*-----------------------------------------------------------------------
59  */
60
61 unsigned long
62 flash_init (void)
63 {
64         unsigned int i;
65         unsigned long size_b0 = 0, size_b1 = 0;
66         unsigned long base, flash_size;
67
68         /* Init: no FLASHes known */
69         for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
70                 flash_info[i].flash_id = FLASH_UNKNOWN;
71         }
72
73         /* the boot flash */
74         base = CFG_FLASH_BASE;
75         size_b0 = flash_get_size(1, (vu_long *)base, &flash_info[0]);
76
77         printf("[%ldkB@%lx] ", size_b0/1024, base);
78
79         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
80                 printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n",
81                         base, size_b0, size_b0<<20);
82         }
83
84         base = memoryGetDeviceBaseAddress(CFG_EXTRA_FLASH_DEVICE);
85         for(i=1;i<CFG_MAX_FLASH_BANKS;i++) {
86             unsigned long size = flash_get_size(CFG_EXTRA_FLASH_WIDTH, (vu_long *)base, &flash_info[i]);
87
88             printf("[%ldMB@%lx] ", size>>20, base);
89
90             if (flash_info[i].flash_id == FLASH_UNKNOWN) {
91                 if(i==1) {
92                     printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n",
93                             base, size_b1, size_b1<<20);
94                 }
95                 break;
96             }
97             size_b1+=size;
98             base+=size;
99         }
100
101         flash_size = size_b0 + size_b1;
102         return flash_size;
103 }
104
105 /*-----------------------------------------------------------------------
106  */
107 static void
108 flash_get_offsets (ulong base, flash_info_t *info)
109 {
110         int i;
111         int sector_size;
112
113         if(!info->sector_count) return;
114
115         /* set up sector start address table */
116         switch(info->flash_id & FLASH_TYPEMASK) {
117             case FLASH_AM040:
118             case FLASH_28F128J3A:
119             case FLASH_28F640J3A:
120             case FLASH_RAM:
121                 /* this chip has uniformly spaced sectors */
122                 sector_size=info->size/info->sector_count;
123                 for (i = 0; i < info->sector_count; i++)
124                         info->start[i] = base + (i * sector_size);
125                 break;
126             default:
127                 if (info->flash_id & FLASH_BTYPE) {
128                     /* set sector offsets for bottom boot block type    */
129                     info->start[0] = base + 0x00000000;
130                     info->start[1] = base + 0x00008000;
131                     info->start[2] = base + 0x0000C000;
132                     info->start[3] = base + 0x00010000;
133                     for (i = 4; i < info->sector_count; i++) {
134                             info->start[i] = base + (i * 0x00020000) - 0x00060000;
135                     }
136                 } else {
137                     /* set sector offsets for top boot block type               */
138                     i = info->sector_count - 1;
139                     info->start[i--] = base + info->size - 0x00008000;
140                     info->start[i--] = base + info->size - 0x0000C000;
141                     info->start[i--] = base + info->size - 0x00010000;
142                     for (; i >= 0; i--) {
143                             info->start[i] = base + i * 0x00020000;
144                     }
145                 }
146         }
147 }
148
149 /*-----------------------------------------------------------------------
150  */
151 void
152 flash_print_info  (flash_info_t *info)
153 {
154         int i;
155
156         if (info->flash_id == FLASH_UNKNOWN) {
157                 printf ("missing or unknown FLASH type\n");
158                 return;
159         }
160
161         switch (info->flash_id & FLASH_VENDMASK) {
162         case FLASH_MAN_AMD:     printf ("AMD ");                break;
163         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
164         case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
165         default:                printf ("Unknown Vendor ");     break;
166         }
167
168         switch (info->flash_id & FLASH_TYPEMASK) {
169         case FLASH_AM040:
170                 printf ("AM29LV040B (4 Mbit, bottom boot sect)\n");
171                 break;
172         case FLASH_AM400B:
173                 printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
174                 break;
175         case FLASH_AM400T:
176                 printf ("AM29LV400T (4 Mbit, top boot sector)\n");
177                 break;
178         case FLASH_AM800B:
179                 printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
180                 break;
181         case FLASH_AM800T:
182                 printf ("AM29LV800T (8 Mbit, top boot sector)\n");
183                 break;
184         case FLASH_AM160B:
185                 printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
186                 break;
187         case FLASH_AM160T:
188                 printf ("AM29LV160T (16 Mbit, top boot sector)\n");
189                 break;
190         case FLASH_AM320B:
191                 printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
192                 break;
193         case FLASH_AM320T:
194                 printf ("AM29LV320T (32 Mbit, top boot sector)\n");
195                 break;
196         case FLASH_28F640J3A:
197                 printf ("28F640J3A (64 Mbit)\n");
198                 break;
199         case FLASH_28F128J3A:
200                 printf ("28F128J3A (128 Mbit)\n");
201                 break;
202         case FLASH_ROM:
203                 printf ("ROM\n");
204                 break;
205         case FLASH_RAM:
206                 printf ("RAM\n");
207                 break;
208         default:
209                 printf ("Unknown Chip Type\n");
210                 break;
211         }
212
213         puts ("  Size: ");
214         print_size (info->size, "");
215         printf (" in %d Sectors\n", info->sector_count);
216
217         printf ("  Sector Start Addresses:");
218         for (i=0; i<info->sector_count; ++i) {
219                 if ((i % 5) == 0)
220                         printf ("\n   ");
221                 printf (" %08lX%s",
222                         info->start[i],
223                         info->protect[i] ? " (RO)" : "     "
224                 );
225         }
226         printf ("\n");
227         return;
228 }
229
230 /*-----------------------------------------------------------------------
231  */
232
233
234 /*-----------------------------------------------------------------------
235  */
236
237 /*
238  * The following code cannot be run from FLASH!
239  */
240
241 static inline void flash_cmd(int width, volatile unsigned char *addr, int offset, unsigned char cmd)
242 {
243         /* supports 1x8, 1x16, and 2x16 */
244         /* 2x8 and 4x8 are not supported */
245         if(width==4) {
246             /* assuming chips are in 16 bit mode */
247             /* 2x16 */
248             unsigned long cmd32=(cmd<<16)|cmd;
249             *(volatile unsigned long *)(addr+offset*2)=cmd32;
250         } else {
251             /* 1x16 or 1x8 */
252             *(volatile unsigned char *)(addr+offset)=cmd;
253         }
254 }
255
256 static ulong
257 flash_get_size (int portwidth, vu_long *addr, flash_info_t *info)
258 {
259         short i;
260         volatile unsigned char *caddr = (unsigned char *)addr;
261         volatile unsigned short *saddr = (unsigned short *)addr;
262         volatile unsigned long *laddr = (unsigned long *)addr;
263         char old[2], save;
264         ulong id, manu, base = (ulong)addr;
265
266         info->portwidth=portwidth;
267
268         save = *caddr;
269
270         flash_cmd(portwidth,caddr,0,0xf0);
271         flash_cmd(portwidth,caddr,0,0xf0);
272
273         udelay(10);
274
275         old[0] = caddr[0];
276         old[1] = caddr[1];
277
278
279         if(old[0]!=0xf0) {
280             flash_cmd(portwidth,caddr,0,0xf0);
281             flash_cmd(portwidth,caddr,0,0xf0);
282
283             udelay(10);
284
285             if(*caddr==0xf0) {
286                 /* this area is ROM */
287                 *caddr=save;
288 #ifndef FLASH_ID_OVERRIDE
289                 info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN;
290                 info->sector_count = 8;
291                 info->size = 0x80000;
292 #else
293                 info->flash_id = FLASH_MAN_AMD + FLASH_AM040;
294                 info->sector_count = 8;
295                 info->size = 0x80000;
296                 info->chipwidth=1;
297 #endif
298                 flash_get_offsets(base, info);
299                 return info->size;
300             }
301         } else {
302             *caddr=0;
303
304             udelay(10);
305
306             if(*caddr==0) {
307                 /* this area is RAM */
308                 *caddr=save;
309                 info->flash_id = FLASH_RAM + FLASH_MAN_UNKNOWN;
310                 info->sector_count = 8;
311                 info->size = 0x80000;
312                 flash_get_offsets(base, info);
313                 return info->size;
314             }
315             flash_cmd(portwidth,caddr,0,0xf0);
316
317             udelay(10);
318         }
319
320         /* Write auto select command: read Manufacturer ID */
321         flash_cmd(portwidth,caddr,0x555,0xAA);
322         flash_cmd(portwidth,caddr,0x2AA,0x55);
323         flash_cmd(portwidth,caddr,0x555,0x90);
324
325         udelay(10);
326
327         if ((caddr[0] == old[0]) &&
328             (caddr[1] == old[1])) {
329
330             /* this area is ROM */
331 #ifndef FLASH_ID_OVERRIDE
332             info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN;
333             info->sector_count = 8;
334             info->size = 0x80000;
335 #else
336                 info->flash_id = FLASH_MAN_AMD + FLASH_AM040;
337                 info->sector_count = 8;
338                 info->size = 0x80000;
339                 info->chipwidth=1;
340 #endif
341             flash_get_offsets(base, info);
342             return info->size;
343 #ifdef DEBUG
344         } else {
345             printf("%px%d: %02x:%02x -> %02x:%02x\n",
346                     caddr, portwidth, old[0], old[1],
347                     caddr[0], caddr[1]);
348 #endif
349         }
350
351         switch(portwidth) {
352             case 1:
353                 manu = caddr[0];
354                 manu |= manu<<16;
355                 id = caddr[1];
356                 break;
357             case 2:
358                 manu = saddr[0];
359                 manu |= manu<<16;
360                 id = saddr[1];
361                 id |= id<<16;
362                 break;
363             case 4:
364                 manu = laddr[0];
365                 id = laddr[1];
366                 break;
367         default:
368                 id = manu = -1;
369                 break;
370         }
371
372 #ifdef DEBUG
373         printf("\n%08lx:%08lx:%08lx\n", base, manu, id);
374         printf("%08lx %08lx %08lx %08lx\n",
375                 laddr[0],laddr[1],laddr[2],laddr[3]);
376 #endif
377
378         switch (manu) {
379             case AMD_MANUFACT:
380                     info->flash_id = FLASH_MAN_AMD;
381                     break;
382             case FUJ_MANUFACT:
383                     info->flash_id = FLASH_MAN_FUJ;
384                     break;
385             case INTEL_MANUFACT:
386                     info->flash_id = FLASH_MAN_INTEL;
387                     break;
388             default:
389                     printf("Unknown Mfr [%08lx]:%08lx\n", manu, id);
390                     info->flash_id = FLASH_UNKNOWN;
391                     info->sector_count = 0;
392                     info->size = 0;
393                     return (0);                 /* no or unknown flash  */
394         }
395
396         switch (id) {
397             case AMD_ID_LV400T:
398                     info->flash_id += FLASH_AM400T;
399                     info->sector_count = 11;
400                     info->size = 0x00100000;
401                     info->chipwidth=1;
402                     break;                              /* => 1 MB      */
403
404             case AMD_ID_LV400B:
405                     info->flash_id += FLASH_AM400B;
406                     info->sector_count = 11;
407                     info->size = 0x00100000;
408                     info->chipwidth=1;
409                     break;                              /* => 1 MB      */
410
411             case AMD_ID_LV800T:
412                     info->flash_id += FLASH_AM800T;
413                     info->sector_count = 19;
414                     info->size = 0x00200000;
415                     info->chipwidth=1;
416                     break;                              /* => 2 MB      */
417
418             case AMD_ID_LV800B:
419                     info->flash_id += FLASH_AM800B;
420                     info->sector_count = 19;
421                     info->size = 0x00200000;
422                     info->chipwidth=1;
423                     break;                              /* => 2 MB      */
424
425             case AMD_ID_LV160T:
426                     info->flash_id += FLASH_AM160T;
427                     info->sector_count = 35;
428                     info->size = 0x00400000;
429                     info->chipwidth=1;
430                     break;                              /* => 4 MB      */
431
432             case AMD_ID_LV160B:
433                     info->flash_id += FLASH_AM160B;
434                     info->sector_count = 35;
435                     info->size = 0x00400000;
436                     info->chipwidth=1;
437                     break;                              /* => 4 MB      */
438 #if 0   /* enable when device IDs are available */
439             case AMD_ID_LV320T:
440                     info->flash_id += FLASH_AM320T;
441                     info->sector_count = 67;
442                     info->size = 0x00800000;
443                     break;                              /* => 8 MB      */
444
445             case AMD_ID_LV320B:
446                     info->flash_id += FLASH_AM320B;
447                     info->sector_count = 67;
448                     info->size = 0x00800000;
449                     break;                              /* => 8 MB      */
450 #endif
451             case AMD_ID_LV040B:
452                     info->flash_id += FLASH_AM040;
453                     info->sector_count = 8;
454                     info->size = 0x80000;
455                     info->chipwidth=1;
456                     break;
457
458             case INTEL_ID_28F640J3A:
459                     info->flash_id += FLASH_28F640J3A;
460                     info->sector_count = 64;
461                     info->size = 128*1024 * 64; /* 128kbytes x 64 blocks */
462                     info->chipwidth=2;
463                     if(portwidth==4) info->size*=2;     /* 2x16 */
464                     break;
465
466             case INTEL_ID_28F128J3A:
467                     info->flash_id += FLASH_28F128J3A;
468                     info->sector_count = 128;
469                     info->size = 128*1024 * 128; /* 128kbytes x 128 blocks */
470                     info->chipwidth=2;
471                     if(portwidth==4) info->size*=2;     /* 2x16 */
472                     break;
473
474             default:
475                     printf("Unknown id %lx:[%lx]\n", manu, id);
476                     info->flash_id = FLASH_UNKNOWN;
477                     info->chipwidth=1;
478                     return (0);                 /* => no or unknown flash */
479
480         }
481
482         flash_get_offsets(base, info);
483
484 #if 0
485         /* set up sector start address table */
486         if (info->flash_id & FLASH_AM040) {
487                 /* this chip has uniformly spaced sectors */
488                 for (i = 0; i < info->sector_count; i++)
489                         info->start[i] = base + (i * 0x00010000);
490
491         } else if (info->flash_id & FLASH_BTYPE) {
492                 /* set sector offsets for bottom boot block type        */
493                 info->start[0] = base + 0x00000000;
494                 info->start[1] = base + 0x00008000;
495                 info->start[2] = base + 0x0000C000;
496                 info->start[3] = base + 0x00010000;
497                 for (i = 4; i < info->sector_count; i++) {
498                         info->start[i] = base + (i * 0x00020000) - 0x00060000;
499                 }
500         } else {
501                 /* set sector offsets for top boot block type           */
502                 i = info->sector_count - 1;
503                 info->start[i--] = base + info->size - 0x00008000;
504                 info->start[i--] = base + info->size - 0x0000C000;
505                 info->start[i--] = base + info->size - 0x00010000;
506                 for (; i >= 0; i--) {
507                         info->start[i] = base + i * 0x00020000;
508                 }
509         }
510 #endif
511
512         /* check for protected sectors */
513         for (i = 0; i < info->sector_count; i++) {
514                 /* read sector protection at sector address, (A7 .. A0)=0x02 */
515                 /* D0 = 1 if protected */
516                 caddr = (volatile unsigned char *)(info->start[i]);
517                 saddr = (volatile unsigned short *)(info->start[i]);
518                 laddr = (volatile unsigned long *)(info->start[i]);
519                 if(portwidth==1)
520                     info->protect[i] = caddr[2] & 1;
521                 else if(portwidth==2)
522                     info->protect[i] = saddr[2] & 1;
523                 else
524                     info->protect[i] = laddr[2] & 1;
525         }
526
527         /*
528          * Prevent writes to uninitialized FLASH.
529          */
530         if (info->flash_id != FLASH_UNKNOWN) {
531                 caddr = (volatile unsigned char *)info->start[0];
532
533                 flash_cmd(portwidth,caddr,0,0xF0);      /* reset bank */
534         }
535
536         return (info->size);
537 }
538
539 /* TODO: 2x16 unsupported */
540 int
541 flash_erase (flash_info_t *info, int s_first, int s_last)
542 {
543         volatile unsigned char *addr = (char *)(info->start[0]);
544         int flag, prot, sect, l_sect;
545         ulong start, now, last;
546
547         /* TODO: 2x16 unsupported */
548         if(info->portwidth==4) return 1;
549
550         if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 1;
551         if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) {
552             for (sect = s_first; sect<=s_last; sect++) {
553                 int sector_size=info->size/info->sector_count;
554                 addr = (char *)(info->start[sect]);
555                 memset((void *)addr, 0, sector_size);
556             }
557             return 0;
558         }
559
560         if ((s_first < 0) || (s_first > s_last)) {
561                 if (info->flash_id == FLASH_UNKNOWN) {
562                         printf ("- missing\n");
563                 } else {
564                         printf ("- no sectors to erase\n");
565                 }
566                 return 1;
567         }
568
569         if ((info->flash_id&FLASH_VENDMASK) == FLASH_MAN_INTEL)  {
570                 return flash_erase_intel(info,
571                                 (unsigned short)s_first,
572                                 (unsigned short)s_last);
573         }
574
575 #if 0
576         if ((info->flash_id == FLASH_UNKNOWN) ||
577             (info->flash_id > FLASH_AMD_COMP)) {
578                 printf ("Can't erase unknown flash type %08lx - aborted\n",
579                         info->flash_id);
580                 return 1;
581         }
582 #endif
583
584         prot = 0;
585         for (sect=s_first; sect<=s_last; ++sect) {
586                 if (info->protect[sect]) {
587                         prot++;
588                 }
589         }
590
591         if (prot) {
592                 printf ("- Warning: %d protected sectors will not be erased!\n",
593                         prot);
594         } else {
595                 printf ("\n");
596         }
597
598         l_sect = -1;
599
600         /* Disable interrupts which might cause a timeout here */
601         flag = disable_interrupts();
602
603         flash_cmd(info->portwidth,addr,0x555,0xAA);
604         flash_cmd(info->portwidth,addr,0x2AA,0x55);
605         flash_cmd(info->portwidth,addr,0x555,0x80);
606         flash_cmd(info->portwidth,addr,0x555,0xAA);
607         flash_cmd(info->portwidth,addr,0x2AA,0x55);
608
609         /* Start erase on unprotected sectors */
610         for (sect = s_first; sect<=s_last; sect++) {
611                 if (info->protect[sect] == 0) { /* not protected */
612                         addr = (char *)(info->start[sect]);
613                         flash_cmd(info->portwidth,addr,0,0x30);
614                         l_sect = sect;
615                 }
616         }
617
618         /* re-enable interrupts if necessary */
619         if (flag)
620                 enable_interrupts();
621
622         /* wait at least 80us - let's wait 1 ms */
623         udelay (1000);
624
625         /*
626          * We wait for the last triggered sector
627          */
628         if (l_sect < 0)
629                 goto DONE;
630
631         start = get_timer (0);
632         last  = start;
633         addr = (volatile unsigned char *)(info->start[l_sect]);
634         /* broken for 2x16: TODO */
635         while ((addr[0] & 0x80) != 0x80) {
636                 if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
637                         printf ("Timeout\n");
638                         return 1;
639                 }
640                 /* show that we're waiting */
641                 if ((now - last) > 1000) {      /* every second */
642                         putc ('.');
643                         last = now;
644                 }
645         }
646
647 DONE:
648         /* reset to read mode */
649         addr = (volatile unsigned char *)info->start[0];
650         flash_cmd(info->portwidth,addr,0,0xf0);
651         flash_cmd(info->portwidth,addr,0,0xf0);
652
653         printf (" done\n");
654         return 0;
655 }
656
657 /*-----------------------------------------------------------------------
658  * Copy memory to flash, returns:
659  * 0 - OK
660  * 1 - write timeout
661  * 2 - Flash not erased
662  */
663
664 /* broken for 2x16: TODO */
665 int
666 write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
667 {
668         ulong cp, wp, data;
669         int i, l, rc;
670
671         if(info->portwidth==4) return 1;
672
673         if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 0;
674         if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) {
675             memcpy((void *)addr, src, cnt);
676             return 0;
677         }
678
679         wp = (addr & ~3);       /* get lower word aligned address */
680
681         /*
682          * handle unaligned start bytes
683          */
684         if ((l = addr - wp) != 0) {
685                 data = 0;
686                 for (i=0, cp=wp; i<l; ++i, ++cp) {
687                         data = (data << 8) | (*(uchar *)cp);
688                 }
689                 for (; i<4 && cnt>0; ++i) {
690                         data = (data << 8) | *src++;
691                         --cnt;
692                         ++cp;
693                 }
694                 for (; cnt==0 && i<4; ++i, ++cp) {
695                         data = (data << 8) | (*(uchar *)cp);
696                 }
697
698                 if ((rc = write_word(info, wp, data)) != 0) {
699                         return (rc);
700                 }
701                 wp += 4;
702         }
703
704         /*
705          * handle word aligned part
706          */
707         while (cnt >= 4) {
708                 data = 0;
709                 for (i=0; i<4; ++i) {
710                         data = (data << 8) | *src++;
711                 }
712                 if ((rc = write_word(info, wp, data)) != 0) {
713                         return (rc);
714                 }
715                 wp  += 4;
716                 cnt -= 4;
717         }
718
719         if (cnt == 0) {
720                 return (0);
721         }
722
723         /*
724          * handle unaligned tail bytes
725          */
726         data = 0;
727         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
728                 data = (data << 8) | *src++;
729                 --cnt;
730         }
731         for (; i<4; ++i, ++cp) {
732                 data = (data << 8) | (*(uchar *)cp);
733         }
734
735         return (write_word(info, wp, data));
736 }
737
738 /*-----------------------------------------------------------------------
739  * Write a word to Flash, returns:
740  * 0 - OK
741  * 1 - write timeout
742  * 2 - Flash not erased
743  */
744 /* broken for 2x16: TODO */
745 static int
746 write_word (flash_info_t *info, ulong dest, ulong data)
747 {
748         volatile unsigned char *addr = (char *)(info->start[0]);
749         ulong start;
750         int flag, i;
751
752         if(info->portwidth==4) return 1;
753
754         if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 1;
755         if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) {
756             *(unsigned long *)dest=data;
757             return 0;
758         }
759         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)  {
760                 unsigned short low = data & 0xffff;
761                 unsigned short hi  = (data >> 16) & 0xffff;
762                 int ret = write_word_intel((bank_addr_t)dest, hi);
763
764                 if (!ret) ret = write_word_intel((bank_addr_t)(dest+2), low);
765
766                 return ret;
767         }
768
769         /* Check if Flash is (sufficiently) erased */
770         if ((*((vu_long *)dest) & data) != data) {
771                 return (2);
772         }
773         /* Disable interrupts which might cause a timeout here */
774         flag = disable_interrupts();
775
776         /* first, perform an unlock bypass command to speed up flash writes */
777         addr[0x555] = 0xAA;
778         addr[0x2AA] = 0x55;
779         addr[0x555] = 0x20;
780
781         /* write each byte out */
782         for (i = 0; i < 4; i++) {
783                 char *data_ch = (char *)&data;
784                 addr[0] = 0xA0;
785                 *(((char *)dest)+i) = data_ch[i];
786                 udelay(10); /* XXX */
787         }
788
789         /* we're done, now do an unlock bypass reset */
790         addr[0] = 0x90;
791         addr[0] = 0x00;
792
793         /* re-enable interrupts if necessary */
794         if (flag)
795                 enable_interrupts();
796
797         /* data polling for D7 */
798         start = get_timer (0);
799         while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
800                 if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
801                         return (1);
802                 }
803         }
804         return (0);
805 }