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