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