]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/pcs440ep/flash.c
kconfig: arm: remove duplicate definitions of SOC_MX*
[karo-tx-uboot.git] / board / pcs440ep / flash.c
1 /*
2  * (C) Copyright 2006
3  * Stefan Roese, DENX Software Engineering, sr@denx.de.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <asm/processor.h>
10
11 #ifndef CONFIG_SYS_FLASH_READ0
12 #define CONFIG_SYS_FLASH_READ0          0x0000  /* 0 is standard                        */
13 #define CONFIG_SYS_FLASH_READ1          0x0001  /* 1 is standard                        */
14 #define CONFIG_SYS_FLASH_READ2          0x0002  /* 2 is standard                        */
15 #endif
16
17 flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
18
19 /*
20  * Functions
21  */
22 static int write_word(flash_info_t *info, ulong dest, ulong data);
23 static ulong flash_get_size(vu_long *addr, flash_info_t *info);
24
25 unsigned long flash_init(void)
26 {
27         unsigned long size_b0, size_b1;
28         int i;
29         unsigned long base_b0, base_b1;
30
31         /* Init: no FLASHes known */
32         for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
33                 flash_info[i].flash_id = FLASH_UNKNOWN;
34         }
35
36         /* Static FLASH Bank configuration here - FIXME XXX */
37
38         base_b0 = FLASH_BASE0_PRELIM;
39         size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
40
41         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
42                 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
43                                 size_b0, size_b0 << 20);
44         }
45
46         base_b1 = FLASH_BASE1_PRELIM;
47         size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
48
49         return (size_b0 + size_b1);
50 }
51
52 void flash_print_info(flash_info_t *info)
53 {
54         int i;
55         int k;
56         int size;
57         int erased;
58         volatile unsigned long *flash;
59
60         if (info->flash_id == FLASH_UNKNOWN) {
61                 printf ("missing or unknown FLASH type\n");
62                 return;
63         }
64
65         switch (info->flash_id & FLASH_VENDMASK) {
66         case FLASH_MAN_AMD:     printf ("AMD ");                break;
67         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
68         case FLASH_MAN_SST:     printf ("SST ");                break;
69         case FLASH_MAN_STM:     printf ("ST Micro");            break;
70         case FLASH_MAN_EXCEL:   printf ("Excel Semiconductor "); break;
71         case FLASH_MAN_MX:      printf ("MXIC "); break;
72         default:                printf ("Unknown Vendor ");     break;
73         }
74
75         switch (info->flash_id & FLASH_TYPEMASK) {
76         case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
77                 break;
78         case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
79                 break;
80         case FLASH_AM040:       printf ("AM29LV040B (4 Mbit, uniform sector size)\n");
81                 break;
82         case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
83                 break;
84         case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
85                 break;
86         case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
87                 break;
88         case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
89                 break;
90         case FLASH_AM320T:      printf ("AM29LV320T (32 M, top sector)\n");
91                 break;
92         case FLASH_AM320B:      printf ("AM29LV320B (32 M, bottom sector)\n");
93                 break;
94         case FLASH_AMDL322T:    printf ("AM29DL322T (32 M, top sector)\n");
95                 break;
96         case FLASH_AMDL322B:    printf ("AM29DL322B (32 M, bottom sector)\n");
97                 break;
98         case FLASH_AMDL323T:    printf ("AM29DL323T (32 M, top sector)\n");
99                 break;
100         case FLASH_AMDL323B:    printf ("AM29DL323B (32 M, bottom sector)\n");
101                 break;
102         case FLASH_SST020:      printf ("SST39LF/VF020 (2 Mbit, uniform sector size)\n");
103                 break;
104         case FLASH_SST040:      printf ("SST39LF/VF040 (4 Mbit, uniform sector size)\n");
105                 break;
106         case STM_ID_M29W040B:   printf ("ST Micro M29W040B (4 Mbit, uniform sector size)\n");
107                 break;
108         default:                printf ("Unknown Chip Type\n");
109                 break;
110         }
111
112         printf ("  Size: %ld MB in %d Sectors\n",
113                 info->size >> 20, info->sector_count);
114
115         printf ("  Sector Start Addresses:");
116         for (i=0; i<info->sector_count; ++i) {
117 #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
118                 /*
119                  * Check if whole sector is erased
120                  */
121                 if (i != (info->sector_count-1))
122                         size = info->start[i+1] - info->start[i];
123                 else
124                         size = info->start[0] + info->size - info->start[i];
125                 erased = 1;
126                 flash = (volatile unsigned long *)info->start[i];
127                 size = size >> 2;       /* divide by 4 for longword access */
128                 for (k=0; k<size; k++) {
129                         if (*flash++ != 0xffffffff) {
130                                 erased = 0;
131                                 break;
132                         }
133                 }
134
135                 if ((i % 5) == 0)
136                         printf ("\n   ");
137                 /* print empty and read-only info */
138                 printf (" %08lX%s%s",
139                         info->start[i],
140                         erased ? " E" : "  ",
141                         info->protect[i] ? "RO " : "   ");
142 #else
143                 if ((i % 5) == 0)
144                         printf ("\n   ");
145                 printf (" %08lX%s",
146                         info->start[i],
147                         info->protect[i] ? " (RO)" : "     ");
148 #endif
149
150         }
151         printf ("\n");
152         return;
153 }
154
155 /*
156  * The following code cannot be run from FLASH!
157  */
158 static ulong flash_get_size(vu_long *addr, flash_info_t *info)
159 {
160         short i;
161         short n;
162         volatile CONFIG_SYS_FLASH_WORD_SIZE value;
163         ulong base = (ulong)addr;
164         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2 = (volatile CONFIG_SYS_FLASH_WORD_SIZE *)addr;
165
166         /* Write auto select command: read Manufacturer ID */
167         addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00AA00AA;
168         addr2[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00550055;
169         addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00900090;
170
171         value = addr2[CONFIG_SYS_FLASH_READ0];
172
173         switch (value) {
174         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_MANUFACT:
175                 info->flash_id = FLASH_MAN_AMD;
176                 break;
177         case (CONFIG_SYS_FLASH_WORD_SIZE)FUJ_MANUFACT:
178                 info->flash_id = FLASH_MAN_FUJ;
179                 break;
180         case (CONFIG_SYS_FLASH_WORD_SIZE)SST_MANUFACT:
181                 info->flash_id = FLASH_MAN_SST;
182                 break;
183         case (CONFIG_SYS_FLASH_WORD_SIZE)STM_MANUFACT:
184                 info->flash_id = FLASH_MAN_STM;
185                 break;
186         case (CONFIG_SYS_FLASH_WORD_SIZE)EXCEL_MANUFACT:
187                 info->flash_id = FLASH_MAN_EXCEL;
188                 break;
189         case (CONFIG_SYS_FLASH_WORD_SIZE)MX_MANUFACT:
190                 info->flash_id = FLASH_MAN_MX;
191                 break;
192         default:
193                 info->flash_id = FLASH_UNKNOWN;
194                 info->sector_count = 0;
195                 info->size = 0;
196                 return (0);                     /* no or unknown flash  */
197         }
198
199         value = addr2[CONFIG_SYS_FLASH_READ1];          /* device ID    */
200
201         switch (value) {
202         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV400T:
203                 info->flash_id += FLASH_AM400T;
204                 info->sector_count = 11;
205                 info->size = 0x00080000;
206                 break;                          /* => 0.5 MB    */
207
208         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV400B:
209                 info->flash_id += FLASH_AM400B;
210                 info->sector_count = 11;
211                 info->size = 0x00080000;
212                 break;                          /* => 0.5 MB    */
213
214         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV040B:
215                 info->flash_id += FLASH_AM040;
216                 info->sector_count = 8;
217                 info->size = 0x0080000;         /* => 0.5 MB    */
218                 break;
219         case (CONFIG_SYS_FLASH_WORD_SIZE)STM_ID_M29W040B:
220                 info->flash_id += FLASH_AM040;
221                 info->sector_count = 8;
222                 info->size = 0x0080000; /* => 0,5 MB */
223                 break;
224
225         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV800T:
226                 info->flash_id += FLASH_AM800T;
227                 info->sector_count = 19;
228                 info->size = 0x00100000;
229                 break;                          /* => 1 MB      */
230
231         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV800B:
232                 info->flash_id += FLASH_AM800B;
233                 info->sector_count = 19;
234                 info->size = 0x00100000;
235                 break;                          /* => 1 MB      */
236
237         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV160T:
238                 info->flash_id += FLASH_AM160T;
239                 info->sector_count = 35;
240                 info->size = 0x00200000;
241                 break;                          /* => 2 MB      */
242
243         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV160B:
244                 info->flash_id += FLASH_AM160B;
245                 info->sector_count = 35;
246                 info->size = 0x00200000;
247                 break;                          /* => 2 MB      */
248
249         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV320T:
250                 info->flash_id += FLASH_AM320T;
251                 info->sector_count = 71;
252                 info->size = 0x00400000;
253                 break;                          /* => 4 MB      */
254
255         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_LV320B:
256                 info->flash_id += FLASH_AM320B;
257                 info->sector_count = 71;
258                 info->size = 0x00400000;
259                 break;                          /* => 4 MB      */
260
261         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_DL322T:
262                 info->flash_id += FLASH_AMDL322T;
263                 info->sector_count = 71;
264                 info->size = 0x00400000;
265                 break;                          /* => 4 MB      */
266
267         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_DL322B:
268                 info->flash_id += FLASH_AMDL322B;
269                 info->sector_count = 71;
270                 info->size = 0x00400000;
271                 break;                          /* => 4 MB      */
272
273         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_DL323T:
274                 info->flash_id += FLASH_AMDL323T;
275                 info->sector_count = 71;
276                 info->size = 0x00400000;
277                 break;                          /* => 4 MB      */
278
279         case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_DL323B:
280                 info->flash_id += FLASH_AMDL323B;
281                 info->sector_count = 71;
282                 info->size = 0x00400000;
283                 break;                          /* => 4 MB      */
284
285         case (CONFIG_SYS_FLASH_WORD_SIZE)SST_ID_xF020:
286                 info->flash_id += FLASH_SST020;
287                 info->sector_count = 64;
288                 info->size = 0x00040000;
289                 break;                          /* => 256 kB    */
290
291         case (CONFIG_SYS_FLASH_WORD_SIZE)SST_ID_xF040:
292                 info->flash_id += FLASH_SST040;
293                 info->sector_count = 128;
294                 info->size = 0x00080000;
295                 break;                          /* => 512 kB    */
296
297         default:
298                 info->flash_id = FLASH_UNKNOWN;
299                 return (0);                     /* => no or unknown flash */
300
301         }
302
303         /* set up sector start address table */
304         if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
305             ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
306                 for (i = 0; i < info->sector_count; i++)
307                         info->start[i] = base + (i * 0x00001000);
308         } else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
309                 for (i = 0; i < info->sector_count; i++)
310                         info->start[i] = base + (i * 0x00010000);
311         } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
312                    ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
313                    ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
314                    ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
315                 /* set sector offsets for bottom boot block type        */
316                 for (i=0; i<8; ++i) {           /*  8 x 8k boot sectors */
317                         info->start[i] = base;
318                         base += 8 << 10;
319                 }
320                 while (i < info->sector_count) {        /* 64k regular sectors  */
321                         info->start[i] = base;
322                         base += 64 << 10;
323                         ++i;
324                 }
325         } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
326                    ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
327                    ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
328                    ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
329                 /* set sector offsets for top boot block type           */
330                 base += info->size;
331                 i = info->sector_count;
332                 for (n=0; n<8; ++n) {           /*  8 x 8k boot sectors */
333                         base -= 8 << 10;
334                         --i;
335                         info->start[i] = base;
336                 }
337                 while (i > 0) {                 /* 64k regular sectors  */
338                         base -= 64 << 10;
339                         --i;
340                         info->start[i] = base;
341                 }
342         } else {
343                 if (info->flash_id & FLASH_BTYPE) {
344                         /* set sector offsets for bottom boot block type        */
345                         info->start[0] = base + 0x00000000;
346                         info->start[1] = base + 0x00004000;
347                         info->start[2] = base + 0x00006000;
348                         info->start[3] = base + 0x00008000;
349                         for (i = 4; i < info->sector_count; i++) {
350                                 info->start[i] = base + (i * 0x00010000) - 0x00030000;
351                         }
352                 } else {
353                         /* set sector offsets for top boot block type           */
354                         i = info->sector_count - 1;
355                         info->start[i--] = base + info->size - 0x00004000;
356                         info->start[i--] = base + info->size - 0x00006000;
357                         info->start[i--] = base + info->size - 0x00008000;
358                         for (; i >= 0; i--) {
359                                 info->start[i] = base + i * 0x00010000;
360                         }
361                 }
362         }
363
364         /* check for protected sectors */
365         for (i = 0; i < info->sector_count; i++) {
366                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
367                 /* D0 = 1 if protected */
368                 addr2 = (volatile CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[i]);
369                 if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_AMD)
370                         info->protect[i] = 0;
371                 else
372                         info->protect[i] = addr2[CONFIG_SYS_FLASH_READ2] & 1;
373         }
374
375         /*
376          * Prevent writes to uninitialized FLASH.
377          */
378         if (info->flash_id != FLASH_UNKNOWN) {
379                 addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *)info->start[0];
380                 *addr2 = (CONFIG_SYS_FLASH_WORD_SIZE)0x00F000F0;        /* reset bank */
381         }
382
383         return (info->size);
384 }
385
386
387 int flash_erase(flash_info_t *info, int s_first, int s_last)
388 {
389         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr = (CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[0]);
390         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2;
391         int flag, prot, sect, l_sect;
392         ulong start, now, last;
393
394         if ((s_first < 0) || (s_first > s_last)) {
395                 if (info->flash_id == FLASH_UNKNOWN)
396                         printf ("- missing\n");
397                 else
398                         printf ("- no sectors to erase\n");
399                 return 1;
400         }
401
402         if (info->flash_id == FLASH_UNKNOWN) {
403                 printf ("Can't erase unknown flash type - aborted\n");
404                 return 1;
405         }
406
407         prot = 0;
408         for (sect=s_first; sect<=s_last; ++sect)
409                 if (info->protect[sect])
410                         prot++;
411
412         if (prot)
413                 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
414         else
415                 printf ("\n");
416
417         l_sect = -1;
418
419         /* Disable interrupts which might cause a timeout here */
420         flag = disable_interrupts();
421
422         /* Start erase on unprotected sectors */
423         for (sect = s_first; sect<=s_last; sect++) {
424                 if (info->protect[sect] == 0) { /* not protected */
425                         addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[sect]);
426                         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
427                                 addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00AA00AA;
428                                 addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00550055;
429                                 addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080;
430                                 addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00AA00AA;
431                                 addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00550055;
432                                 addr2[0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00300030;  /* sector erase */
433
434                                 /* re-enable interrupts if necessary */
435                                 if (flag) {
436                                         enable_interrupts();
437                                         flag = 0;
438                                 }
439
440                                 /* data polling for D7 */
441                                 start = get_timer (0);
442                                 while ((addr2[0] & (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080) !=
443                                        (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080) {
444                                         if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT)
445                                                 return (1);
446                                 }
447                         } else {
448                                 if (sect == s_first) {
449                                         addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00AA00AA;
450                                         addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00550055;
451                                         addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080;
452                                         addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00AA00AA;
453                                         addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00550055;
454                                 }
455                                 addr2[0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00300030;  /* sector erase */
456                         }
457                         l_sect = sect;
458                 }
459         }
460
461         /* re-enable interrupts if necessary */
462         if (flag)
463                 enable_interrupts();
464
465         /* wait at least 80us - let's wait 1 ms */
466         udelay (1000);
467
468         /*
469          * We wait for the last triggered sector
470          */
471         if (l_sect < 0)
472                 goto DONE;
473
474         start = get_timer (0);
475         last  = start;
476         addr = (CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[l_sect]);
477         while ((addr[0] & (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080) != (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080) {
478                 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
479                         printf ("Timeout\n");
480                         return 1;
481                 }
482                 /* show that we're waiting */
483                 if ((now - last) > 1000) {      /* every second */
484                         putc ('.');
485                         last = now;
486                 }
487         }
488
489 DONE:
490         /* reset to read mode */
491         addr = (CONFIG_SYS_FLASH_WORD_SIZE *)info->start[0];
492         addr[0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00F000F0;       /* reset bank */
493
494         printf (" done\n");
495         return 0;
496 }
497
498 /*
499  * Copy memory to flash, returns:
500  * 0 - OK
501  * 1 - write timeout
502  * 2 - Flash not erased
503  */
504 int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
505 {
506         ulong cp, wp, data;
507         int i, l, rc;
508
509         wp = (addr & ~3);       /* get lower word aligned address */
510
511         /*
512          * handle unaligned start bytes
513          */
514         if ((l = addr - wp) != 0) {
515                 data = 0;
516                 for (i=0, cp=wp; i<l; ++i, ++cp) {
517                         data = (data << 8) | (*(uchar *)cp);
518                 }
519                 for (; i<4 && cnt>0; ++i) {
520                         data = (data << 8) | *src++;
521                         --cnt;
522                         ++cp;
523                 }
524                 for (; cnt==0 && i<4; ++i, ++cp) {
525                         data = (data << 8) | (*(uchar *)cp);
526                 }
527
528                 if ((rc = write_word(info, wp, data)) != 0) {
529                         return (rc);
530                 }
531                 wp += 4;
532         }
533
534         /*
535          * handle word aligned part
536          */
537         while (cnt >= 4) {
538                 data = 0;
539                 for (i=0; i<4; ++i)
540                         data = (data << 8) | *src++;
541                 if ((rc = write_word(info, wp, data)) != 0)
542                         return (rc);
543                 wp  += 4;
544                 cnt -= 4;
545         }
546
547         if (cnt == 0)
548                 return (0);
549
550         /*
551          * handle unaligned tail bytes
552          */
553         data = 0;
554         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
555                 data = (data << 8) | *src++;
556                 --cnt;
557         }
558         for (; i<4; ++i, ++cp)
559                 data = (data << 8) | (*(uchar *)cp);
560
561         return (write_word(info, wp, data));
562 }
563
564 /*
565  * Write a word to Flash, returns:
566  * 0 - OK
567  * 1 - write timeout
568  * 2 - Flash not erased
569  */
570 static int write_word(flash_info_t *info, ulong dest, ulong data)
571 {
572         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[0]);
573         volatile CONFIG_SYS_FLASH_WORD_SIZE *dest2 = (CONFIG_SYS_FLASH_WORD_SIZE *)dest;
574         volatile CONFIG_SYS_FLASH_WORD_SIZE *data2 = (CONFIG_SYS_FLASH_WORD_SIZE *)&data;
575         ulong start;
576         int flag;
577         int i;
578
579         /* Check if Flash is (sufficiently) erased */
580         if ((*((vu_long *)dest) & data) != data)
581                 return (2);
582
583         /* Disable interrupts which might cause a timeout here */
584         flag = disable_interrupts();
585
586         for (i=0; i<4/sizeof(CONFIG_SYS_FLASH_WORD_SIZE); i++) {
587                 addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00AA00AA;
588                 addr2[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00550055;
589                 addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE)0x00A000A0;
590
591                 dest2[i] = data2[i];
592
593                 /* re-enable interrupts if necessary */
594                 if (flag)
595                         enable_interrupts();
596
597                 /* data polling for D7 */
598                 start = get_timer (0);
599                 while ((dest2[i] & (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080) !=
600                        (data2[i] & (CONFIG_SYS_FLASH_WORD_SIZE)0x00800080)) {
601                         if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT)
602                                 return (1);
603                 }
604         }
605
606         return (0);
607 }