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