* Patch by Marc Singer, 29 May 2003:
[oweals/u-boot.git] / board / sc520_spunk / flash.c
1 /*
2  * (C) Copyright 2002, 2003
3  * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
4  * 
5  * (C) Copyright 2002
6  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7  * Alex Zuepke <azu@sysgo.de>
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27
28 #include <common.h>
29 #include <asm/io.h>
30 #include <pci.h>
31 #include <asm/ic/sc520.h>
32
33 #define PROBE_BUFFER_SIZE 1024
34 static unsigned char buffer[PROBE_BUFFER_SIZE];
35
36
37 #define SC520_MAX_FLASH_BANKS  1
38 #define SC520_FLASH_BANK0_BASE 0x38000000  /* BOOTCS */
39 #define SC520_FLASH_BANKSIZE   0x8000000
40
41 #define A29LV641DH_SIZE        0x800000
42 #define A29LV641DH_SECTORS     128
43
44 #define A29LV641MH_SIZE        0x800000
45 #define A29LV641MH_SECTORS     128
46
47 #define I28F320J3A_SIZE        0x400000
48 #define I28F320J3A_SECTORS     32
49
50 #define I28F640J3A_SIZE        0x800000
51 #define I28F640J3A_SECTORS     64
52
53 #define I28F128J3A_SIZE        0x1000000
54 #define I28F128J3A_SECTORS     128
55
56 flash_info_t    flash_info[SC520_MAX_FLASH_BANKS];
57
58 #define READY 1
59 #define ERR   2
60 #define TMO   4
61
62 /*-----------------------------------------------------------------------
63  */
64
65
66 static u32 _probe_flash(u32 addr, u32 bw, int il)
67 {
68         u32 result=0;
69         
70         /* First do an unlock cycle for the benefit of
71          * devices that need it */
72         
73         switch (bw) {
74                 
75         case 1:
76                 *(volatile u8*)(addr+0x5555) = 0xaa;
77                 *(volatile u8*)(addr+0x2aaa) = 0x55;
78                 *(volatile u8*)(addr+0x5555) = 0x90;
79                 
80                 /* Read vendor */
81                 result = *(volatile u8*)addr;
82                 result <<= 16;
83                 
84                 /* Read device */
85                 result |= *(volatile u8*)(addr+2);
86                 
87                 /* Return device to data mode */
88                 *(volatile u8*)addr = 0xff;
89                 *(volatile u8*)(addr+0x5555), 0xf0;  
90                 break;
91                 
92         case 2:
93                 *(volatile u16*)(addr+0xaaaa) = 0xaaaa;
94                 *(volatile u16*)(addr+0x5554) = 0x5555;
95                 
96                 /* Issue identification command */
97                 if (il == 2) {
98                         *(volatile u16*)(addr+0xaaaa) = 0x9090;
99                         
100                         /* Read vendor */
101                         result = *(volatile u8*)addr;
102                         result <<= 16;
103                         
104                         /* Read device */
105                         result |= *(volatile u8*)(addr+2);
106                         
107                         /* Return device to data mode */
108                         *(volatile u16*)addr =  0xffff;
109                         *(volatile u16*)(addr+0xaaaa), 0xf0f0;  
110                         
111                 } else {
112                         *(volatile u8*)(addr+0xaaaa) = 0x90;
113                         /* Read vendor */
114                         result = *(volatile u16*)addr;
115                         result <<= 16;
116                         
117                         /* Read device */
118                         result |= *(volatile u16*)(addr+2);
119                         
120                         /* Return device to data mode */
121                         *(volatile u8*)addr = 0xff;
122                         *(volatile u8*)(addr+0xaaaa), 0xf0;                     
123                 }
124                 
125                 break;
126                 
127          case 4:
128                 *(volatile u32*)(addr+0x5554) = 0xaaaaaaaa;
129                 *(volatile u32*)(addr+0xaaa8) = 0x55555555;
130                 
131                 switch (il) {
132                 case 1:
133                         /* Issue identification command */
134                         *(volatile u8*)(addr+0x5554) = 0x90;
135                         
136                         /* Read vendor */
137                         result = *(volatile u16*)addr;
138                         result <<= 16;
139                 
140                         /* Read device */
141                         result |= *(volatile u16*)(addr+4);
142                         
143                         /* Return device to data mode */
144                         *(volatile u8*)addr =  0xff;
145                         *(volatile u8*)(addr+0x5554), 0xf0;  
146                         break;
147                         
148                 case 2:
149                         /* Issue identification command */
150                         *(volatile u32*)(addr + 0x5554) = 0x00900090;
151                         
152                         /* Read vendor */
153                         result = *(volatile u16*)addr;
154                         result <<= 16;
155                         
156                         /* Read device */
157                         result |= *(volatile u16*)(addr+4);
158                         
159                         /* Return device to data mode */
160                         *(volatile u32*)addr =  0x00ff00ff;
161                         *(volatile u32*)(addr+0x5554), 0x00f000f0;  
162                         break;
163                         
164                 case 4:
165                         /* Issue identification command */
166                         *(volatile u32*)(addr+0x5554) = 0x90909090;
167                         
168                         /* Read vendor */
169                         result = *(volatile u8*)addr;
170                         result <<= 16;
171                         
172                         /* Read device */
173                         result |= *(volatile u8*)(addr+4);
174                         
175                         /* Return device to data mode */
176                         *(volatile u32*)addr =  0xffffffff;
177                         *(volatile u32*)(addr+0x5554), 0xf0f0f0f0; 
178                         break;
179                 }
180                 break;
181         }
182         
183         
184         
185         return result;
186 }
187
188 extern int _probe_flash_end;
189 asm ("_probe_flash_end:\n"
190      ".long 0\n");
191
192 static int identify_flash(unsigned address, int width)
193 {
194         int is; 
195         int device;
196         int vendor;     
197         int size;
198         unsigned res;
199         
200         u32 (*_probe_flash_ptr)(u32 a, u32 bw, int il);
201         
202         size = (unsigned)&_probe_flash_end - (unsigned)_probe_flash; 
203         
204         if (size > PROBE_BUFFER_SIZE) {
205                 printf("_probe_flash() routine too large (%d) %p - %p\n",
206                        size, &_probe_flash_end, _probe_flash);
207                 return 0;
208         }
209         
210         memcpy(buffer, _probe_flash, size);
211         _probe_flash_ptr = (void*)buffer;
212         
213         is = disable_interrupts();
214         res = _probe_flash_ptr(address, width, 1);
215         if (is) {
216                 enable_interrupts();
217         }
218         
219         
220         vendor = res >> 16;
221         device = res & 0xffff;
222         
223                 
224         return res;
225 }
226
227 ulong flash_init(void)
228 {
229         int i, j;
230         ulong size = 0;
231         
232         for (i = 0; i < SC520_MAX_FLASH_BANKS; i++) {
233                 unsigned id;
234                 ulong flashbase = 0;
235                 int sectsize = 0; 
236                 
237                 memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
238                 switch (i) {
239                 case 0:
240                         flashbase = SC520_FLASH_BANK0_BASE;
241                         break;
242                 default:
243                         panic("configured to many flash banks!\n");
244                 }
245                 
246                 id = identify_flash(flashbase, 2);
247                 switch (id) {
248                 case 0x000122d7:
249                         /* 29LV641DH */
250                         flash_info[i].flash_id =
251                                 (AMD_MANUFACT & FLASH_VENDMASK) |
252                                 (AMD_ID_LV640U & FLASH_TYPEMASK);
253                         
254                         flash_info[i].size = A29LV641DH_SIZE;
255                         flash_info[i].sector_count = A29LV641DH_SECTORS;
256                         sectsize = A29LV641DH_SIZE/A29LV641DH_SECTORS;
257                         printf("Bank %d: AMD 29LV641DH\n", i);
258                         break;
259                         
260                 case 0x0001227E:
261                         /* 29LV641MH */
262                         flash_info[i].flash_id =
263                                 (AMD_MANUFACT & FLASH_VENDMASK) |
264                                 (AMD_ID_DL640 & FLASH_TYPEMASK);
265                         
266                         flash_info[i].size = A29LV641MH_SIZE;
267                         flash_info[i].sector_count = A29LV641MH_SECTORS;
268                         sectsize = A29LV641MH_SIZE/A29LV641MH_SECTORS;
269                         printf("Bank %d: AMD 29LV641MH\n", i);
270                         break;
271                         
272                 case 0x00890016:
273                         /* 28F320J3A */
274                         flash_info[i].flash_id =
275                                 (INTEL_MANUFACT & FLASH_VENDMASK) |
276                                 (INTEL_ID_28F320J3A & FLASH_TYPEMASK);
277                         
278                         flash_info[i].size = I28F320J3A_SIZE;
279                         flash_info[i].sector_count = I28F320J3A_SECTORS;
280                         sectsize = I28F320J3A_SIZE/I28F320J3A_SECTORS;
281                         printf("Bank %d: Intel 28F320J3A\n", i);
282                         break;
283                         
284                 case 0x00890017:
285                         /* 28F640J3A */
286                         flash_info[i].flash_id =
287                                 (INTEL_MANUFACT & FLASH_VENDMASK) |
288                                 (INTEL_ID_28F640J3A & FLASH_TYPEMASK);
289                         
290                         flash_info[i].size = I28F640J3A_SIZE;
291                         flash_info[i].sector_count = I28F640J3A_SECTORS;
292                         sectsize = I28F640J3A_SIZE/I28F640J3A_SECTORS;
293                         printf("Bank %d: Intel 28F640J3A\n", i);
294                         break;
295                         
296                 case 0x00890018:
297                         /* 28F128J3A */
298                         flash_info[i].flash_id =
299                                 (INTEL_MANUFACT & FLASH_VENDMASK) |
300                                 (INTEL_ID_28F128J3A & FLASH_TYPEMASK);
301                         
302                         flash_info[i].size = I28F128J3A_SIZE;
303                         flash_info[i].sector_count = I28F128J3A_SECTORS;
304                         sectsize = I28F128J3A_SIZE/I28F128J3A_SECTORS;
305                         printf("Bank %d: Intel 28F128J3A\n", i);
306                         break;
307                         
308                 default:
309                         printf("Bank %d have unknown flash %08x\n", i, id);
310                         flash_info[i].flash_id = FLASH_UNKNOWN;
311                         continue;
312                 }
313                 
314                 for (j = 0; j < flash_info[i].sector_count; j++) {
315                         flash_info[i].start[j] = flashbase + j * sectsize;
316                 }
317                 size += flash_info[i].size;
318                 
319                 flash_protect(FLAG_PROTECT_CLEAR,
320                               flash_info[i].start[0],
321                                flash_info[i].start[0] + flash_info[i].size - 1,
322                               &flash_info[i]);
323         }
324         
325         /*
326          * Protect monitor and environment sectors
327          */
328         flash_protect(FLAG_PROTECT_SET,
329                       i386boot_start,
330                       i386boot_end,
331                       &flash_info[0]);
332 #ifdef CFG_ENV_ADDR
333         flash_protect(FLAG_PROTECT_SET,
334                       CFG_ENV_ADDR,
335                       CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
336                       &flash_info[0]);
337 #endif  
338         return size;
339 }
340
341 /*-----------------------------------------------------------------------
342  */
343 void flash_print_info(flash_info_t *info)
344 {
345         int i;
346         
347         switch (info->flash_id & FLASH_VENDMASK) {
348         case (INTEL_MANUFACT & FLASH_VENDMASK):
349                 printf("INTEL: ");
350                 switch (info->flash_id & FLASH_TYPEMASK) {
351                 case (INTEL_ID_28F320J3A & FLASH_TYPEMASK):
352                         printf("1x I28F320J3A (32Mbit)\n");
353                         break;
354                 case (INTEL_ID_28F640J3A & FLASH_TYPEMASK):
355                         printf("1x I28F640J3A (64Mbit)\n");
356                         break;
357                 case (INTEL_ID_28F128J3A & FLASH_TYPEMASK):
358                         printf("1x I28F128J3A (128Mbit)\n");
359                         break;
360                 default:
361                         printf("Unknown Chip Type\n");
362                         goto done;
363                         break;
364                 }
365                 
366                 break;
367                 
368         case (AMD_MANUFACT & FLASH_VENDMASK):
369                 printf("AMD:   ");
370                 switch (info->flash_id & FLASH_TYPEMASK) {
371                 case (AMD_ID_LV640U & FLASH_TYPEMASK):
372                         printf("1x AMD29LV641DH (64Mbit)\n");
373                         break;
374                 case (AMD_ID_DL640 & FLASH_TYPEMASK):
375                         printf("1x AMD29LV641MH (64Mbit)\n");
376                         break;
377                 default:
378                         printf("Unknown Chip Type\n");
379                         goto done;
380                         break;
381                 }
382                 
383                 break;
384         default:
385                 printf("Unknown Vendor ");
386                 break;
387         }
388         
389         
390         printf("  Size: %ld MB in %d Sectors\n",
391                info->size >> 20, info->sector_count);
392         
393         printf("  Sector Start Addresses:");
394         for (i = 0; i < info->sector_count; i++) {
395                 if ((i % 5) == 0) {
396                         printf ("\n   ");
397                 }
398                 printf (" %08lX%s", info->start[i],
399                         info->protect[i] ? " (RO)" : "     ");
400         }
401         printf ("\n");
402         
403         done:
404 }
405
406 /*-----------------------------------------------------------------------
407  */
408
409
410 static u32 _amd_erase_flash(u32 addr, u32 sector)
411 {
412         unsigned elapsed;
413         
414         /* Issue erase */
415         *(volatile u16*)(addr + 0xaaaa) = 0x00AA;
416         *(volatile u16*)(addr + 0x5554) = 0x0055;
417         *(volatile u16*)(addr + 0xaaaa) = 0x0080;
418         /* And one unlock */
419         *(volatile u16*)(addr + 0xaaaa) = 0x00AA;
420         *(volatile u16*)(addr + 0x5554) = 0x0055;
421         /* Sector erase command comes last */
422         *(volatile u16*)(addr + sector) = 0x0030;
423         
424         elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
425         elapsed = 0;
426         while (((*(volatile u16*)(addr + sector)) & 0x0080) != 0x0080) {
427                 
428                 elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
429                 if (elapsed > ((CFG_FLASH_ERASE_TOUT/CFG_HZ) * 1000)) {
430                         *(volatile u16*)(addr) = 0x00f0;
431                         return 1;                       
432                 }
433         }
434         
435         *(volatile u16*)(addr) = 0x00f0;
436         
437         return 0;
438 }
439
440 extern int _amd_erase_flash_end;
441 asm ("_amd_erase_flash_end:\n"
442      ".long 0\n");
443
444 /* this needs to be inlined, the SWTMRMMILLI register is reset by each read */
445 #define __udelay(delay) \
446 {       \
447         unsigned micro; \
448         unsigned milli=0; \
449         \
450         micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
451          \
452         for (;;) { \
453                 \
454                 milli += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
455                 micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMICRO); \
456                 \
457                 if ((delay) <= (micro + (milli * 1000))) { \
458                         break; \
459                 } \
460         } \
461 } while (0) 
462
463 static u32 _intel_erase_flash(u32 addr, u32 sector)
464 {       
465         unsigned elapsed;
466         
467         *(volatile u16*)(addr + sector) = 0x0050;   /* clear status register */
468         *(volatile u16*)(addr + sector) = 0x0020;   /* erase setup */
469         *(volatile u16*)(addr + sector) = 0x00D0;   /* erase confirm */
470
471         
472         /* Wait at least 80us - let's wait 1 ms */
473         __udelay(1000);
474         
475         elapsed = 0;
476         while (((*(volatile u16*)(addr + sector)) & 0x0080) != 0x0080) {
477                 elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
478                 if (elapsed > ((CFG_FLASH_ERASE_TOUT/CFG_HZ) * 1000)) {
479                         *(volatile u16*)(addr + sector) = 0x00B0;  /* suspend erase      */
480                         *(volatile u16*)(addr + sector) = 0x00FF;  /* reset to read mode */
481                         return 1;                       
482                 }
483         }
484         
485         *(volatile u16*)(addr + sector) = 0x00FF;  /* reset to read mode */
486         
487         return 0;
488 }
489
490
491 extern int _intel_erase_flash_end;
492 asm ("_intel_erase_flash_end:\n"
493      ".long 0\n");
494
495 int flash_erase(flash_info_t *info, int s_first, int s_last)
496 {
497         u32 (*_erase_flash_ptr)(u32 a, u32 so);
498         int prot;
499         int sect;
500         unsigned size;
501         
502         if ((s_first < 0) || (s_first > s_last)) {
503                 if (info->flash_id == FLASH_UNKNOWN) {
504                         printf("- missing\n");
505                 } else {
506                         printf("- no sectors to erase\n");
507                 }
508                 return 1;
509         }
510         
511         if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
512                 size = (unsigned)&_amd_erase_flash_end - (unsigned)_amd_erase_flash; 
513                 
514                 if (size > PROBE_BUFFER_SIZE) {
515                         printf("_amd_erase_flash() routine too large (%d) %p - %p\n",
516                                size, &_amd_erase_flash_end, _amd_erase_flash);
517                         return 0;
518                 }
519                 
520                 memcpy(buffer, _amd_erase_flash, size);
521                 _erase_flash_ptr = (void*)buffer;
522         
523         } else if ((info->flash_id & FLASH_VENDMASK) == (INTEL_MANUFACT & FLASH_VENDMASK)) {
524                 size = (unsigned)&_intel_erase_flash_end - (unsigned)_intel_erase_flash; 
525                 
526                 if (size > PROBE_BUFFER_SIZE) {
527                         printf("_intel_erase_flash() routine too large (%d) %p - %p\n",
528                                size, &_intel_erase_flash_end, _intel_erase_flash);
529                         return 0;
530                 }
531                 
532                 memcpy(buffer, _intel_erase_flash, size);
533                 _erase_flash_ptr = (void*)buffer;
534         } else {
535                 printf ("Can't erase unknown flash type - aborted\n");
536                 return 1;
537         }
538         
539         prot = 0;
540         for (sect=s_first; sect<=s_last; ++sect) {
541                 if (info->protect[sect]) {
542                         prot++;
543                 }
544         }
545         
546         if (prot) {
547                 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
548         } else {
549                 printf ("\n");
550         }
551                 
552         
553         /* Start erase on unprotected sectors */
554         for (sect = s_first; sect<=s_last; sect++) {
555                 
556                 if (info->protect[sect] == 0) { /* not protected */
557                         int res;
558                         int flag;
559                         
560                         /* Disable interrupts which might cause a timeout here */
561                         flag = disable_interrupts();
562                         
563                         res = _erase_flash_ptr(info->start[0], info->start[sect]-info->start[0]);
564                         
565                         /* re-enable interrupts if necessary */
566                         if (flag) {
567                                 enable_interrupts();
568                         }
569                         
570                         
571                         if (res) {
572                                 printf("Erase timed out, sector %d\n", sect);
573                                 return res;
574                         }
575                         
576                         putc('.');                      
577                 }               
578         }
579
580         
581         return 0;
582 }
583
584 /*-----------------------------------------------------------------------
585  * Write a word to Flash, returns:
586  * 0 - OK
587  * 1 - write timeout
588  * 2 - Flash not erased
589  */
590 static int _amd_write_word(unsigned start, unsigned dest, unsigned data)
591 {
592         volatile u16 *addr2 = (u16*)start;
593         volatile u16 *dest2 = (u16*)dest;
594         volatile u16 *data2 = (u16*)&data;
595         int i;
596         unsigned elapsed;
597         
598         /* Check if Flash is (sufficiently) erased */
599         if ((*((volatile u16*)dest) & (u16)data) != (u16)data) {
600                 return 2;
601         }
602         
603         for (i = 0; i < 2; i++) {
604                 
605                 
606                 addr2[0x5555] = 0x00AA;
607                 addr2[0x2aaa] = 0x0055;
608                 addr2[0x5555] = 0x00A0;
609                 
610                 dest2[i] = (data >> (i*16)) & 0xffff;
611                 
612                 elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
613                 elapsed = 0;
614                 
615                 /* data polling for D7 */
616                 while ((dest2[i] & 0x0080) != (data2[i] & 0x0080)) {
617                         elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
618                         if (elapsed > ((CFG_FLASH_WRITE_TOUT/CFG_HZ) * 1000)) {
619                                 addr2[i] = 0x00f0;
620                                 return 1;                       
621                         }
622                 }
623         }
624         
625         addr2[i] = 0x00f0;
626         
627         return 0;
628 }
629
630 extern int _amd_write_word_end;
631 asm ("_amd_write_word_end:\n"
632      ".long 0\n");
633
634
635
636 static int _intel_write_word(unsigned start, unsigned dest, unsigned data)
637 {
638         int i;
639         unsigned elapsed;
640         
641         /* Check if Flash is (sufficiently) erased */
642         if ((*((volatile u16*)dest) & (u16)data) != (u16)data) {
643                 return 2;
644         }
645         
646         for (i = 0; i < 2; i++) {
647                 
648                 *(volatile u16*)(dest+2*i) = 0x0040; /* write setup */          
649                 *(volatile u16*)(dest+2*i) = (data >> (i*16)) & 0xffff;
650                 
651                 elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
652                 elapsed = 0;
653                 
654                 /* data polling for D7 */
655                 while ((*(volatile u16*)dest & 0x0080) != 0x0080) {
656                         elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
657                         if (elapsed > ((CFG_FLASH_WRITE_TOUT/CFG_HZ) * 1000)) {
658                                 *(volatile u16*)dest = 0x00ff;
659                                 return 1;                       
660                         }
661                 }
662         }
663         
664         *(volatile u16*)dest = 0x00ff;
665         
666         
667         return 0;
668
669 }
670
671 extern int _intel_write_word_end;
672 asm ("_intel_write_word_end:\n"
673      ".long 0\n");
674
675
676 /*-----------------------------------------------------------------------
677  * Copy memory to flash, returns:
678  * 0 - OK
679  * 1 - write timeout
680  * 2 - Flash not erased
681  * 3 - Unsupported flash type
682  */
683
684 int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
685 {
686         ulong cp, wp, data;
687         int i, l, rc;
688         int flag;
689         u32 (*_write_word_ptr)(unsigned start, unsigned dest, unsigned data);
690         unsigned size;
691         
692         if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
693                 size = (unsigned)&_amd_write_word_end - (unsigned)_amd_write_word; 
694                 
695                 if (size > PROBE_BUFFER_SIZE) {
696                         printf("_amd_write_word() routine too large (%d) %p - %p\n",
697                                size, &_amd_write_word_end, _amd_write_word);
698                         return 0;
699                 }
700                 
701                 memcpy(buffer, _amd_write_word, size);
702                 _write_word_ptr = (void*)buffer;
703         
704         } else if ((info->flash_id & FLASH_VENDMASK) == (INTEL_MANUFACT & FLASH_VENDMASK)) {
705                 size = (unsigned)&_intel_write_word_end - (unsigned)_intel_write_word; 
706                 
707                 if (size > PROBE_BUFFER_SIZE) {
708                         printf("_intel_write_word() routine too large (%d) %p - %p\n",
709                                size, &_intel_write_word_end, _intel_write_word);
710                         return 0;
711                 }
712                 
713                 memcpy(buffer, _intel_write_word, size);
714                 _write_word_ptr = (void*)buffer;
715         } else {
716                 printf ("Can't program unknown flash type - aborted\n");
717                 return 3;
718         }
719
720
721         wp = (addr & ~3);       /* get lower word aligned address */
722         
723
724         /*
725          * handle unaligned start bytes
726          */
727         if ((l = addr - wp) != 0) {
728                 data = 0;
729                 for (i=0, cp=wp; i<l; ++i, ++cp) {
730                         data |= (*(uchar *)cp) << (8*i);
731                 }
732                 for (; i<4 && cnt>0; ++i) {
733                         data |= *src++ << (8*i);
734                         --cnt;
735                         ++cp;
736                 }
737                 for (; cnt==0 && i<4; ++i, ++cp) {
738                         data |= (*(uchar *)cp)  << (8*i);
739                 }
740                 
741                 /* Disable interrupts which might cause a timeout here */
742                 flag = disable_interrupts();
743                 
744                 rc = _write_word_ptr(info->start[0], wp, data);
745                 
746                 /* re-enable interrupts if necessary */
747                 if (flag) {
748                         enable_interrupts();
749                 }
750                 if (rc != 0) {
751                         return rc;
752                 }
753                 wp += 4;
754         }
755         
756         /*
757          * handle word aligned part
758          */
759         while (cnt >= 4) {
760                 data = 0;
761                                
762                 for (i=0; i<4; ++i) {
763                         data |= *src++ << (8*i);
764                 }
765                 
766                 /* Disable interrupts which might cause a timeout here */
767                 flag = disable_interrupts();
768
769                 rc = _write_word_ptr(info->start[0], wp, data);
770                 
771                 /* re-enable interrupts if necessary */
772                 if (flag) {
773                         enable_interrupts();
774                 }
775                 if (rc != 0) {
776                         return rc;
777                 }
778                 wp  += 4;
779                 cnt -= 4;
780         }
781         
782         if (cnt == 0) {
783                 return 0;
784         }
785         
786         /*
787          * handle unaligned tail bytes
788          */
789         data = 0;
790         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
791                 data |= *src++ << (8*i);
792                 --cnt;
793         }
794         
795         for (; i<4; ++i, ++cp) {
796                 data |= (*(uchar *)cp) << (8*i);
797         }
798
799         /* Disable interrupts which might cause a timeout here */
800         flag = disable_interrupts();
801
802         rc = _write_word_ptr(info->start[0], wp, data);
803         
804         /* re-enable interrupts if necessary */
805         if (flag) {
806                 enable_interrupts();
807         }
808         
809         return rc;
810         
811 }
812
813