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