]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/sc520_spunk/flash.c
* Patches by Anders Larsen, 17 Sep 2003:
[karo-tx-uboot.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         return result;
185 }
186
187 extern int _probe_flash_end;
188 asm ("_probe_flash_end:\n"
189      ".long 0\n");
190
191 static int identify_flash(unsigned address, int width)
192 {
193         int is;
194         int device;
195         int vendor;
196         int size;
197         unsigned res;
198
199         u32 (*_probe_flash_ptr)(u32 a, u32 bw, int il);
200
201         size = (unsigned)&_probe_flash_end - (unsigned)_probe_flash;
202
203         if (size > PROBE_BUFFER_SIZE) {
204                 printf("_probe_flash() routine too large (%d) %p - %p\n",
205                        size, &_probe_flash_end, _probe_flash);
206                 return 0;
207         }
208
209         memcpy(buffer, _probe_flash, size);
210         _probe_flash_ptr = (void*)buffer;
211
212         is = disable_interrupts();
213         res = _probe_flash_ptr(address, width, 1);
214         if (is) {
215                 enable_interrupts();
216         }
217
218
219         vendor = res >> 16;
220         device = res & 0xffff;
221
222
223         return res;
224 }
225
226 ulong flash_init(void)
227 {
228         int i, j;
229         ulong size = 0;
230
231         for (i = 0; i < SC520_MAX_FLASH_BANKS; i++) {
232                 unsigned id;
233                 ulong flashbase = 0;
234                 int sectsize = 0;
235
236                 memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
237                 switch (i) {
238                 case 0:
239                         flashbase = SC520_FLASH_BANK0_BASE;
240                         break;
241                 default:
242                         panic("configured too many flash banks!\n");
243                 }
244
245                 id = identify_flash(flashbase, 2);
246                 switch (id) {
247                 case 0x000122d7:
248                         /* 29LV641DH */
249                         flash_info[i].flash_id =
250                                 (AMD_MANUFACT & FLASH_VENDMASK) |
251                                 (AMD_ID_LV640U & FLASH_TYPEMASK);
252
253                         flash_info[i].size = A29LV641DH_SIZE;
254                         flash_info[i].sector_count = A29LV641DH_SECTORS;
255                         sectsize = A29LV641DH_SIZE/A29LV641DH_SECTORS;
256                         printf("Bank %d: AMD 29LV641DH\n", i);
257                         break;
258
259                 case 0x0001227E:
260                         /* 29LV641MH */
261                         flash_info[i].flash_id =
262                                 (AMD_MANUFACT & FLASH_VENDMASK) |
263                                 (AMD_ID_DL640 & FLASH_TYPEMASK);
264
265                         flash_info[i].size = A29LV641MH_SIZE;
266                         flash_info[i].sector_count = A29LV641MH_SECTORS;
267                         sectsize = A29LV641MH_SIZE/A29LV641MH_SECTORS;
268                         printf("Bank %d: AMD 29LV641MH\n", i);
269                         break;
270
271                 case 0x00890016:
272                         /* 28F320J3A */
273                         flash_info[i].flash_id =
274                                 (INTEL_MANUFACT & FLASH_VENDMASK) |
275                                 (INTEL_ID_28F320J3A & FLASH_TYPEMASK);
276
277                         flash_info[i].size = I28F320J3A_SIZE;
278                         flash_info[i].sector_count = I28F320J3A_SECTORS;
279                         sectsize = I28F320J3A_SIZE/I28F320J3A_SECTORS;
280                         printf("Bank %d: Intel 28F320J3A\n", i);
281                         break;
282
283                 case 0x00890017:
284                         /* 28F640J3A */
285                         flash_info[i].flash_id =
286                                 (INTEL_MANUFACT & FLASH_VENDMASK) |
287                                 (INTEL_ID_28F640J3A & FLASH_TYPEMASK);
288
289                         flash_info[i].size = I28F640J3A_SIZE;
290                         flash_info[i].sector_count = I28F640J3A_SECTORS;
291                         sectsize = I28F640J3A_SIZE/I28F640J3A_SECTORS;
292                         printf("Bank %d: Intel 28F640J3A\n", i);
293                         break;
294
295                 case 0x00890018:
296                         /* 28F128J3A */
297                         flash_info[i].flash_id =
298                                 (INTEL_MANUFACT & FLASH_VENDMASK) |
299                                 (INTEL_ID_28F128J3A & FLASH_TYPEMASK);
300
301                         flash_info[i].size = I28F128J3A_SIZE;
302                         flash_info[i].sector_count = I28F128J3A_SECTORS;
303                         sectsize = I28F128J3A_SIZE/I28F128J3A_SECTORS;
304                         printf("Bank %d: Intel 28F128J3A\n", i);
305                         break;
306
307                 default:
308                         printf("Bank %d have unknown flash %08x\n", i, id);
309                         flash_info[i].flash_id = FLASH_UNKNOWN;
310                         continue;
311                 }
312
313                 for (j = 0; j < flash_info[i].sector_count; j++) {
314                         flash_info[i].start[j] = flashbase + j * sectsize;
315                 }
316                 size += flash_info[i].size;
317
318                 flash_protect(FLAG_PROTECT_CLEAR,
319                               flash_info[i].start[0],
320                                flash_info[i].start[0] + flash_info[i].size - 1,
321                               &flash_info[i]);
322         }
323
324         /*
325          * Protect monitor and environment sectors
326          */
327         flash_protect(FLAG_PROTECT_SET,
328                       i386boot_start,
329                       i386boot_end,
330                       &flash_info[0]);
331 #ifdef CFG_ENV_ADDR
332         flash_protect(FLAG_PROTECT_SET,
333                       CFG_ENV_ADDR,
334                       CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
335                       &flash_info[0]);
336 #endif
337         return size;
338 }
339
340 /*-----------------------------------------------------------------------
341  */
342 void flash_print_info(flash_info_t *info)
343 {
344         int i;
345
346         switch (info->flash_id & FLASH_VENDMASK) {
347         case (INTEL_MANUFACT & FLASH_VENDMASK):
348                 printf("INTEL: ");
349                 switch (info->flash_id & FLASH_TYPEMASK) {
350                 case (INTEL_ID_28F320J3A & FLASH_TYPEMASK):
351                         printf("1x I28F320J3A (32Mbit)\n");
352                         break;
353                 case (INTEL_ID_28F640J3A & FLASH_TYPEMASK):
354                         printf("1x I28F640J3A (64Mbit)\n");
355                         break;
356                 case (INTEL_ID_28F128J3A & FLASH_TYPEMASK):
357                         printf("1x I28F128J3A (128Mbit)\n");
358                         break;
359                 default:
360                         printf("Unknown Chip Type\n");
361                         goto done;
362                         break;
363                 }
364
365                 break;
366
367         case (AMD_MANUFACT & FLASH_VENDMASK):
368                 printf("AMD:   ");
369                 switch (info->flash_id & FLASH_TYPEMASK) {
370                 case (AMD_ID_LV640U & FLASH_TYPEMASK):
371                         printf("1x AMD29LV641DH (64Mbit)\n");
372                         break;
373                 case (AMD_ID_DL640 & FLASH_TYPEMASK):
374                         printf("1x AMD29LV641MH (64Mbit)\n");
375                         break;
376                 default:
377                         printf("Unknown Chip Type\n");
378                         goto done;
379                         break;
380                 }
381
382                 break;
383         default:
384                 printf("Unknown Vendor ");
385                 break;
386         }
387
388
389         printf("  Size: %ld MB in %d Sectors\n",
390                info->size >> 20, info->sector_count);
391
392         printf("  Sector Start Addresses:");
393         for (i = 0; i < info->sector_count; i++) {
394                 if ((i % 5) == 0) {
395                         printf ("\n   ");
396                 }
397                 printf (" %08lX%s", info->start[i],
398                         info->protect[i] ? " (RO)" : "     ");
399         }
400         printf ("\n");
401
402         done:
403 }
404
405 /*-----------------------------------------------------------------------
406  */
407
408
409 static u32 _amd_erase_flash(u32 addr, u32 sector)
410 {
411         unsigned elapsed;
412
413         /* Issue erase */
414         *(volatile u16*)(addr + 0xaaaa) = 0x00AA;
415         *(volatile u16*)(addr + 0x5554) = 0x0055;
416         *(volatile u16*)(addr + 0xaaaa) = 0x0080;
417         /* And one unlock */
418         *(volatile u16*)(addr + 0xaaaa) = 0x00AA;
419         *(volatile u16*)(addr + 0x5554) = 0x0055;
420         /* Sector erase command comes last */
421         *(volatile u16*)(addr + sector) = 0x0030;
422
423         elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
424         elapsed = 0;
425         while (((*(volatile u16*)(addr + sector)) & 0x0080) != 0x0080) {
426
427                 elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
428                 if (elapsed > ((CFG_FLASH_ERASE_TOUT/CFG_HZ) * 1000)) {
429                         *(volatile u16*)(addr) = 0x00f0;
430                         return 1;
431                 }
432         }
433
434         *(volatile u16*)(addr) = 0x00f0;
435
436         return 0;
437 }
438
439 extern int _amd_erase_flash_end;
440 asm ("_amd_erase_flash_end:\n"
441      ".long 0\n");
442
443 /* this needs to be inlined, the SWTMRMMILLI register is reset by each read */
444 #define __udelay(delay) \
445 {       \
446         unsigned micro; \
447         unsigned milli=0; \
448         \
449         micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
450          \
451         for (;;) { \
452                 \
453                 milli += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
454                 micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMICRO); \
455                 \
456                 if ((delay) <= (micro + (milli * 1000))) { \
457                         break; \
458                 } \
459         } \
460 } while (0)
461
462 static u32 _intel_erase_flash(u32 addr, u32 sector)
463 {
464         unsigned elapsed;
465
466         *(volatile u16*)(addr + sector) = 0x0050;   /* clear status register */
467         *(volatile u16*)(addr + sector) = 0x0020;   /* erase setup */
468         *(volatile u16*)(addr + sector) = 0x00D0;   /* erase confirm */
469
470
471         /* Wait at least 80us - let's wait 1 ms */
472         __udelay(1000);
473
474         elapsed = 0;
475         while (((*(volatile u16*)(addr + sector)) & 0x0080) != 0x0080) {
476                 elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
477                 if (elapsed > ((CFG_FLASH_ERASE_TOUT/CFG_HZ) * 1000)) {
478                         *(volatile u16*)(addr + sector) = 0x00B0;  /* suspend erase      */
479                         *(volatile u16*)(addr + sector) = 0x00FF;  /* reset to read mode */
480                         return 1;
481                 }
482         }
483
484         *(volatile u16*)(addr + sector) = 0x00FF;  /* reset to read mode */
485
486         return 0;
487 }
488
489
490 extern int _intel_erase_flash_end;
491 asm ("_intel_erase_flash_end:\n"
492      ".long 0\n");
493
494 int flash_erase(flash_info_t *info, int s_first, int s_last)
495 {
496         u32 (*_erase_flash_ptr)(u32 a, u32 so);
497         int prot;
498         int sect;
499         unsigned size;
500
501         if ((s_first < 0) || (s_first > s_last)) {
502                 if (info->flash_id == FLASH_UNKNOWN) {
503                         printf("- missing\n");
504                 } else {
505                         printf("- no sectors to erase\n");
506                 }
507                 return 1;
508         }
509
510         if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
511                 size = (unsigned)&_amd_erase_flash_end - (unsigned)_amd_erase_flash;
512
513                 if (size > PROBE_BUFFER_SIZE) {
514                         printf("_amd_erase_flash() routine too large (%d) %p - %p\n",
515                                size, &_amd_erase_flash_end, _amd_erase_flash);
516                         return 0;
517                 }
518
519                 memcpy(buffer, _amd_erase_flash, size);
520                 _erase_flash_ptr = (void*)buffer;
521
522         } else if ((info->flash_id & FLASH_VENDMASK) == (INTEL_MANUFACT & FLASH_VENDMASK)) {
523                 size = (unsigned)&_intel_erase_flash_end - (unsigned)_intel_erase_flash;
524
525                 if (size > PROBE_BUFFER_SIZE) {
526                         printf("_intel_erase_flash() routine too large (%d) %p - %p\n",
527                                size, &_intel_erase_flash_end, _intel_erase_flash);
528                         return 0;
529                 }
530
531                 memcpy(buffer, _intel_erase_flash, size);
532                 _erase_flash_ptr = (void*)buffer;
533         } else {
534                 printf ("Can't erase unknown flash type - aborted\n");
535                 return 1;
536         }
537
538         prot = 0;
539         for (sect=s_first; sect<=s_last; ++sect) {
540                 if (info->protect[sect]) {
541                         prot++;
542                 }
543         }
544
545         if (prot) {
546                 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
547         } else {
548                 printf ("\n");
549         }
550
551
552         /* Start erase on unprotected sectors */
553         for (sect = s_first; sect<=s_last; sect++) {
554
555                 if (info->protect[sect] == 0) { /* not protected */
556                         int res;
557                         int flag;
558
559                         /* Disable interrupts which might cause a timeout here */
560                         flag = disable_interrupts();
561
562                         res = _erase_flash_ptr(info->start[0], info->start[sect]-info->start[0]);
563
564                         /* re-enable interrupts if necessary */
565                         if (flag) {
566                                 enable_interrupts();
567                         }
568
569
570                         if (res) {
571                                 printf("Erase timed out, sector %d\n", sect);
572                                 return res;
573                         }
574
575                         putc('.');
576                 }
577         }
578
579
580         return 0;
581 }
582
583 /*-----------------------------------------------------------------------
584  * Write a word to Flash, returns:
585  * 0 - OK
586  * 1 - write timeout
587  * 2 - Flash not erased
588  */
589 static int _amd_write_word(unsigned start, unsigned dest, unsigned data)
590 {
591         volatile u16 *addr2 = (u16*)start;
592         volatile u16 *dest2 = (u16*)dest;
593         volatile u16 *data2 = (u16*)&data;
594         int i;
595         unsigned elapsed;
596
597         /* Check if Flash is (sufficiently) erased */
598         if ((*((volatile u16*)dest) & (u16)data) != (u16)data) {
599                 return 2;
600         }
601
602         for (i = 0; i < 2; i++) {
603
604
605                 addr2[0x5555] = 0x00AA;
606                 addr2[0x2aaa] = 0x0055;
607                 addr2[0x5555] = 0x00A0;
608
609                 dest2[i] = (data >> (i*16)) & 0xffff;
610
611                 elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
612                 elapsed = 0;
613
614                 /* data polling for D7 */
615                 while ((dest2[i] & 0x0080) != (data2[i] & 0x0080)) {
616                         elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
617                         if (elapsed > ((CFG_FLASH_WRITE_TOUT/CFG_HZ) * 1000)) {
618                                 addr2[i] = 0x00f0;
619                                 return 1;
620                         }
621                 }
622         }
623
624         addr2[i] = 0x00f0;
625
626         return 0;
627 }
628
629 extern int _amd_write_word_end;
630 asm ("_amd_write_word_end:\n"
631      ".long 0\n");
632
633
634 static int _intel_write_word(unsigned start, unsigned dest, unsigned data)
635 {
636         int i;
637         unsigned elapsed;
638
639         /* Check if Flash is (sufficiently) erased */
640         if ((*((volatile u16*)dest) & (u16)data) != (u16)data) {
641                 return 2;
642         }
643
644         for (i = 0; i < 2; i++) {
645
646                 *(volatile u16*)(dest+2*i) = 0x0040; /* write setup */
647                 *(volatile u16*)(dest+2*i) = (data >> (i*16)) & 0xffff;
648
649                 elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
650                 elapsed = 0;
651
652                 /* data polling for D7 */
653                 while ((*(volatile u16*)dest & 0x0080) != 0x0080) {
654                         elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
655                         if (elapsed > ((CFG_FLASH_WRITE_TOUT/CFG_HZ) * 1000)) {
656                                 *(volatile u16*)dest = 0x00ff;
657                                 return 1;
658                         }
659                 }
660         }
661
662         *(volatile u16*)dest = 0x00ff;
663
664
665         return 0;
666
667 }
668
669 extern int _intel_write_word_end;
670 asm ("_intel_write_word_end:\n"
671      ".long 0\n");
672
673
674 /*-----------------------------------------------------------------------
675  * Copy memory to flash, returns:
676  * 0 - OK
677  * 1 - write timeout
678  * 2 - Flash not erased
679  * 3 - Unsupported flash type
680  */
681
682 int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
683 {
684         ulong cp, wp, data;
685         int i, l, rc;
686         int flag;
687         u32 (*_write_word_ptr)(unsigned start, unsigned dest, unsigned data);
688         unsigned size;
689
690         if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
691                 size = (unsigned)&_amd_write_word_end - (unsigned)_amd_write_word;
692
693                 if (size > PROBE_BUFFER_SIZE) {
694                         printf("_amd_write_word() routine too large (%d) %p - %p\n",
695                                size, &_amd_write_word_end, _amd_write_word);
696                         return 0;
697                 }
698
699                 memcpy(buffer, _amd_write_word, size);
700                 _write_word_ptr = (void*)buffer;
701
702         } else if ((info->flash_id & FLASH_VENDMASK) == (INTEL_MANUFACT & FLASH_VENDMASK)) {
703                 size = (unsigned)&_intel_write_word_end - (unsigned)_intel_write_word;
704
705                 if (size > PROBE_BUFFER_SIZE) {
706                         printf("_intel_write_word() routine too large (%d) %p - %p\n",
707                                size, &_intel_write_word_end, _intel_write_word);
708                         return 0;
709                 }
710
711                 memcpy(buffer, _intel_write_word, size);
712                 _write_word_ptr = (void*)buffer;
713         } else {
714                 printf ("Can't program unknown flash type - aborted\n");
715                 return 3;
716         }
717
718
719         wp = (addr & ~3);       /* get lower word aligned address */
720
721
722         /*
723          * handle unaligned start bytes
724          */
725         if ((l = addr - wp) != 0) {
726                 data = 0;
727                 for (i=0, cp=wp; i<l; ++i, ++cp) {
728                         data |= (*(uchar *)cp) << (8*i);
729                 }
730                 for (; i<4 && cnt>0; ++i) {
731                         data |= *src++ << (8*i);
732                         --cnt;
733                         ++cp;
734                 }
735                 for (; cnt==0 && i<4; ++i, ++cp) {
736                         data |= (*(uchar *)cp)  << (8*i);
737                 }
738
739                 /* Disable interrupts which might cause a timeout here */
740                 flag = disable_interrupts();
741
742                 rc = _write_word_ptr(info->start[0], wp, data);
743
744                 /* re-enable interrupts if necessary */
745                 if (flag) {
746                         enable_interrupts();
747                 }
748                 if (rc != 0) {
749                         return rc;
750                 }
751                 wp += 4;
752         }
753
754         /*
755          * handle word aligned part
756          */
757         while (cnt >= 4) {
758                 data = 0;
759
760                 for (i=0; i<4; ++i) {
761                         data |= *src++ << (8*i);
762                 }
763
764                 /* Disable interrupts which might cause a timeout here */
765                 flag = disable_interrupts();
766
767                 rc = _write_word_ptr(info->start[0], wp, data);
768
769                 /* re-enable interrupts if necessary */
770                 if (flag) {
771                         enable_interrupts();
772                 }
773                 if (rc != 0) {
774                         return rc;
775                 }
776                 wp  += 4;
777                 cnt -= 4;
778         }
779
780         if (cnt == 0) {
781                 return 0;
782         }
783
784         /*
785          * handle unaligned tail bytes
786          */
787         data = 0;
788         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
789                 data |= *src++ << (8*i);
790                 --cnt;
791         }
792
793         for (; i<4; ++i, ++cp) {
794                 data |= (*(uchar *)cp) << (8*i);
795         }
796
797         /* Disable interrupts which might cause a timeout here */
798         flag = disable_interrupts();
799
800         rc = _write_word_ptr(info->start[0], wp, data);
801
802         /* re-enable interrupts if necessary */
803         if (flag) {
804                 enable_interrupts();
805         }
806
807         return rc;
808
809 }