]> git.sur5r.net Git - u-boot/blob - board/logodl/flash.c
ppc4xx: Update 44x_spd_ddr2 code (440SP/440SPe)
[u-boot] / board / logodl / flash.c
1 /*
2  * (C) 2000 Wolfgang Denk, DENX Software Engineering, wd@denx.de.
3  * (C) 2003 August Hoeraendl, Logotronic GmbH
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #undef CONFIG_FLASH_16BIT
25
26 #include <common.h>
27
28 #define FLASH_BANK_SIZE 0x1000000
29 #define MAIN_SECT_SIZE  0x20000         /* 2x64k = 128k per sector */
30
31 flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips   */
32
33 /* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
34  *        has nothing to do with the flash chip being 8-bit or 16-bit.
35  */
36 #ifdef CONFIG_FLASH_16BIT
37 typedef unsigned short FLASH_PORT_WIDTH;
38 typedef volatile unsigned short FLASH_PORT_WIDTHV;
39
40 #define FLASH_ID_MASK   0xFFFF
41 #else
42 typedef unsigned long FLASH_PORT_WIDTH;
43 typedef volatile unsigned long FLASH_PORT_WIDTHV;
44
45 #define FLASH_ID_MASK   0xFFFFFFFF
46 #endif
47
48 #define FPW     FLASH_PORT_WIDTH
49 #define FPWV    FLASH_PORT_WIDTHV
50
51 #define ORMASK(size) ((-size) & OR_AM_MSK)
52
53 /*-----------------------------------------------------------------------
54  * Functions
55  */
56 static ulong flash_get_size(FPWV *addr, flash_info_t *info);
57 static void flash_reset(flash_info_t *info);
58 static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
59 static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
60 #define write_word(in, de, da)   write_word_amd(in, de, da)
61 static void flash_get_offsets(ulong base, flash_info_t *info);
62 #ifdef CFG_FLASH_PROTECTION
63 static void flash_sync_real_protect(flash_info_t *info);
64 #endif
65
66 /*-----------------------------------------------------------------------
67  * flash_init()
68  *
69  * sets up flash_info and returns size of FLASH (bytes)
70  */
71 ulong flash_init(void)
72 {
73     int i, j;
74     ulong size = 0;
75
76     for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
77     {
78         ulong flashbase = 0;
79         flash_info[i].flash_id =
80           (FLASH_MAN_AMD & FLASH_VENDMASK) |
81           (FLASH_AM640U & FLASH_TYPEMASK);
82         flash_info[i].size = FLASH_BANK_SIZE;
83         flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
84         memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
85         switch (i)
86         {
87            case 0:
88                 flashbase = PHYS_FLASH_1;
89                 break;
90            case 1:
91                 flashbase = PHYS_FLASH_2;
92                 break;
93            default:
94                 panic("configured too many flash banks!\n");
95                 break;
96         }
97         for (j = 0; j < flash_info[i].sector_count; j++)
98         {
99             flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE;
100         }
101         size += flash_info[i].size;
102     }
103
104     /* Protect monitor and environment sectors
105      */
106     flash_protect(FLAG_PROTECT_SET,
107                   CFG_FLASH_BASE,
108                   CFG_FLASH_BASE + _bss_start - _armboot_start,
109                   &flash_info[0]);
110
111     flash_protect(FLAG_PROTECT_SET,
112                   CFG_ENV_ADDR,
113                   CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
114                   &flash_info[0]);
115
116     return size;
117 }
118
119 /*-----------------------------------------------------------------------
120  */
121 static void flash_reset(flash_info_t *info)
122 {
123         FPWV *base = (FPWV *)(info->start[0]);
124
125         /* Put FLASH back in read mode */
126         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
127                 *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
128         else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
129                 *base = (FPW)0x00F000F0;        /* AMD Read Mode */
130 }
131
132 /*-----------------------------------------------------------------------
133  */
134 static void flash_get_offsets (ulong base, flash_info_t *info)
135 {
136         int i;
137
138         /* set up sector start address table */
139         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
140             && (info->flash_id & FLASH_BTYPE)) {
141                 int bootsect_size;      /* number of bytes/boot sector  */
142                 int sect_size;          /* number of bytes/regular sector */
143
144                 bootsect_size = 0x00002000 * (sizeof(FPW)/2);
145                 sect_size =     0x00010000 * (sizeof(FPW)/2);
146
147                 /* set sector offsets for bottom boot block type        */
148                 for (i = 0; i < 8; ++i) {
149                         info->start[i] = base + (i * bootsect_size);
150                 }
151                 for (i = 8; i < info->sector_count; i++) {
152                         info->start[i] = base + ((i - 7) * sect_size);
153                 }
154         }
155         else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
156                  && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
157
158                 int sect_size;          /* number of bytes/sector */
159
160                 sect_size = 0x00010000 * (sizeof(FPW)/2);
161
162                 /* set up sector start address table (uniform sector type) */
163                 for( i = 0; i < info->sector_count; i++ )
164                         info->start[i] = base + (i * sect_size);
165         }
166 }
167
168 /*-----------------------------------------------------------------------
169  */
170
171 void flash_print_info (flash_info_t *info)
172 {
173         int i;
174         uchar *boottype;
175         uchar *bootletter;
176         uchar *fmt;
177         uchar botbootletter[] = "B";
178         uchar topbootletter[] = "T";
179         uchar botboottype[] = "bottom boot sector";
180         uchar topboottype[] = "top boot sector";
181
182         if (info->flash_id == FLASH_UNKNOWN) {
183                 printf ("missing or unknown FLASH type\n");
184                 return;
185         }
186
187         switch (info->flash_id & FLASH_VENDMASK) {
188         case FLASH_MAN_AMD:     printf ("AMD ");                break;
189         case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
190         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
191         case FLASH_MAN_SST:     printf ("SST ");                break;
192         case FLASH_MAN_STM:     printf ("STM ");                break;
193         case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
194         default:                printf ("Unknown Vendor ");     break;
195         }
196
197         /* check for top or bottom boot, if it applies */
198         if (info->flash_id & FLASH_BTYPE) {
199                 boottype = botboottype;
200                 bootletter = botbootletter;
201         }
202         else {
203                 boottype = topboottype;
204                 bootletter = topbootletter;
205         }
206
207         switch (info->flash_id & FLASH_TYPEMASK) {
208         case FLASH_AM640U:
209                 fmt = "29LV641D (64 Mbit, uniform sectors)\n";
210                 break;
211         case FLASH_28F800C3B:
212         case FLASH_28F800C3T:
213                 fmt = "28F800C3%s (8 Mbit, %s)\n";
214                 break;
215         case FLASH_INTEL800B:
216         case FLASH_INTEL800T:
217                 fmt = "28F800B3%s (8 Mbit, %s)\n";
218                 break;
219         case FLASH_28F160C3B:
220         case FLASH_28F160C3T:
221                 fmt = "28F160C3%s (16 Mbit, %s)\n";
222                 break;
223         case FLASH_INTEL160B:
224         case FLASH_INTEL160T:
225                 fmt = "28F160B3%s (16 Mbit, %s)\n";
226                 break;
227         case FLASH_28F320C3B:
228         case FLASH_28F320C3T:
229                 fmt = "28F320C3%s (32 Mbit, %s)\n";
230                 break;
231         case FLASH_INTEL320B:
232         case FLASH_INTEL320T:
233                 fmt = "28F320B3%s (32 Mbit, %s)\n";
234                 break;
235         case FLASH_28F640C3B:
236         case FLASH_28F640C3T:
237                 fmt = "28F640C3%s (64 Mbit, %s)\n";
238                 break;
239         case FLASH_INTEL640B:
240         case FLASH_INTEL640T:
241                 fmt = "28F640B3%s (64 Mbit, %s)\n";
242                 break;
243         default:
244                 fmt = "Unknown Chip Type\n";
245                 break;
246         }
247
248         printf (fmt, bootletter, boottype);
249
250         printf ("  Size: %ld MB in %d Sectors\n",
251                 info->size >> 20,
252                 info->sector_count);
253
254         printf ("  Sector Start Addresses:");
255
256         for (i=0; i<info->sector_count; ++i) {
257                 if ((i % 5) == 0) {
258                         printf ("\n   ");
259                 }
260
261                 printf (" %08lX%s", info->start[i],
262                         info->protect[i] ? " (RO)" : "     ");
263         }
264
265         printf ("\n");
266 }
267
268 /*-----------------------------------------------------------------------
269  */
270
271 /*
272  * The following code cannot be run from FLASH!
273  */
274
275 ulong flash_get_size (FPWV *addr, flash_info_t *info)
276 {
277         /* Write auto select command: read Manufacturer ID */
278
279         /* Write auto select command sequence and test FLASH answer */
280         addr[0x0555] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
281         addr[0x02AA] = (FPW)0x00550055; /* for AMD, Intel ignores this */
282         addr[0x0555] = (FPW)0x00900090; /* selects Intel or AMD */
283
284         /* The manufacturer codes are only 1 byte, so just use 1 byte.
285          * This works for any bus width and any FLASH device width.
286          */
287         switch (addr[0] & 0xff) {
288
289         case (uchar)AMD_MANUFACT:
290                 info->flash_id = FLASH_MAN_AMD;
291                 break;
292
293         case (uchar)INTEL_MANUFACT:
294                 info->flash_id = FLASH_MAN_INTEL;
295                 break;
296
297         default:
298                 info->flash_id = FLASH_UNKNOWN;
299                 info->sector_count = 0;
300                 info->size = 0;
301                 break;
302         }
303
304         /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
305         if (info->flash_id != FLASH_UNKNOWN) switch (addr[1]) {
306
307         case (FPW)AMD_ID_LV640U:        /* 29LV640 and 29LV641 have same ID */
308                 info->flash_id += FLASH_AM640U;
309                 info->sector_count = 128;
310                 info->size = 0x00800000 * (sizeof(FPW)/2);
311                 break;                          /* => 8 or 16 MB        */
312
313         case (FPW)INTEL_ID_28F800C3B:
314                 info->flash_id += FLASH_28F800C3B;
315                 info->sector_count = 23;
316                 info->size = 0x00100000 * (sizeof(FPW)/2);
317                 break;                          /* => 1 or 2 MB         */
318
319         case (FPW)INTEL_ID_28F800B3B:
320                 info->flash_id += FLASH_INTEL800B;
321                 info->sector_count = 23;
322                 info->size = 0x00100000 * (sizeof(FPW)/2);
323                 break;                          /* => 1 or 2 MB         */
324
325         case (FPW)INTEL_ID_28F160C3B:
326                 info->flash_id += FLASH_28F160C3B;
327                 info->sector_count = 39;
328                 info->size = 0x00200000 * (sizeof(FPW)/2);
329                 break;                          /* => 2 or 4 MB         */
330
331         case (FPW)INTEL_ID_28F160B3B:
332                 info->flash_id += FLASH_INTEL160B;
333                 info->sector_count = 39;
334                 info->size = 0x00200000 * (sizeof(FPW)/2);
335                 break;                          /* => 2 or 4 MB         */
336
337         case (FPW)INTEL_ID_28F320C3B:
338                 info->flash_id += FLASH_28F320C3B;
339                 info->sector_count = 71;
340                 info->size = 0x00400000 * (sizeof(FPW)/2);
341                 break;                          /* => 4 or 8 MB         */
342
343         case (FPW)INTEL_ID_28F320B3B:
344                 info->flash_id += FLASH_INTEL320B;
345                 info->sector_count = 71;
346                 info->size = 0x00400000 * (sizeof(FPW)/2);
347                 break;                          /* => 4 or 8 MB         */
348
349         case (FPW)INTEL_ID_28F640C3B:
350                 info->flash_id += FLASH_28F640C3B;
351                 info->sector_count = 135;
352                 info->size = 0x00800000 * (sizeof(FPW)/2);
353                 break;                          /* => 8 or 16 MB        */
354
355         case (FPW)INTEL_ID_28F640B3B:
356                 info->flash_id += FLASH_INTEL640B;
357                 info->sector_count = 135;
358                 info->size = 0x00800000 * (sizeof(FPW)/2);
359                 break;                          /* => 8 or 16 MB        */
360
361         default:
362                 info->flash_id = FLASH_UNKNOWN;
363                 info->sector_count = 0;
364                 info->size = 0;
365                 return (0);                     /* => no or unknown flash */
366         }
367
368         flash_get_offsets((ulong)addr, info);
369
370         /* Put FLASH back in read mode */
371         flash_reset(info);
372
373         return (info->size);
374 }
375
376 #ifdef CFG_FLASH_PROTECTION
377 /*-----------------------------------------------------------------------
378  */
379
380 static void flash_sync_real_protect(flash_info_t *info)
381 {
382     FPWV *addr = (FPWV *)(info->start[0]);
383     FPWV *sect;
384     int i;
385
386     switch (info->flash_id & FLASH_TYPEMASK) {
387     case FLASH_28F800C3B:
388     case FLASH_28F800C3T:
389     case FLASH_28F160C3B:
390     case FLASH_28F160C3T:
391     case FLASH_28F320C3B:
392     case FLASH_28F320C3T:
393     case FLASH_28F640C3B:
394     case FLASH_28F640C3T:
395         /* check for protected sectors */
396         *addr = (FPW)0x00900090;
397         for (i = 0; i < info->sector_count; i++) {
398             /* read sector protection at sector address, (A7 .. A0) = 0x02.
399              * D0 = 1 for each device if protected.
400              * If at least one device is protected the sector is marked
401              * protected, but mixed protected and  unprotected devices
402              * within a sector should never happen.
403              */
404             sect = (FPWV *)(info->start[i]);
405             info->protect[i] = (sect[2] & (FPW)(0x00010001)) ? 1 : 0;
406         }
407
408         /* Put FLASH back in read mode */
409         flash_reset(info);
410         break;
411
412     case FLASH_AM640U:
413     default:
414         /* no hardware protect that we support */
415         break;
416     }
417 }
418 #endif
419
420 /*-----------------------------------------------------------------------
421  */
422
423 int     flash_erase (flash_info_t *info, int s_first, int s_last)
424 {
425         FPWV *addr;
426         int flag, prot, sect;
427         int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
428         ulong start, now, last;
429         int rcode = 0;
430
431         if ((s_first < 0) || (s_first > s_last)) {
432                 if (info->flash_id == FLASH_UNKNOWN) {
433                         printf ("- missing\n");
434                 } else {
435                         printf ("- no sectors to erase\n");
436                 }
437                 return 1;
438         }
439
440         switch (info->flash_id & FLASH_TYPEMASK) {
441         case FLASH_INTEL800B:
442         case FLASH_INTEL160B:
443         case FLASH_INTEL320B:
444         case FLASH_INTEL640B:
445         case FLASH_28F800C3B:
446         case FLASH_28F160C3B:
447         case FLASH_28F320C3B:
448         case FLASH_28F640C3B:
449         case FLASH_AM640U:
450                 break;
451         case FLASH_UNKNOWN:
452         default:
453                 printf ("Can't erase unknown flash type %08lx - aborted\n",
454                         info->flash_id);
455                 return 1;
456         }
457
458         prot = 0;
459         for (sect=s_first; sect<=s_last; ++sect) {
460                 if (info->protect[sect]) {
461                         prot++;
462                 }
463         }
464
465         if (prot) {
466                 printf ("- Warning: %d protected sectors will not be erased!\n",
467                         prot);
468         } else {
469                 printf ("\n");
470         }
471
472         start = get_timer(0);
473         last  = start;
474
475         /* Start erase on unprotected sectors */
476         for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
477
478                 if (info->protect[sect] != 0)   /* protected, skip it */
479                         continue;
480
481                 /* Disable interrupts which might cause a timeout here */
482                 flag = disable_interrupts();
483
484                 addr = (FPWV *)(info->start[sect]);
485                 if (intel) {
486                         *addr = (FPW)0x00500050; /* clear status register */
487                         *addr = (FPW)0x00200020; /* erase setup */
488                         *addr = (FPW)0x00D000D0; /* erase confirm */
489                 }
490                 else {
491                         /* must be AMD style if not Intel */
492                         FPWV *base;             /* first address in bank */
493
494                         base = (FPWV *)(info->start[0]);
495                         base[0x0555] = (FPW)0x00AA00AA; /* unlock */
496                         base[0x02AA] = (FPW)0x00550055; /* unlock */
497                         base[0x0555] = (FPW)0x00800080; /* erase mode */
498                         base[0x0555] = (FPW)0x00AA00AA; /* unlock */
499                         base[0x02AA] = (FPW)0x00550055; /* unlock */
500                         *addr = (FPW)0x00300030;        /* erase sector */
501                 }
502
503                 /* re-enable interrupts if necessary */
504                 if (flag)
505                         enable_interrupts();
506
507                 /* wait at least 50us for AMD, 80us for Intel.
508                  * Let's wait 1 ms.
509                  */
510                 udelay (1000);
511
512                 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
513                         if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
514                                 printf ("Timeout\n");
515
516                                 if (intel) {
517                                         /* suspend erase        */
518                                         *addr = (FPW)0x00B000B0;
519                                 }
520
521                                 flash_reset(info);      /* reset to read mode */
522                                 rcode = 1;              /* failed */
523                                 break;
524                         }
525
526                         /* show that we're waiting */
527                         if ((now - last) > 1000) {      /* every second */
528                                 putc ('.');
529                                 last = now;
530                         }
531                 }
532
533                 flash_reset(info);      /* reset to read mode   */
534         }
535
536         printf (" done\n");
537         return rcode;
538 }
539
540 /*-----------------------------------------------------------------------
541  * Copy memory to flash, returns:
542  * 0 - OK
543  * 1 - write timeout
544  * 2 - Flash not erased
545  */
546 int bad_write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
547 {
548     FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
549     int bytes;    /* number of bytes to program in current word         */
550     int left;     /* number of bytes left to program                    */
551     int i, res;
552
553     for (left = cnt, res = 0;
554          left > 0 && res == 0;
555          addr += sizeof(data), left -= sizeof(data) - bytes) {
556
557         bytes = addr & (sizeof(data) - 1);
558         addr &= ~(sizeof(data) - 1);
559
560         /* combine source and destination data so can program
561          * an entire word of 16 or 32 bits
562          */
563         for (i = 0; i < sizeof(data); i++) {
564             data <<= 8;
565             if (i < bytes || i - bytes >= left )
566                 data += *((uchar *)addr + i);
567             else
568                 data += *src++;
569         }
570
571         /* write one word to the flash */
572         switch (info->flash_id & FLASH_VENDMASK) {
573         case FLASH_MAN_AMD:
574                 res = write_word_amd(info, (FPWV *)addr, data);
575                 break;
576         case FLASH_MAN_INTEL:
577                 res = write_word_intel(info, (FPWV *)addr, data);
578                 break;
579         default:
580                 /* unknown flash type, error! */
581                 printf ("missing or unknown FLASH type\n");
582                 res = 1;        /* not really a timeout, but gives error */
583                 break;
584         }
585     }
586
587     return (res);
588 }
589
590 /**
591  * write_buf: - Copy memory to flash.
592  *
593  * @param info:
594  * @param src:  source of copy transaction
595  * @param addr: where to copy to
596  * @param cnt:  number of bytes to copy
597  *
598  * @return      error code
599  */
600
601 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
602 {
603         ulong cp, wp;
604         FPW data;
605         int l;
606         int i, rc;
607
608         wp = (addr & ~1);       /* get lower word aligned address */
609
610         /*
611          * handle unaligned start bytes
612          */
613         if ((l = addr - wp) != 0) {
614                 data = 0;
615                 for (i=0, cp=wp; i<l; ++i, ++cp) {
616                         data = (data >> 8) | (*(uchar *)cp << 8);
617                 }
618                 for (; i<2 && cnt>0; ++i) {
619                         data = (data >> 8) | (*src++ << 8);
620                         --cnt;
621                         ++cp;
622                 }
623                 for (; cnt==0 && i<2; ++i, ++cp) {
624                         data = (data >> 8) | (*(uchar *)cp << 8);
625                 }
626
627                 if ((rc = write_word(info, wp, data)) != 0) {
628                         return (rc);
629                 }
630                 wp += 2;
631         }
632
633         /*
634          * handle word aligned part
635          */
636         while (cnt >= 2) {
637                 /* data = *((vushort*)src); */
638                 data = *((FPW*)src);
639                 if ((rc = write_word(info, wp, data)) != 0) {
640                         return (rc);
641                 }
642                 src += sizeof(FPW);
643                 wp  += sizeof(FPW);
644                 cnt -= sizeof(FPW);
645         }
646
647         if (cnt == 0) return ERR_OK;
648
649         /*
650          * handle unaligned tail bytes
651          */
652         data = 0;
653         for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
654                 data = (data >> 8) | (*src++ << 8);
655                 --cnt;
656         }
657         for (; i<2; ++i, ++cp) {
658                 data = (data >> 8) | (*(uchar *)cp << 8);
659         }
660
661         return write_word(info, wp, data);
662 }
663
664
665 /*-----------------------------------------------------------------------
666  * Write a word to Flash for AMD FLASH
667  * A word is 16 or 32 bits, whichever the bus width of the flash bank
668  * (not an individual chip) is.
669  *
670  * returns:
671  * 0 - OK
672  * 1 - write timeout
673  * 2 - Flash not erased
674  */
675 static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
676 {
677     ulong start;
678     int flag;
679     int res = 0;        /* result, assume success       */
680     FPWV *base;         /* first address in flash bank  */
681
682     /* Check if Flash is (sufficiently) erased */
683     if ((*dest & data) != data) {
684         return (2);
685     }
686
687
688     base = (FPWV *)(info->start[0]);
689     /* Disable interrupts which might cause a timeout here */
690     flag = disable_interrupts();
691
692     base[0x0555] = (FPW)0x00AA00AA;     /* unlock */
693     base[0x02AA] = (FPW)0x00550055;     /* unlock */
694     base[0x0555] = (FPW)0x00A000A0;     /* selects program mode */
695
696     *dest = data;               /* start programming the data   */
697
698     /* re-enable interrupts if necessary */
699     if (flag)
700         enable_interrupts();
701
702     start = get_timer (0);
703
704     /* data polling for D7 */
705     while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
706         if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
707             *dest = (FPW)0x00F000F0;    /* reset bank */
708             res = 1;
709         }
710     }
711
712     return (res);
713 }
714
715 /*-----------------------------------------------------------------------
716  * Write a word to Flash for Intel FLASH
717  * A word is 16 or 32 bits, whichever the bus width of the flash bank
718  * (not an individual chip) is.
719  *
720  * returns:
721  * 0 - OK
722  * 1 - write timeout
723  * 2 - Flash not erased
724  */
725 static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
726 {
727     ulong start;
728     int flag;
729     int res = 0;        /* result, assume success       */
730
731     /* Check if Flash is (sufficiently) erased */
732     if ((*dest & data) != data) {
733         return (2);
734     }
735
736     /* Disable interrupts which might cause a timeout here */
737     flag = disable_interrupts();
738
739     *dest = (FPW)0x00500050;    /* clear status register        */
740     *dest = (FPW)0x00FF00FF;    /* make sure in read mode       */
741     *dest = (FPW)0x00400040;    /* program setup                */
742
743     *dest = data;               /* start programming the data   */
744
745     /* re-enable interrupts if necessary */
746     if (flag)
747         enable_interrupts();
748
749     start = get_timer (0);
750
751     while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
752         if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
753             *dest = (FPW)0x00B000B0;    /* Suspend program      */
754             res = 1;
755         }
756     }
757
758     if (res == 0 && (*dest & (FPW)0x00100010))
759         res = 1;        /* write failed, time out error is close enough */
760
761     *dest = (FPW)0x00500050;    /* clear status register        */
762     *dest = (FPW)0x00FF00FF;    /* make sure in read mode       */
763
764     return (res);
765 }
766
767 #ifdef CFG_FLASH_PROTECTION
768 /*-----------------------------------------------------------------------
769  */
770 int flash_real_protect (flash_info_t * info, long sector, int prot)
771 {
772         int rcode = 0;          /* assume success */
773         FPWV *addr;             /* address of sector */
774         FPW value;
775
776         addr = (FPWV *) (info->start[sector]);
777
778         switch (info->flash_id & FLASH_TYPEMASK) {
779         case FLASH_28F800C3B:
780         case FLASH_28F800C3T:
781         case FLASH_28F160C3B:
782         case FLASH_28F160C3T:
783         case FLASH_28F320C3B:
784         case FLASH_28F320C3T:
785         case FLASH_28F640C3B:
786         case FLASH_28F640C3T:
787                 flash_reset (info);             /* make sure in read mode */
788                 *addr = (FPW) 0x00600060L;      /* lock command setup */
789                 if (prot)
790                         *addr = (FPW) 0x00010001L;      /* lock sector */
791                 else
792                         *addr = (FPW) 0x00D000D0L;      /* unlock sector */
793                 flash_reset (info);             /* reset to read mode */
794
795                 /* now see if it really is locked/unlocked as requested */
796                 *addr = (FPW) 0x00900090;
797                 /* read sector protection at sector address, (A7 .. A0) = 0x02.
798                  * D0 = 1 for each device if protected.
799                  * If at least one device is protected the sector is marked
800                  * protected, but return failure. Mixed protected and
801                  * unprotected devices within a sector should never happen.
802                  */
803                 value = addr[2] & (FPW) 0x00010001;
804                 if (value == 0)
805                         info->protect[sector] = 0;
806                 else if (value == (FPW) 0x00010001)
807                         info->protect[sector] = 1;
808                 else {
809                         /* error, mixed protected and unprotected */
810                         rcode = 1;
811                         info->protect[sector] = 1;
812                 }
813                 if (info->protect[sector] != prot)
814                         rcode = 1;      /* failed to protect/unprotect as requested */
815
816                 /* reload all protection bits from hardware for now */
817                 flash_sync_real_protect (info);
818                 break;
819
820         case FLASH_AM640U:
821         default:
822                 /* no hardware protect that we support */
823                 info->protect[sector] = prot;
824                 break;
825         }
826
827         return rcode;
828 }
829 #endif