Fix style issues primarily in 85xx and 83xx boards.
[platform/kernel/u-boot.git] / board / alaska / flash.c
1 /*
2  * (C) Copyright 2001
3  * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
4  *
5  * (C) Copyright 2001-2004
6  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 #include <common.h>
28 #include <linux/byteorder/swab.h>
29
30
31 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];   /* info for FLASH chips    */
32
33 /* Board support for 1 or 2 flash devices */
34 #define FLASH_PORT_WIDTH8
35
36 typedef unsigned char FLASH_PORT_WIDTH;
37 typedef volatile unsigned char FLASH_PORT_WIDTHV;
38
39 #define SWAP(x)         (x)
40
41 /* Intel-compatible flash ID */
42 #define INTEL_COMPAT    0x89
43 #define INTEL_ALT       0xB0
44
45 /* Intel-compatible flash commands */
46 #define INTEL_PROGRAM   0x10
47 #define INTEL_ERASE     0x20
48 #define INTEL_CLEAR     0x50
49 #define INTEL_LOCKBIT   0x60
50 #define INTEL_PROTECT   0x01
51 #define INTEL_STATUS    0x70
52 #define INTEL_READID    0x90
53 #define INTEL_CONFIRM   0xD0
54 #define INTEL_RESET     0xFF
55
56 /* Intel-compatible flash status bits */
57 #define INTEL_FINISHED  0x80
58 #define INTEL_OK        0x80
59
60 #define FPW             FLASH_PORT_WIDTH
61 #define FPWV            FLASH_PORT_WIDTHV
62
63 #define FLASH_CYCLE1    0x0555
64 #define FLASH_CYCLE2    0x02aa
65
66 #define WR_BLOCK        0x20
67
68 /*-----------------------------------------------------------------------
69  * Functions
70  */
71 static ulong flash_get_size (FPW * addr, flash_info_t * info);
72 static int write_data (flash_info_t * info, ulong dest, FPW data);
73 static int write_data_block (flash_info_t * info, ulong src, ulong dest);
74 static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data);
75 static void flash_get_offsets (ulong base, flash_info_t * info);
76 void inline spin_wheel (void);
77
78 /*-----------------------------------------------------------------------
79  */
80
81 unsigned long flash_init (void)
82 {
83         int i;
84         ulong size = 0;
85         ulong fsize = 0;
86
87         for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
88                 memset (&flash_info[i], 0, sizeof (flash_info_t));
89
90                 switch (i) {
91                 case 0:
92                         flash_get_size ((FPW *) CFG_FLASH1_BASE,
93                                         &flash_info[i]);
94                         flash_get_offsets (CFG_FLASH1_BASE, &flash_info[i]);
95                         break;
96                 case 1:
97                         flash_get_size ((FPW *) CFG_FLASH1_BASE,
98                                         &flash_info[i]);
99                         fsize = CFG_FLASH1_BASE + flash_info[i - 1].size;
100                         flash_get_offsets (fsize, &flash_info[i]);
101                         break;
102                 case 2:
103                         flash_get_size ((FPW *) CFG_FLASH0_BASE,
104                                         &flash_info[i]);
105                         flash_get_offsets (CFG_FLASH0_BASE, &flash_info[i]);
106                         break;
107                 case 3:
108                         flash_get_size ((FPW *) CFG_FLASH0_BASE,
109                                         &flash_info[i]);
110                         fsize = CFG_FLASH0_BASE + flash_info[i - 1].size;
111                         flash_get_offsets (fsize, &flash_info[i]);
112                         break;
113                 default:
114                         panic ("configured to many flash banks!\n");
115                         break;
116                 }
117                 size += flash_info[i].size;
118         }
119
120         /* Protect monitor and environment sectors
121          */
122 #if defined (CFG_AMD_BOOT)
123         flash_protect (FLAG_PROTECT_SET,
124                        CFG_MONITOR_BASE,
125                        CFG_MONITOR_BASE + monitor_flash_len - 1,
126                        &flash_info[2]);
127         flash_protect (FLAG_PROTECT_SET,
128                        CFG_INTEL_BASE,
129                        CFG_INTEL_BASE + monitor_flash_len - 1,
130                        &flash_info[1]);
131 #else
132         flash_protect (FLAG_PROTECT_SET,
133                        CFG_MONITOR_BASE,
134                        CFG_MONITOR_BASE + monitor_flash_len - 1,
135                        &flash_info[3]);
136         flash_protect (FLAG_PROTECT_SET,
137                        CFG_AMD_BASE,
138                        CFG_AMD_BASE + monitor_flash_len - 1, &flash_info[0]);
139 #endif
140
141         flash_protect (FLAG_PROTECT_SET,
142                        CFG_ENV1_ADDR,
143                        CFG_ENV1_ADDR + CFG_ENV1_SIZE - 1, &flash_info[1]);
144         flash_protect (FLAG_PROTECT_SET,
145                        CFG_ENV_ADDR,
146                        CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[3]);
147
148         return size;
149 }
150
151 /*-----------------------------------------------------------------------
152  */
153 static void flash_get_offsets (ulong base, flash_info_t * info)
154 {
155         int i;
156
157         if (info->flash_id == FLASH_UNKNOWN)
158                 return;
159
160         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) {
161                 for (i = 0; i < info->sector_count; i++) {
162                         info->start[i] = base + (i * PHYS_AMD_SECT_SIZE);
163                         info->protect[i] = 0;
164                 }
165         }
166
167         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
168                 for (i = 0; i < info->sector_count; i++) {
169                         info->start[i] = base + (i * PHYS_INTEL_SECT_SIZE);
170                         info->protect[i] = 0;
171                 }
172         }
173 }
174
175 /*-----------------------------------------------------------------------
176  */
177 void flash_print_info (flash_info_t * info)
178 {
179         int i;
180
181         if (info->flash_id == FLASH_UNKNOWN) {
182                 printf ("missing or unknown FLASH type\n");
183                 return;
184         }
185
186         switch (info->flash_id & FLASH_VENDMASK) {
187         case FLASH_MAN_INTEL:
188                 printf ("INTEL ");
189                 break;
190         case FLASH_MAN_AMD:
191                 printf ("AMD ");
192                 break;
193         default:
194                 printf ("Unknown Vendor ");
195                 break;
196         }
197
198         switch (info->flash_id & FLASH_TYPEMASK) {
199         case FLASH_28F128J3A:
200                 printf ("28F128J3A\n");
201                 break;
202
203         case FLASH_AM040:
204                 printf ("AMD29F040B\n");
205                 break;
206
207         default:
208                 printf ("Unknown Chip Type\n");
209                 break;
210         }
211
212         printf ("  Size: %ld MB in %d Sectors\n",
213                 info->size >> 20, info->sector_count);
214
215         printf ("  Sector Start Addresses:");
216         for (i = 0; i < info->sector_count; ++i) {
217                 if ((i % 5) == 0)
218                         printf ("\n   ");
219                 printf (" %08lX%s",
220                         info->start[i], info->protect[i] ? " (RO)" : "     ");
221         }
222         printf ("\n");
223         return;
224 }
225
226 /*
227  * The following code cannot be run from FLASH!
228  */
229 static ulong flash_get_size (FPW * addr, flash_info_t * info)
230 {
231         FPWV value;
232         static int amd = 0;
233
234         /* Write auto select command: read Manufacturer ID */
235         /* Write auto select command sequence and test FLASH answer */
236         addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* for AMD, Intel ignores this */
237         __asm__ ("sync");
238         addr[FLASH_CYCLE2] = (FPW) 0x00550055;  /* for AMD, Intel ignores this */
239         __asm__ ("sync");
240         addr[FLASH_CYCLE1] = (FPW) 0x00900090;  /* selects Intel or AMD */
241         __asm__ ("sync");
242
243         udelay (100);
244
245         switch (addr[0] & 0xff) {
246
247         case (uchar) AMD_MANUFACT:
248                 info->flash_id = FLASH_MAN_AMD;
249                 value = addr[1];
250                 break;
251
252         case (uchar) INTEL_MANUFACT:
253                 info->flash_id = FLASH_MAN_INTEL;
254                 value = addr[2];
255                 break;
256
257         default:
258                 printf ("unknown\n");
259                 info->flash_id = FLASH_UNKNOWN;
260                 info->sector_count = 0;
261                 info->size = 0;
262                 addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
263                 return (0);     /* no or unknown flash  */
264         }
265
266         switch (value) {
267
268         case (FPW) INTEL_ID_28F128J3A:
269                 info->flash_id += FLASH_28F128J3A;
270                 info->sector_count = 64;
271                 info->size = 0x00800000;        /* => 16 MB     */
272                 break;
273
274         case (FPW) AMD_ID_LV040B:
275                 info->flash_id += FLASH_AM040;
276                 if (amd == 0) {
277                         info->sector_count = 7;
278                         info->size = 0x00070000;        /* => 448 KB     */
279                         amd = 1;
280                 } else {
281                         /* for Environment settings */
282                         info->sector_count = 1;
283                         info->size = PHYS_AMD_SECT_SIZE;        /* => 64 KB     */
284                         amd = 0;
285                 }
286                 break;
287
288         default:
289                 info->flash_id = FLASH_UNKNOWN;
290                 break;
291         }
292
293         if (info->sector_count > CFG_MAX_FLASH_SECT) {
294                 printf ("** ERROR: sector count %d > max (%d) **\n",
295                         info->sector_count, CFG_MAX_FLASH_SECT);
296                 info->sector_count = CFG_MAX_FLASH_SECT;
297         }
298
299         if (value == (FPW) INTEL_ID_28F128J3A)
300                 addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
301         else
302                 addr[0] = (FPW) 0x00F000F0;     /* restore read mode */
303
304         return (info->size);
305 }
306
307
308 /*-----------------------------------------------------------------------
309  */
310 int flash_erase (flash_info_t * info, int s_first, int s_last)
311 {
312         int flag, prot, sect;
313         ulong type, start, last;
314         int rcode = 0, intel = 0;
315
316         if ((s_first < 0) || (s_first > s_last)) {
317                 if (info->flash_id == FLASH_UNKNOWN)
318                         printf ("- missing\n");
319                 else
320                         printf ("- no sectors to erase\n");
321                 return 1;
322         }
323
324         type = (info->flash_id & FLASH_VENDMASK);
325         if ((type != FLASH_MAN_INTEL)) {
326                 type = (info->flash_id & FLASH_VENDMASK);
327                 if ((type != FLASH_MAN_AMD)) {
328                         printf ("Can't erase unknown flash type %08lx - aborted\n",
329                                 info->flash_id);
330                         return 1;
331                 }
332         }
333
334         if (type == FLASH_MAN_INTEL)
335                 intel = 1;
336
337         prot = 0;
338         for (sect = s_first; sect <= s_last; ++sect) {
339                 if (info->protect[sect]) {
340                         prot++;
341                 }
342         }
343
344         if (prot) {
345                 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
346         } else {
347                 printf ("\n");
348         }
349
350         start = get_timer (0);
351         last = start;
352
353         /* Disable interrupts which might cause a timeout here */
354         flag = disable_interrupts ();
355
356         /* Start erase on unprotected sectors */
357         for (sect = s_first; sect <= s_last; sect++) {
358                 if (info->protect[sect] == 0) { /* not protected */
359                         FPWV *addr = (FPWV *) (info->start[sect]);
360                         FPW status;
361
362                         printf ("Erasing sector %2d ... ", sect);
363
364                         /* arm simple, non interrupt dependent timer */
365                         start = get_timer (0);
366
367                         if (intel) {
368                                 *addr = (FPW) 0x00500050;       /* clear status register */
369                                 *addr = (FPW) 0x00200020;       /* erase setup */
370                                 *addr = (FPW) 0x00D000D0;       /* erase confirm */
371                         } else {
372                                 FPWV *base;     /* first address in bank */
373
374                                 base = (FPWV *) (CFG_AMD_BASE);
375                                 base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
376                                 base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
377                                 base[FLASH_CYCLE1] = (FPW) 0x00800080;  /* erase mode */
378                                 base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
379                                 base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
380                                 *addr = (FPW) 0x00300030;       /* erase sector */
381                         }
382
383                         while (((status =
384                                  *addr) & (FPW) 0x00800080) !=
385                                (FPW) 0x00800080) {
386                                 if (get_timer (start) > CFG_FLASH_ERASE_TOUT) {
387                                         printf ("Timeout\n");
388                                         if (intel) {
389                                                 *addr = (FPW) 0x00B000B0;       /* suspend erase     */
390                                                 *addr = (FPW) 0x00FF00FF;       /* reset to read mode */
391                                         } else
392                                                 *addr = (FPW) 0x00F000F0;       /* reset to read mode */
393
394                                         rcode = 1;
395                                         break;
396                                 }
397                         }
398
399                         if (intel) {
400                                 *addr = (FPW) 0x00500050;       /* clear status register cmd.   */
401                                 *addr = (FPW) 0x00FF00FF;       /* resest to read mode          */
402                         } else
403                                 *addr = (FPW) 0x00F000F0;       /* reset to read mode */
404
405                         printf (" done\n");
406                 }
407         }
408         return rcode;
409 }
410
411 /*-----------------------------------------------------------------------
412  * Copy memory to flash, returns:
413  * 0 - OK
414  * 1 - write timeout
415  * 2 - Flash not erased
416  * 4 - Flash not identified
417  */
418
419 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
420 {
421         if (info->flash_id == FLASH_UNKNOWN) {
422                 return 4;
423         }
424
425         switch (info->flash_id & FLASH_VENDMASK) {
426         case FLASH_MAN_AMD:
427             {
428                 FPW data = 0;   /* 16 or 32 bit word, matches flash bus width */
429                 int bytes;      /* number of bytes to program in current word */
430                 int left;       /* number of bytes left to program */
431                 int i, res;
432
433                 for (left = cnt, res = 0;
434                      left > 0 && res == 0;
435                      addr += sizeof (data), left -=
436                      sizeof (data) - bytes) {
437
438                         bytes = addr & (sizeof (data) - 1);
439                         addr &= ~(sizeof (data) - 1);
440
441                         /* combine source and destination data so can program
442                          * an entire word of 16 or 32 bits
443                          */
444                         for (i = 0; i < sizeof (data); i++) {
445                                 data <<= 8;
446                                 if (i < bytes || i - bytes >= left)
447                                         data += *((uchar *) addr + i);
448                                 else
449                                         data += *src++;
450                         }
451
452                         res = write_word_amd (info, (FPWV *) addr,
453                                               data);
454                 }
455                 return res;
456             }           /* case FLASH_MAN_AMD */
457
458         case FLASH_MAN_INTEL:
459             {
460                 ulong cp, wp;
461                 FPW data;
462                 int count, i, l, rc, port_width;
463
464                 /* get lower word aligned address */
465                 wp = addr;
466                 port_width = 1;
467
468                 /*
469                  * handle unaligned start bytes
470                  */
471                 if ((l = addr - wp) != 0) {
472                         data = 0;
473                         for (i = 0, cp = wp; i < l; ++i, ++cp) {
474                                 data = (data << 8) | (*(uchar *) cp);
475                         }
476
477                         for (; i < port_width && cnt > 0; ++i) {
478                                 data = (data << 8) | *src++;
479                                 --cnt;
480                                 ++cp;
481                         }
482
483                         for (; cnt == 0 && i < port_width; ++i, ++cp)
484                                 data = (data << 8) | (*(uchar *) cp);
485
486                         if ((rc =
487                              write_data (info, wp, SWAP (data))) != 0)
488                                 return (rc);
489                         wp += port_width;
490                 }
491
492                 if (cnt > WR_BLOCK) {
493                         /*
494                          * handle word aligned part
495                          */
496                         count = 0;
497                         while (cnt >= WR_BLOCK) {
498
499                                 if ((rc =
500                                      write_data_block (info,
501                                                        (ulong) src,
502                                                        wp)) != 0)
503                                         return (rc);
504
505                                 wp += WR_BLOCK;
506                                 src += WR_BLOCK;
507                                 cnt -= WR_BLOCK;
508
509                                 if (count++ > 0x800) {
510                                         spin_wheel ();
511                                         count = 0;
512                                 }
513                         }
514                 }
515
516                 if (cnt < WR_BLOCK) {
517                         /*
518                          * handle word aligned part
519                          */
520                         count = 0;
521                         while (cnt >= port_width) {
522                                 data = 0;
523                                 for (i = 0; i < port_width; ++i)
524                                         data = (data << 8) | *src++;
525
526                                 if ((rc =
527                                      write_data (info, wp,
528                                                  SWAP (data))) != 0)
529                                         return (rc);
530
531                                 wp += port_width;
532                                 cnt -= port_width;
533                                 if (count++ > 0x800) {
534                                         spin_wheel ();
535                                         count = 0;
536                                 }
537                         }
538                 }
539
540                 if (cnt == 0)
541                         return (0);
542
543                 /*
544                  * handle unaligned tail bytes
545                  */
546                 data = 0;
547                 for (i = 0, cp = wp; i < port_width && cnt > 0;
548                      ++i, ++cp) {
549                         data = (data << 8) | *src++;
550                         --cnt;
551                 }
552
553                 for (; i < port_width; ++i, ++cp)
554                         data = (data << 8) | (*(uchar *) cp);
555
556                 return (write_data (info, wp, SWAP (data)));
557             }           /* case FLASH_MAN_INTEL */
558
559         }                       /* switch */
560         return (0);
561 }
562
563 /*-----------------------------------------------------------------------
564  * Write a word or halfword to Flash, returns:
565  * 0 - OK
566  * 1 - write timeout
567  * 2 - Flash not erased
568  */
569 static int write_data (flash_info_t * info, ulong dest, FPW data)
570 {
571         FPWV *addr = (FPWV *) dest;
572         ulong start;
573         int flag;
574
575         /* Check if Flash is (sufficiently) erased */
576         if ((*addr & data) != data) {
577                 printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr);
578                 return (2);
579         }
580         /* Disable interrupts which might cause a timeout here */
581         flag = disable_interrupts ();
582
583         *addr = (FPW) 0x00400040;       /* write setup */
584         *addr = data;
585
586         /* arm simple, non interrupt dependent timer */
587         start = get_timer (0);
588
589         /* wait while polling the status register */
590         while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) {
591                 if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
592                         *addr = (FPW) 0x00FF00FF;       /* restore read mode */
593                         return (1);
594                 }
595         }
596
597         *addr = (FPW) 0x00FF00FF;       /* restore read mode */
598
599         return (0);
600 }
601
602 /*-----------------------------------------------------------------------
603  * Write a word or halfword to Flash, returns:
604  * 0 - OK
605  * 1 - write timeout
606  * 2 - Flash not erased
607  */
608 static int write_data_block (flash_info_t * info, ulong src, ulong dest)
609 {
610         FPWV *srcaddr = (FPWV *) src;
611         FPWV *dstaddr = (FPWV *) dest;
612         ulong start;
613         int flag, i;
614
615         /* Check if Flash is (sufficiently) erased */
616         for (i = 0; i < WR_BLOCK; i++)
617                 if ((*dstaddr++ & 0xff) != 0xff) {
618                         printf ("not erased at %08lx (%lx)\n",
619                                 (ulong) dstaddr, *dstaddr);
620                         return (2);
621                 }
622
623         dstaddr = (FPWV *) dest;
624
625         /* Disable interrupts which might cause a timeout here */
626         flag = disable_interrupts ();
627
628         *dstaddr = (FPW) 0x00e800e8;    /* write block setup */
629
630         /* arm simple, non interrupt dependent timer */
631         start = get_timer (0);
632
633         /* wait while polling the status register */
634         while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) {
635                 if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
636                         *dstaddr = (FPW) 0x00FF00FF;    /* restore read mode */
637                         return (1);
638                 }
639         }
640
641         *dstaddr = (FPW) 0x001f001f;    /* write 32 to buffer */
642         for (i = 0; i < WR_BLOCK; i++)
643                 *dstaddr++ = *srcaddr++;
644
645         dstaddr -= 1;
646         *dstaddr = (FPW) 0x00d000d0;    /* write 32 to buffer */
647
648         /* arm simple, non interrupt dependent timer */
649         start = get_timer (0);
650
651         /* wait while polling the status register */
652         while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) {
653                 if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
654                         *dstaddr = (FPW) 0x00FF00FF;    /* restore read mode */
655                         return (1);
656                 }
657         }
658
659         *dstaddr = (FPW) 0x00FF00FF;    /* restore read mode */
660
661         return (0);
662 }
663
664 /*-----------------------------------------------------------------------
665  * Write a word to Flash for AMD FLASH
666  * A word is 16 or 32 bits, whichever the bus width of the flash bank
667  * (not an individual chip) is.
668  *
669  * returns:
670  * 0 - OK
671  * 1 - write timeout
672  * 2 - Flash not erased
673  */
674 static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data)
675 {
676         ulong start;
677         int flag;
678         int res = 0;            /* result, assume success */
679         FPWV *base;             /* first address in flash bank */
680
681         /* Check if Flash is (sufficiently) erased */
682         if ((*dest & data) != data) {
683                 return (2);
684         }
685
686         base = (FPWV *) (CFG_AMD_BASE);
687
688         /* Disable interrupts which might cause a timeout here */
689         flag = disable_interrupts ();
690
691         base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
692         base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
693         base[FLASH_CYCLE1] = (FPW) 0x00A000A0;  /* selects program mode */
694
695         *dest = data;           /* start programming the data */
696
697         /* re-enable interrupts if necessary */
698         if (flag)
699                 enable_interrupts ();
700
701         start = get_timer (0);
702
703         /* data polling for D7 */
704         while (res == 0
705                && (*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 void inline spin_wheel (void)
716 {
717         static int p = 0;
718         static char w[] = "\\/-";
719
720         printf ("\010%c", w[p]);
721         (++p == 3) ? (p = 0) : 0;
722 }
723
724 /*-----------------------------------------------------------------------
725  * Set/Clear sector's lock bit, returns:
726  * 0 - OK
727  * 1 - Error (timeout, voltage problems, etc.)
728  */
729 int flash_real_protect (flash_info_t * info, long sector, int prot)
730 {
731         ulong start;
732         int i;
733         int rc = 0;
734         FPWV *addr = (FPWV *) (info->start[sector]);
735         int flag = disable_interrupts ();
736
737         /*
738          * 29F040B AMD flash does not support software protection/unprotection,
739          * the only way to protect the AMD flash is marked it as prot bit.
740          * This flash only support hardware protection, by supply or not supply
741          * 12vpp to the flash
742          */
743         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) {
744                 info->protect[sector] = prot;
745
746                 return 0;
747         }
748
749         *addr = INTEL_CLEAR;    /* Clear status register    */
750         if (prot) {             /* Set sector lock bit      */
751                 *addr = INTEL_LOCKBIT;  /* Sector lock bit          */
752                 *addr = INTEL_PROTECT;  /* set                      */
753         } else {                /* Clear sector lock bit    */
754                 *addr = INTEL_LOCKBIT;  /* All sectors lock bits    */
755                 *addr = INTEL_CONFIRM;  /* clear                    */
756         }
757
758         start = get_timer (0);
759
760         while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) {
761                 if (get_timer (start) > CFG_FLASH_UNLOCK_TOUT) {
762                         printf ("Flash lock bit operation timed out\n");
763                         rc = 1;
764                         break;
765                 }
766         }
767
768         if (*addr != INTEL_OK) {
769                 printf ("Flash lock bit operation failed at %08X, CSR=%08X\n",
770                         (uint) addr, (uint) * addr);
771                 rc = 1;
772         }
773
774         if (!rc)
775                 info->protect[sector] = prot;
776
777         /*
778          * Clear lock bit command clears all sectors lock bits, so
779          * we have to restore lock bits of protected sectors.
780          */
781         if (!prot) {
782                 for (i = 0; i < info->sector_count; i++) {
783                         if (info->protect[i]) {
784                                 start = get_timer (0);
785                                 addr = (FPWV *) (info->start[i]);
786                                 *addr = INTEL_LOCKBIT;  /* Sector lock bit  */
787                                 *addr = INTEL_PROTECT;  /* set              */
788                                 while ((*addr & INTEL_FINISHED) !=
789                                        INTEL_FINISHED) {
790                                         if (get_timer (start) >
791                                             CFG_FLASH_UNLOCK_TOUT) {
792                                                 printf ("Flash lock bit operation timed out\n");
793                                                 rc = 1;
794                                                 break;
795                                         }
796                                 }
797                         }
798                 }
799         }
800
801         if (flag)
802                 enable_interrupts ();
803
804         *addr = INTEL_RESET;    /* Reset to read array mode */
805
806         return rc;
807 }